package com.hitherejoe.bourbon.test;
import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.contrib.RecyclerViewActions;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import com.hitherejoe.bourbon.R;
import com.hitherejoe.bourbon.ui.browse.BrowseActivity;
import com.hitherejoe.bourboncorecommon.data.model.Comment;
import com.hitherejoe.bourboncorecommon.data.model.Shot;
import com.hitherejoe.bourboncorecommon.injection.component.TestComponentRule;
import com.hitherejoe.androidtestcommon.helper.StubHelper;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import java.util.Collections;
import java.util.List;
import rx.Single;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static com.hitherejoe.androidtestcommon.util.CustomMatchers.withItemText;
import com.hitherejoe.bourbon.R;
import com.hitherejoe.bourboncorecommon.util.TestDataFactory;
@RunWith(AndroidJUnit4.class)
public class BrowseActivityTest {
public final TestComponentRule component =
new TestComponentRule(InstrumentationRegistry.getTargetContext());
public final ActivityTestRule<BrowseActivity> main =
new ActivityTestRule<>(BrowseActivity.class, false, false);
// TestComponentRule needs to go first to make sure the Dagger ApplicationTestComponent is set
// in the Application before any Activity is launched.
@Rule
public TestRule chain = RuleChain.outerRule(component).around(main);
@Test
public void errorViewDisplaysWhenLoadingContentFails() throws InterruptedException {
StubHelper.stubDataManagerGetShots(component,
Single.<List<Shot>>error(new RuntimeException()));
main.launchActivity(null);
onView(withText(R.string.title_oops))
.check(matches(isDisplayed()));
onView(withText(R.string.text_error_loading_shots))
.check(matches(isDisplayed()));
onView(withText(R.string.text_reload))
.check(matches(isDisplayed()));
}
@Test
public void emptyViewDisplaysWhenLoadingContentFails() throws InterruptedException {
StubHelper.stubDataManagerGetShots(component, Single.just(Collections.<Shot>emptyList()));
main.launchActivity(null);
onView(withText(R.string.title_no_shots))
.check(matches(isDisplayed()));
onView(withText(R.string.text_no_shots))
.check(matches(isDisplayed()));
onView(withText(R.string.text_check_again))
.check(matches(isDisplayed()));
}
@Test
public void clickingReloadAfterError() {
List<Shot> shots = TestDataFactory.makeShots(3);
StubHelper.stubDataManagerGetShots(component,
Single.<List<Shot>>error(new RuntimeException()));
main.launchActivity(null);
StubHelper.stubDataManagerGetShots(component, Single.just(shots));
onView(withId(com.hitherejoe.bourbon.R.id.button_message))
.perform(click());
checkPostsDisplayOnRecyclerView(shots, 0);
}
@Test
public void clickingCheckAgainAfterEmptyContent() {
List<Shot> shots = TestDataFactory.makeShots(3);
StubHelper.stubDataManagerGetShots(component, Single.just(Collections.<Shot>emptyList()));
main.launchActivity(null);
StubHelper.stubDataManagerGetShots(component, Single.just(shots));
onView(withId(com.hitherejoe.bourbon.R.id.button_message))
.perform(click());
checkPostsDisplayOnRecyclerView(shots, 0);
}
@Test
public void shotItemViewsDisplayWhenClickingReload() {
List<Shot> shots = TestDataFactory.makeShots(3);
StubHelper.stubDataManagerGetShots(component,
Single.<List<Shot>>error(new RuntimeException()));
main.launchActivity(null);
StubHelper.stubDataManagerGetShots(component, Single.just(shots));
onView(withId(com.hitherejoe.bourbon.R.id.button_message))
.perform(click());
onView(withId(R.id.button_message))
.check(doesNotExist());
onView(withId(R.id.text_message))
.check(doesNotExist());
onView(withId(R.id.image_message))
.check(doesNotExist());
checkPostsDisplayOnRecyclerView(shots, 0);
}
@Test
public void shotItemViewsDisplayWhenClickingCheckAgain() {
List<Shot> shots = TestDataFactory.makeShots(3);
StubHelper.stubDataManagerGetShots(component, Single.just(Collections.<Shot>emptyList()));
main.launchActivity(null);
StubHelper.stubDataManagerGetShots(component, Single.just(shots));
onView(withId(R.id.button_message))
.perform(click());
onView(withId(R.id.button_message))
.check(doesNotExist());
onView(withId(R.id.text_message))
.check(doesNotExist());
onView(withId(R.id.image_message))
.check(doesNotExist());
checkPostsDisplayOnRecyclerView(shots, 0);
}
@Test
public void clickingShotNavigatesToShotActivity() {
List<Shot> shots = TestDataFactory.makeShots(20);
Shot shot = shots.get(0);
StubHelper.stubDataManagerGetShots(component, Single.just(shots));
StubHelper.stubDataManagerGetComments(component,
Single.just(Collections.<Comment>emptyList()));
main.launchActivity(null);
onView(withText(shot.title))
.perform(click());
onView(withId(com.hitherejoe.bourbon.R.id.pager_shot))
.check(matches(isDisplayed()));
}
@Test
public void shotItemViewsDisplayAndAreBrowseable() {
List<Shot> shots = TestDataFactory.makeShots(10);
StubHelper.stubDataManagerGetShots(component, Single.just(shots));
main.launchActivity(null);
checkPostsDisplayOnRecyclerView(shots, 0);
}
/**
* This method checks that the given list of posts display within the VerticalGridView. At the time
* of writing this, RecyclerViewActions is really buggy with grid based recycler views - so this
* method traverses through the rows of the grid (starting at left-to-right, then right-to-left
* and vice versa). This isn't ideal, but currently proper testing doesn't seem supported.
*
* @param shotsToCheck posts to be checked
*/
private void checkPostsDisplayOnRecyclerView(List<Shot> shotsToCheck, int position) {
int columnCount = 5;
int size = shotsToCheck.size() + position;
int pos = 0;
for (int i = position; i < size; i++) {
// The first item starts as selected, clicking on this would open the Playback Activity
checkItemAtPosition(i, shotsToCheck.get(pos));
// If we get to the end of the current row then we need to go down to the next one
if (((i + 1) % columnCount) == 0) {
int nextRowStart = i + columnCount;
int nextRowEnd = nextRowStart - columnCount + 1;
for (int n = nextRowStart; n >= nextRowEnd; n--) {
checkItemAtPosition(n, shotsToCheck.get(n - position));
}
// Set i to the start of the row beneath the one we've just checked
i = i + columnCount;
}
pos++;
}
}
private void checkItemAtPosition(int position, Shot shot) {
if (position > 0) {
onView(withId(R.id.browse_grid))
.perform(RecyclerViewActions.actionOnItemAtPosition(position, click()));
}
onView(withItemText(shot.title, com.hitherejoe.bourbon.R.id.browse_grid)).check(matches(isDisplayed()));
onView(withItemText(shot.description, com.hitherejoe.bourbon.R.id.browse_grid)).check(matches(isDisplayed()));
}
}