package flow.sample.basic; import android.content.res.Configuration; import android.support.test.InstrumentationRegistry; import android.support.test.espresso.action.ViewActions; import android.support.test.rule.ActivityTestRule; import org.junit.Rule; import org.junit.Test; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE; import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.Espresso.pressBack; import static android.support.test.espresso.action.ViewActions.click; import static android.support.test.espresso.assertion.ViewAssertions.matches; import static android.support.test.espresso.matcher.ViewMatchers.hasDescendant; import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom; import static android.support.test.espresso.matcher.ViewMatchers.withId; import static android.support.test.espresso.matcher.ViewMatchers.withText; /** * Verifies that simple navigation works, along with Flow and view state persistence across * navigation and across configuration changes. */ public class BasicSampleTest { @Rule public ActivityTestRule rule = new ActivityTestRule<>(BasicSampleActivity.class); /** Verifies that the app is in its default state on a cold start. */ @Test public void defaultKeyIsUsed() { onView(withId(R.id.basic_activity_frame)) .check(matches(hasDescendant(isAssignableFrom(WelcomeView.class)))); } /** * Verifies that the current Flow state is maintained, as well as view state associated with * Flow state. */ @Test public void rotationMaintainsState() { // Enter some text on the welcome screen onView(withId(R.id.welcome_screen_name)) .perform(ViewActions.typeText("Bart")); rotate(); // We should still have that text, despite the configuration change. onView(withId(R.id.welcome_screen_name)) .check(matches(withText("Bart"))); // Continue to the next screen and verify that it's showing info from our Flow state object. onView(withId(R.id.welcome_screen_name)) .perform(ViewActions.typeText("\n")); onView(withId(R.id.hello_name)) .check(matches(withText("Hello Bart"))); // Change the text in the counter TextView. Only this view knows its state, we don't store it // anywhere else. onView(withId(R.id.hello_increment)) .perform(click()) .perform(click()); onView(withId(R.id.hello_counter)) .check(matches(withText("2"))); rotate(); // Verify that we still have our Flow state object. onView(withId(R.id.hello_name)) .check(matches(withText("Hello Bart"))); // Verify that the counter TextView's view state was restored. onView(withId(R.id.hello_counter)) .check(matches(withText("2"))); } /** Verifies that states in the history keep their associated view state. */ @Test public void goingBackWorksAndRestoresState() { // Enter some text in the name field and go forward. // The field's view state, including the text we entered, should be remembered in the history. onView(withId(R.id.welcome_screen_name)) .perform(ViewActions.typeText("Bart\n")); onView(withId(R.id.basic_activity_frame)) .check(matches(hasDescendant(isAssignableFrom(HelloView.class)))); pressBack(); onView(withId(R.id.basic_activity_frame)) .check(matches(hasDescendant(isAssignableFrom(WelcomeView.class)))); // When we navigated back, the view state of the name field should have been restored. onView(withId(R.id.welcome_screen_name)) .check(matches(withText("Bart"))); } private void rotate() { Configuration config = InstrumentationRegistry.getTargetContext().getResources().getConfiguration(); rule.getActivity().setRequestedOrientation( (config.orientation == ORIENTATION_PORTRAIT) ? SCREEN_ORIENTATION_LANDSCAPE : SCREEN_ORIENTATION_PORTRAIT); } }