reduce code duplication and creation of more test utils methods

This commit is contained in:
Marcatili, Manuel
2026-04-16 11:00:26 +03:00
committed by mmarca.tech
parent def4f3a1b9
commit 81081b0ee5
7 changed files with 168 additions and 188 deletions
@@ -2,46 +2,36 @@ package de.dennisguse.opentracks;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.replaceText;
import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static androidx.test.espresso.matcher.RootMatchers.isDialog;
import static androidx.test.espresso.matcher.RootMatchers.isPlatformPopup;
import static de.dennisguse.opentracks.util.ActivityTestUtils.waitForResumedActivity;
import static de.dennisguse.opentracks.util.EspressoUtils.performClick;
import static de.dennisguse.opentracks.util.EspressoUtils.performClickOnAncestor;
import static de.dennisguse.opentracks.util.EspressoUtils.performLongClick;
import static de.dennisguse.opentracks.util.EspressoUtils.performLongClickOnAncestor;
import static de.dennisguse.opentracks.util.EspressoUtils.waitForResumedView;
import static de.dennisguse.opentracks.util.EspressoUtils.waitForResumedViewCondition;
import static de.dennisguse.opentracks.util.EspressoUtils.waitUntilDisplayed;
import static de.dennisguse.opentracks.util.EspressoUtils.waitUntilRecyclerViewItemCount;
import static de.dennisguse.opentracks.util.EspressoUtils.withRecyclerViewItemCount;
import static de.dennisguse.opentracks.util.TrackRecordingServiceTestUtils.waitForRecordingState;
import static de.dennisguse.opentracks.util.TestEnvironmentUtils.resetTrackRecordingServiceAndDeleteTracks;
import static de.dennisguse.opentracks.util.TrackUiTestUtils.renameStoppedTrack;
import static de.dennisguse.opentracks.util.TrackUiTestUtils.startRecordingFromTrackList;
import static de.dennisguse.opentracks.util.TrackUiTestUtils.stopRecordingToTrackStopped;
import static org.hamcrest.Matchers.allOf;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.GrantPermissionRule;
import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.time.Duration;
import de.dennisguse.opentracks.data.ContentProviderUtils;
@LargeTest
@RunWith(AndroidJUnit4.class)
@@ -57,9 +47,7 @@ public class EspressoDeleteTrackTest {
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
context.stopService(new Intent(context, de.dennisguse.opentracks.services.TrackRecordingService.class));
new ContentProviderUtils(context).deleteAllTracks(context);
resetTrackRecordingServiceAndDeleteTracks();
}
@Test
@@ -72,9 +60,8 @@ public class EspressoDeleteTrackTest {
onView(withText(android.R.string.ok))
.inRoot(isDialog())
.perform(performClick());
waitForResumedActivity(TrackListActivity.class, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_list));
waitUntilRecyclerViewItemCount(withId(R.id.track_list), 0);
waitUntilDisplayed(withId(R.id.track_list), UI_TIMEOUT);
waitUntilRecyclerViewItemCount(withId(R.id.track_list), 0, UI_TIMEOUT);
// the recycler is empty again after discarding the only recorded track
onView(withId(R.id.track_list))
@@ -86,15 +73,13 @@ public class EspressoDeleteTrackTest {
String uniqueTrackName = "DeleteFromTrackList-" + System.currentTimeMillis();
recordTrackAndOpenTrackStoppedActivity();
onView(withId(R.id.track_edit_name))
.perform(scrollTo(), replaceText(uniqueTrackName), closeSoftKeyboard());
renameStoppedTrack(uniqueTrackName, UI_TIMEOUT);
onView(withId(R.id.finish_button))
.perform(performClick());
waitForResumedActivity(TrackListActivity.class, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_list));
waitUntilDisplayed(allOf(withId(R.id.track_list_item_name), withText(uniqueTrackName)));
waitUntilRecyclerViewItemCount(withId(R.id.track_list), 1);
waitUntilDisplayed(withId(R.id.track_list), UI_TIMEOUT);
waitUntilDisplayed(allOf(withId(R.id.track_list_item_name), withText(uniqueTrackName)), UI_TIMEOUT);
waitUntilRecyclerViewItemCount(withId(R.id.track_list), 1, UI_TIMEOUT);
onView(allOf(withId(R.id.track_list_item_name), withText(uniqueTrackName)))
.perform(performLongClickOnAncestor());
@@ -103,34 +88,20 @@ public class EspressoDeleteTrackTest {
onView(withText(android.R.string.ok))
.inRoot(isDialog())
.perform(performClick());
waitUntilRecyclerViewItemCount(withId(R.id.track_list), 0);
waitUntilRecyclerViewItemCount(withId(R.id.track_list), 0, UI_TIMEOUT);
onView(withId(R.id.track_list))
.check(matches(withRecyclerViewItemCount(0)));
}
private void recordTrackAndOpenTrackStoppedActivity() {
// TrackListActivity: start recording
onView(withId(R.id.track_list_fab_action))
.perform(performClick());
waitForResumedActivity(TrackRecordingActivity.class, UI_TIMEOUT);
waitForRecordingState(true, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_recording_fab_action));
// TrackRecordingActivity: stop recording and open TrackStoppedActivity
onView(withId(R.id.track_recording_fab_action))
.perform(performLongClick());
waitForResumedActivity(TrackStoppedActivity.class, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_edit_name));
waitUntilDisplayed(withId(R.id.discard_button));
waitUntilDisplayed(withId(R.id.finish_button));
onView(withId(R.id.track_edit_name))
.perform(closeSoftKeyboard());
startRecordingFromTrackList(UI_TIMEOUT);
stopRecordingToTrackStopped(UI_TIMEOUT, R.id.discard_button, R.id.finish_button);
}
private void clickDeleteSelectedTrackAction() {
try {
waitUntilDisplayed(withId(R.id.list_context_menu_delete));
waitUntilDisplayed(withId(R.id.list_context_menu_delete), UI_TIMEOUT);
onView(withId(R.id.list_context_menu_delete))
.perform(performClick());
} catch (AssertionError ignored) {
@@ -144,15 +115,4 @@ public class EspressoDeleteTrackTest {
}
}
private void waitUntilDisplayed(Matcher<View> viewMatcher) {
waitForResumedView(allOf(viewMatcher, isDisplayed()), UI_TIMEOUT);
}
private void waitUntilRecyclerViewItemCount(Matcher<View> viewMatcher, int expectedCount) {
waitForResumedViewCondition(
viewMatcher,
view -> withRecyclerViewItemCount(expectedCount).matches(view),
"RecyclerView item count to be " + expectedCount,
UI_TIMEOUT);
}
}
@@ -12,25 +12,19 @@ import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA;
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.dennisguse.opentracks.util.ActivityTestUtils.waitForResumedActivity;
import static de.dennisguse.opentracks.util.EspressoUtils.performClick;
import static de.dennisguse.opentracks.util.EspressoUtils.performClickOnAncestor;
import static de.dennisguse.opentracks.util.EspressoUtils.performLongClick;
import static de.dennisguse.opentracks.util.EspressoUtils.waitForResumedView;
import static de.dennisguse.opentracks.util.TrackRecordingServiceTestUtils.waitForRecordingState;
import static de.dennisguse.opentracks.util.EspressoUtils.waitUntilDisplayed;
import static de.dennisguse.opentracks.util.TestEnvironmentUtils.resetTrackRecordingServiceAndDeleteTracks;
import static de.dennisguse.opentracks.util.TrackUiTestUtils.startRecordingFromTrackList;
import static de.dennisguse.opentracks.util.TrackUiTestUtils.stopRecordingToTrackStopped;
import static org.hamcrest.Matchers.allOf;
import android.view.View;
import android.content.Context;
import android.content.Intent;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.GrantPermissionRule;
import org.hamcrest.Matcher;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -38,7 +32,6 @@ import org.junit.runner.RunWith;
import java.time.Duration;
import java.util.Locale;
import de.dennisguse.opentracks.data.ContentProviderUtils;
@LargeTest
@RunWith(AndroidJUnit4.class)
@@ -57,22 +50,13 @@ public class EspressoEditTrackRecordingTest {
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
context.stopService(new Intent(context, de.dennisguse.opentracks.services.TrackRecordingService.class));
new ContentProviderUtils(context).deleteAllTracks(context);
resetTrackRecordingServiceAndDeleteTracks();
}
@LargeTest
@Test
public void espressoEditTrackRecordingTest() {
{
// TrackListActivity: start recording
onView(withId(R.id.track_list_fab_action))
.perform(performClick());
waitForResumedActivity(TrackRecordingActivity.class, UI_TIMEOUT);
waitForRecordingState(true, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_recording_fab_action));
}
startRecordingFromTrackList(UI_TIMEOUT);
{
// TrackRecordingActivity
@@ -84,7 +68,7 @@ public class EspressoEditTrackRecordingTest {
onView(withText(R.string.menu_edit))
.inRoot(isPlatformPopup())
.perform(performClickOnAncestor());
waitUntilDisplayed(withId(R.id.track_edit_name));
waitUntilDisplayed(withId(R.id.track_edit_name), UI_TIMEOUT);
// change name for "New Name"
onView(withId(R.id.track_edit_name))
@@ -96,14 +80,10 @@ public class EspressoEditTrackRecordingTest {
// save edition
onView(withId(R.id.track_edit_save))
.perform(performClick());
waitUntilDisplayed(withId(R.id.track_recording_fab_action));
waitUntilDisplayed(withId(R.id.track_recording_fab_action), UI_TIMEOUT);
// stop;
onView(withId(R.id.track_recording_fab_action))
.perform(performLongClick());
waitForResumedActivity(TrackStoppedActivity.class, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.resume_button));
waitUntilDisplayed(withId(R.id.finish_button));
stopRecordingToTrackStopped(UI_TIMEOUT, R.id.resume_button, R.id.finish_button);
// it's on track stopped activity and there are two buttons
onView(withId(R.id.resume_button))
@@ -112,8 +92,4 @@ public class EspressoEditTrackRecordingTest {
.check(matches(isDisplayed()));
}
}
private void waitUntilDisplayed(Matcher<View> viewMatcher) {
waitForResumedView(allOf(viewMatcher, isDisplayed()), UI_TIMEOUT);
}
}
@@ -1,28 +1,24 @@
package de.dennisguse.opentracks;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.dennisguse.opentracks.util.ActivityTestUtils.waitForResumedActivity;
import static de.dennisguse.opentracks.util.EspressoUtils.performClick;
import static de.dennisguse.opentracks.util.EspressoUtils.performLongClick;
import static de.dennisguse.opentracks.util.EspressoUtils.performLongClickOnAncestor;
import static de.dennisguse.opentracks.util.EspressoUtils.selectTabAtIndex;
import static de.dennisguse.opentracks.util.EspressoUtils.waitForResumedView;
import static de.dennisguse.opentracks.util.EspressoUtils.waitUntilDisplayed;
import static de.dennisguse.opentracks.util.EspressoUtils.waitForResumedViewCondition;
import static de.dennisguse.opentracks.util.EspressoUtils.withSelectedTab;
import static de.dennisguse.opentracks.util.EspressoUtils.withViewPagerCurrentItem;
import static de.dennisguse.opentracks.util.TrackRecordingServiceTestUtils.waitForRecordingState;
import static de.dennisguse.opentracks.util.TestEnvironmentUtils.resetTrackRecordingServiceAndDeleteTracks;
import static de.dennisguse.opentracks.util.TrackUiTestUtils.finishStoppedTrack;
import static de.dennisguse.opentracks.util.TrackUiTestUtils.resumeStoppedTrack;
import static de.dennisguse.opentracks.util.TrackUiTestUtils.startRecordingFromTrackList;
import static de.dennisguse.opentracks.util.TrackUiTestUtils.stopRecordingToTrackStopped;
import static org.hamcrest.Matchers.allOf;
import android.util.Pair;
import android.content.Context;
import android.content.Intent;
import android.view.View;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.espresso.ViewInteraction;
@@ -40,6 +36,7 @@ import org.junit.runner.RunWith;
import java.time.Duration;
import java.util.List;
import de.dennisguse.opentracks.content.data.TestDataUtil;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
@@ -61,68 +58,27 @@ public class EspressoUITest {
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
context.stopService(new Intent(context, de.dennisguse.opentracks.services.TrackRecordingService.class));
new ContentProviderUtils(context).deleteAllTracks(context);
resetTrackRecordingServiceAndDeleteTracks();
}
@LargeTest
@Test
public void record_stop_resume_stop_finish() {
startRecordingFromTrackList(UI_TIMEOUT);
{
// TrackListActivity: start recording
onView(withId(R.id.track_list_fab_action))
.perform(performClick());
waitForResumedActivity(TrackRecordingActivity.class, UI_TIMEOUT);
waitForRecordingState(true, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_recording_fab_action));
}
{
// TrackRecordingActivity: stop
onView(withId(R.id.track_recording_fab_action))
.perform(performLongClick());
waitForResumedActivity(TrackStoppedActivity.class, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_edit_name));
waitUntilDisplayed(withId(R.id.resume_button));
onView(withId(R.id.track_edit_name))
.perform(closeSoftKeyboard());
// TrackStoppedActivity: resume
onView(allOf(withId(R.id.resume_button), isClickable()))
.perform(performClick());
waitForResumedActivity(TrackRecordingActivity.class, UI_TIMEOUT);
waitForRecordingState(true, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_recording_fab_action));
// TrackRecordingActivity: stop again
onView(withId(R.id.track_recording_fab_action))
.perform(performLongClick());
waitForResumedActivity(TrackStoppedActivity.class, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_edit_name));
waitUntilDisplayed(withId(R.id.finish_button));
onView(withId(R.id.track_edit_name))
.perform(closeSoftKeyboard());
// TrackStoppedActivity
onView(withId(R.id.finish_button))
.perform(performClick());
waitForResumedActivity(TrackListActivity.class, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_list));
stopRecordingToTrackStopped(UI_TIMEOUT, R.id.resume_button);
resumeStoppedTrack(UI_TIMEOUT);
stopRecordingToTrackStopped(UI_TIMEOUT, R.id.finish_button);
finishStoppedTrack(UI_TIMEOUT);
}
}
@LargeTest
@Test
public void record_move_through_tabs() {
{
// TrackListActivity: start recording
onView(withId(R.id.track_list_fab_action))
.perform(performClick());
waitForResumedActivity(TrackRecordingActivity.class, UI_TIMEOUT);
waitForRecordingState(true, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_detail_activity_tablayout));
waitUntilDisplayed(withId(R.id.track_detail_activity_view_pager));
}
startRecordingFromTrackList(UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_detail_activity_tablayout), UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.track_detail_activity_view_pager), UI_TIMEOUT);
{
// TrackRecordingActivity
ViewInteraction tabLayout = onView(withId(R.id.track_detail_activity_tablayout));
@@ -140,10 +96,7 @@ public class EspressoUITest {
waitUntilTabSelectionSettlesAt(0);
// stop
onView(withId(R.id.track_recording_fab_action))
.perform(performLongClick());
waitForResumedActivity(TrackStoppedActivity.class, UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.resume_button));
stopRecordingToTrackStopped(UI_TIMEOUT, R.id.resume_button);
}
}
@@ -156,17 +109,13 @@ public class EspressoUITest {
trackBuilder.setName(uniqueTrackName);
TestDataUtil.insertTrackWithLocations(new ContentProviderUtils(ApplicationProvider.getApplicationContext()), trackBuilder.getTrack(), pair.second);
activityRule.getScenario().recreate();
waitUntilDisplayed(allOf(withId(R.id.track_list_item_name), withText(uniqueTrackName)));
waitUntilDisplayed(allOf(withId(R.id.track_list_item_name), withText(uniqueTrackName)), UI_TIMEOUT);
onView(withId(R.id.track_list)).check(matches(isDisplayed()));
onView(allOf(withId(R.id.track_list_item_name), withText(uniqueTrackName)))
.perform(performLongClickOnAncestor());
}
private void waitUntilDisplayed(Matcher<View> viewMatcher) {
waitForResumedView(allOf(viewMatcher, isDisplayed()), UI_TIMEOUT);
}
private void waitUntilTabSelectionSettlesAt(int index) {
waitForResumedViewCondition(
withId(R.id.track_detail_activity_tablayout),
@@ -9,18 +9,16 @@ import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withParent;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static de.dennisguse.opentracks.util.EspressoUtils.performClick;
import static de.dennisguse.opentracks.util.EspressoUtils.waitForResumedView;
import static de.dennisguse.opentracks.util.EspressoUtils.waitForResumedViewCondition;
import static de.dennisguse.opentracks.util.EspressoUtils.withRecyclerViewItemCount;
import static de.dennisguse.opentracks.util.EspressoUtils.waitUntilDisplayed;
import static de.dennisguse.opentracks.util.EspressoUtils.waitUntilRecyclerViewItemCount;
import static de.dennisguse.opentracks.util.TestEnvironmentUtils.resetTrackRecordingServiceAndDeleteTracks;
import static de.dennisguse.opentracks.util.TestEnvironmentUtils.stopTrackRecordingService;
import static org.hamcrest.Matchers.allOf;
import android.content.Context;
import android.content.Intent;
import android.util.Pair;
import android.view.View;
import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
import androidx.test.rule.GrantPermissionRule;
@@ -43,7 +41,6 @@ import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.data.models.Track;
import de.dennisguse.opentracks.data.models.TrackBuilder;
import de.dennisguse.opentracks.data.models.TrackPoint;
import de.dennisguse.opentracks.services.TrackRecordingService;
@LargeTest
@RunWith(AndroidJUnit4.class)
@@ -60,11 +57,8 @@ public class EspressoAggregatedFilterTest {
@Before
public void setUp() {
Context context = ApplicationProvider.getApplicationContext();
context.stopService(new Intent(context, TrackRecordingService.class));
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
contentProviderUtils.deleteAllTracks(context);
resetTrackRecordingServiceAndDeleteTracks();
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(androidx.test.core.app.ApplicationProvider.getApplicationContext());
Pair<Track, List<TrackPoint>> pair = TestDataUtil.createTrack(new Track.Id(System.currentTimeMillis()), 20);
TrackBuilder trackBuilder = new TrackBuilder(pair.first);
@@ -76,8 +70,7 @@ public class EspressoAggregatedFilterTest {
@After
public void tearDown() {
Context context = ApplicationProvider.getApplicationContext();
context.stopService(new Intent(context, TrackRecordingService.class));
stopTrackRecordingService();
if (scenario != null) {
scenario.close();
}
@@ -85,10 +78,10 @@ public class EspressoAggregatedFilterTest {
@Test
public void espressoAggregatedFilterTest() {
waitUntilDisplayed(withId(R.id.bottom_app_bar));
waitUntilDisplayed(withId(R.id.aggregated_statistics_filter));
waitUntilRecyclerViewItemCount(withId(R.id.aggregated_stats_list), 1);
waitUntilDisplayed(allOf(withId(R.id.aggregated_stats_type_label), withText(ACTIVITY_TYPE_LOCALIZED)));
waitUntilDisplayed(withId(R.id.bottom_app_bar), UI_TIMEOUT);
waitUntilDisplayed(withId(R.id.aggregated_statistics_filter), UI_TIMEOUT);
waitUntilRecyclerViewItemCount(withId(R.id.aggregated_stats_list), 1, UI_TIMEOUT);
waitUntilDisplayed(allOf(withId(R.id.aggregated_stats_type_label), withText(ACTIVITY_TYPE_LOCALIZED)), UI_TIMEOUT);
// open FilterDialogFragment through the current bottom app bar action item
onView(withId(R.id.bottom_app_bar))
@@ -118,15 +111,4 @@ public class EspressoAggregatedFilterTest {
.check(matches(isDisplayed()));
}
private void waitUntilDisplayed(Matcher<View> viewMatcher) {
waitForResumedView(allOf(viewMatcher, isDisplayed()), UI_TIMEOUT);
}
private void waitUntilRecyclerViewItemCount(Matcher<View> viewMatcher, int expectedCount) {
waitForResumedViewCondition(
allOf(viewMatcher, isDisplayed()),
view -> withRecyclerViewItemCount(expectedCount).matches(view),
"RecyclerView item count to be " + expectedCount,
UI_TIMEOUT);
}
}
@@ -1,5 +1,6 @@
package de.dennisguse.opentracks.util;
import static org.hamcrest.Matchers.allOf;
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom;
@@ -88,6 +89,18 @@ public class EspressoUtils {
waitForResumedViewCondition(viewMatcher, ignored -> true, "view to match " + viewMatcher, timeout);
}
public static void waitUntilDisplayed(final Matcher<View> viewMatcher, final Duration timeout) {
waitForResumedView(allOf(viewMatcher, isDisplayed()), timeout);
}
public static void waitUntilRecyclerViewItemCount(final Matcher<View> viewMatcher, final int expectedCount, final Duration timeout) {
waitForResumedViewCondition(
allOf(viewMatcher, isDisplayed()),
view -> withRecyclerViewItemCount(expectedCount).matches(view),
"RecyclerView item count to be " + expectedCount,
timeout);
}
public static void waitForResumedViewCondition(final Matcher<View> viewMatcher,
final Predicate<View> condition,
final String conditionDescription,
@@ -0,0 +1,30 @@
package de.dennisguse.opentracks.util;
import android.content.Context;
import android.content.Intent;
import androidx.test.core.app.ApplicationProvider;
import de.dennisguse.opentracks.data.ContentProviderUtils;
import de.dennisguse.opentracks.services.TrackRecordingService;
public final class TestEnvironmentUtils {
private TestEnvironmentUtils() {
}
public static void stopTrackRecordingService() {
Context context = ApplicationProvider.getApplicationContext();
context.stopService(new Intent(context, TrackRecordingService.class));
}
public static void deleteAllTracks() {
Context context = ApplicationProvider.getApplicationContext();
new ContentProviderUtils(context).deleteAllTracks(context);
}
public static void resetTrackRecordingServiceAndDeleteTracks() {
stopTrackRecordingService();
deleteAllTracks();
}
}
@@ -0,0 +1,70 @@
package de.dennisguse.opentracks.util;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.closeSoftKeyboard;
import static androidx.test.espresso.action.ViewActions.replaceText;
import static androidx.test.espresso.action.ViewActions.scrollTo;
import static androidx.test.espresso.matcher.ViewMatchers.isClickable;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static de.dennisguse.opentracks.util.ActivityTestUtils.waitForResumedActivity;
import static de.dennisguse.opentracks.util.EspressoUtils.performClick;
import static de.dennisguse.opentracks.util.EspressoUtils.performLongClick;
import static de.dennisguse.opentracks.util.EspressoUtils.waitUntilDisplayed;
import static de.dennisguse.opentracks.util.TrackRecordingServiceTestUtils.waitForRecordingState;
import static org.hamcrest.Matchers.allOf;
import androidx.annotation.IdRes;
import java.time.Duration;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.TrackListActivity;
import de.dennisguse.opentracks.TrackRecordingActivity;
import de.dennisguse.opentracks.TrackStoppedActivity;
public final class TrackUiTestUtils {
private TrackUiTestUtils() {
}
public static void startRecordingFromTrackList(Duration timeout) {
onView(withId(R.id.track_list_fab_action))
.perform(performClick());
waitForResumedActivity(TrackRecordingActivity.class, timeout);
waitForRecordingState(true, timeout);
waitUntilDisplayed(withId(R.id.track_recording_fab_action), timeout);
}
public static void stopRecordingToTrackStopped(Duration timeout, @IdRes int... expectedVisibleViewIds) {
onView(withId(R.id.track_recording_fab_action))
.perform(performLongClick());
waitForResumedActivity(TrackStoppedActivity.class, timeout);
waitUntilDisplayed(withId(R.id.track_edit_name), timeout);
for (int viewId : expectedVisibleViewIds) {
waitUntilDisplayed(withId(viewId), timeout);
}
onView(withId(R.id.track_edit_name))
.perform(closeSoftKeyboard());
}
public static void resumeStoppedTrack(Duration timeout) {
onView(allOf(withId(R.id.resume_button), isClickable()))
.perform(performClick());
waitForResumedActivity(TrackRecordingActivity.class, timeout);
waitForRecordingState(true, timeout);
waitUntilDisplayed(withId(R.id.track_recording_fab_action), timeout);
}
public static void finishStoppedTrack(Duration timeout) {
onView(withId(R.id.finish_button))
.perform(performClick());
waitForResumedActivity(TrackListActivity.class, timeout);
waitUntilDisplayed(withId(R.id.track_list), timeout);
}
public static void renameStoppedTrack(String name, Duration timeout) {
waitUntilDisplayed(withId(R.id.track_edit_name), timeout);
onView(withId(R.id.track_edit_name))
.perform(scrollTo(), replaceText(name), closeSoftKeyboard());
}
}