package com.philosophicalhacker.philhackernews; import android.database.sqlite.SQLiteDatabase; import android.support.test.espresso.Espresso; import android.support.test.espresso.IdlingResource; import android.support.test.rule.ActivityTestRule; import android.support.test.runner.AndroidJUnit4; import android.test.suitebuilder.annotation.LargeTest; import com.philosophicalhacker.philhackernews.data.sync.DataSynchronizer; import com.philosophicalhacker.philhackernews.ui.storieslist.StoriesActivity; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import java.io.File; import javax.inject.Inject; 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.matches; import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; import static android.support.test.espresso.matcher.ViewMatchers.isRoot; import static android.support.test.espresso.matcher.ViewMatchers.withClassName; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; import static org.hamcrest.CoreMatchers.containsString; @RunWith(AndroidJUnit4.class) @LargeTest public class MainActivityTests { public static final String DUMMY_STORY_POINTS = "999+"; public static final String DUMMY_STORY_TITLE = "Why Hacker News is Awesomer than your News"; public static final String DUMMY_STORY_AUTHOR = "PhilosophicalHacker"; public static final String DUMMY_URL = "http://www.philosophicalhacker.com"; @Rule public ActivityTestRule<StoriesActivity> mActivityTestRule = new ActivityTestRule<>(StoriesActivity.class); @Inject DataSynchronizer mDataSynchronizer; @Inject File mHackerNewsDatabaseFile; private SyncAdapterIdlingResource mSyncAdapterIdlingResource; @Before public void registerIdlingResource() { PhilHackerNewsApplication application = (PhilHackerNewsApplication) mActivityTestRule.getActivity().getApplication(); application.getObjectGraph().inject(this); mSyncAdapterIdlingResource = new SyncAdapterIdlingResource(mDataSynchronizer); Espresso.registerIdlingResources(mSyncAdapterIdlingResource); } @After public void unregisterIdlingResources() { Espresso.unregisterIdlingResources(mSyncAdapterIdlingResource); SQLiteDatabase.deleteDatabase(mHackerNewsDatabaseFile); } //---------------------------------------------------------------------------------- // Tests //---------------------------------------------------------------------------------- @Test public void loadHackerNewsPostsOnStartup() { onView(withClassName(containsString("RecyclerView"))).check(matches(isDisplayed())); verifyDummyDataIsDisplayed(); } @Test public void dataStillDisplaysAfterOrientationChange() { onView(isRoot()).perform(OrientationChangeAction.orientationLandscape()); verifyDummyDataIsDisplayed(); } @Test public void showStoryDetailsWhenStoryIsTapped() { onView(withId(R.id.recyclerView)).perform(actionOnItemAtPosition(0, click())); onView(withText(DUMMY_STORY_TITLE)).check(matches(isDisplayed())); //TODO Test that proper web content is loaded } //---------------------------------------------------------------------------------- // Helpers //---------------------------------------------------------------------------------- private void verifyDummyDataIsDisplayed() { onView(withText(DUMMY_STORY_POINTS)).check(matches(isDisplayed())); onView(withText(DUMMY_STORY_TITLE)).check(matches(isDisplayed())); onView(withText(DUMMY_STORY_AUTHOR)).check(matches(isDisplayed())); } //---------------------------------------------------------------------------------- // Nested Inner Class //---------------------------------------------------------------------------------- private static class SyncAdapterIdlingResource implements IdlingResource { private ResourceCallback mResourceCallback; public SyncAdapterIdlingResource(DataSynchronizer dataSynchronizer) { mDataSynchronizer = dataSynchronizer; } private DataSynchronizer mDataSynchronizer; @Override public String getName() { return "SyncAdapterRequest"; } @Override public boolean isIdleNow() { boolean idle = !mDataSynchronizer.isSyncActiveOrPending(); if(idle) { mResourceCallback.onTransitionToIdle(); } return idle; } @Override public void registerIdleTransitionCallback(ResourceCallback resourceCallback) { mResourceCallback = resourceCallback; } } }