diff --git a/app/src/androidTest/java/com/orgzly/android/espresso/BooksTest.java b/app/src/androidTest/java/com/orgzly/android/espresso/BooksTest.java index 04d1b75b6..3f85cb5d5 100644 --- a/app/src/androidTest/java/com/orgzly/android/espresso/BooksTest.java +++ b/app/src/androidTest/java/com/orgzly/android/espresso/BooksTest.java @@ -11,8 +11,12 @@ import static androidx.test.espresso.intent.Intents.intending; import static androidx.test.espresso.intent.matcher.IntentMatchers.hasAction; import static androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra; +import static androidx.test.espresso.matcher.ViewMatchers.hasChildCount; +import static androidx.test.espresso.matcher.ViewMatchers.isChecked; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; import static androidx.test.espresso.matcher.ViewMatchers.isEnabled; +import static androidx.test.espresso.matcher.ViewMatchers.isNotChecked; +import static androidx.test.espresso.matcher.ViewMatchers.withClassName; import static androidx.test.espresso.matcher.ViewMatchers.withId; import static androidx.test.espresso.matcher.ViewMatchers.withText; import static com.orgzly.android.espresso.util.EspressoUtils.contextualToolbarOverflowMenu; @@ -21,7 +25,9 @@ import static com.orgzly.android.espresso.util.EspressoUtils.onNoteInBook; import static com.orgzly.android.espresso.util.EspressoUtils.onSnackbar; import static com.orgzly.android.espresso.util.EspressoUtils.replaceTextCloseKeyboard; +import static com.orgzly.android.espresso.util.EspressoUtils.sync; import static org.hamcrest.Matchers.allOf; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.endsWith; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.startsWith; @@ -41,6 +47,7 @@ import com.orgzly.R; import com.orgzly.android.BookFormat; import com.orgzly.android.OrgzlyTest; +import com.orgzly.android.repos.RepoType; import com.orgzly.android.ui.main.MainActivity; import org.junit.Before; @@ -299,4 +306,106 @@ public void testBackPressClosesSelectionMenu() { // Make sure we're still in the app onBook(0, R.id.item_book_title).check(matches(withText("book-1"))); } + + @Test + public void testSetLinkOnSingleBookCurrentRepoIsSelected() { + testUtils.setupRepo(RepoType.MOCK, "mock://repo"); + sync(); + onBook(0, R.id.item_book_link_repo).check(matches(withText("mock://repo"))); + onBook(0).perform(longClick()); + contextualToolbarOverflowMenu().perform(click()); + onView(withText(R.string.books_context_menu_item_set_link)).perform(click()); + onView(withText("mock://repo")).check(matches(isChecked())); + } + + /** + * When setting the link of multiple books, no repo should be pre-selected, no matter how + * many repos there are, and no matter whether the books already have a link or not. The + * reason for this is that we have intuitive way of handling selected books being linked to + * different repos. + */ + @Test + public void testSetLinkOnMultipleBooksNoRepoIsSelected() { + testUtils.setupRepo(RepoType.MOCK, "mock://repo"); + sync(); + onBook(0, R.id.item_book_link_repo).check(matches(withText("mock://repo"))); + onBook(1, R.id.item_book_link_repo).check(matches(withText("mock://repo"))); + onBook(0).perform(longClick()); + onBook(1).perform(click()); + contextualToolbarOverflowMenu().perform(click()); + onView(withText(R.string.books_context_menu_item_set_link)).perform(click()); + onView(withText("mock://repo")).check(matches(isNotChecked())); + } + + @Test + public void testDeleteSingleBookLinkedUrlIsShown() { + testUtils.setupRepo(RepoType.MOCK, "mock://repo"); + sync(); + onBook(0, R.id.item_book_link_repo).check(matches(withText("mock://repo"))); + onBook(0).perform(longClick()); + contextualToolbarOverflowMenu().perform(click()); + onView(withText(R.string.delete)).perform(click()); + onView(withText(R.string.also_delete_linked_book)).check(matches(isDisplayed())); + onView(withId(R.id.delete_linked_url)).check(matches(withText("mock://repo/book-1.org"))); + } + + @Test + public void testDeleteMultipleBooksLinkedUrlIsNotShown() { + testUtils.setupRepo(RepoType.MOCK, "mock://repo"); + sync(); + onBook(0, R.id.item_book_link_repo).check(matches(withText("mock://repo"))); + onBook(1, R.id.item_book_link_repo).check(matches(withText("mock://repo"))); + onBook(0).perform(longClick()); + onBook(1).perform(click()); + contextualToolbarOverflowMenu().perform(click()); + onView(withText(R.string.delete)).perform(click()); + onView(withText(R.string.also_delete_linked_books)).check(matches(isDisplayed())); + onView(withId(R.id.delete_linked_url)).check(matches(withText(""))); + } + + @Test + public void testDeleteMultipleBooksWithNoLinks() { + onBook(0).perform(longClick()); + onBook(1).perform(click()); + contextualToolbarOverflowMenu().perform(click()); + onView(withText(R.string.delete)).perform(click()); + onView(withText(R.string.delete)).perform(click()); + assert dataRepository.getBooks().size() == 1; + } + + @Test + public void testDeleteMultipleBooksAndRooks() { + testUtils.setupRepo(RepoType.MOCK, "mock://repo"); + sync(); + onBook(0, R.id.item_book_link_repo).check(matches(withText("mock://repo"))); + onBook(1, R.id.item_book_link_repo).check(matches(withText("mock://repo"))); + onBook(0).perform(longClick()); + onBook(1).perform(click()); + contextualToolbarOverflowMenu().perform(click()); + onView(withText(R.string.delete)).perform(click()); + onView(withId(R.id.delete_linked_checkbox)).perform(click()); + onView(withText(R.string.delete)).perform(click()); + assert dataRepository.getBooks().size() == 1; + } + + /** + * When multiple books are selected, the "rename" and "export" actions should be removed from + * the context menu. By also testing that only the expected number of actions are shown, we + * protect against someone later adding actions to the menu without fully considering the support for + * multiple selected books. When such support is added, this test will need to be updated. + */ + @Test + public void testMultipleBooksSelectedContextMenuShowsSupportedActionsOnly() { + onBook(0).perform(longClick()); + contextualToolbarOverflowMenu().perform(click()); + onView(withText(R.string.rename)).check(matches(isDisplayed())); + onView(withText(R.string.export)).check(matches(isDisplayed())); + onView(withClassName(containsString("MenuDropDownListView"))).check(matches(hasChildCount(4))); + pressBack(); + onBook(1).perform(click()); + contextualToolbarOverflowMenu().perform(click()); + onView(withText(R.string.rename)).check(doesNotExist()); + onView(withText(R.string.export)).check(doesNotExist()); + onView(withClassName(containsString("MenuDropDownListView"))).check(matches(hasChildCount(2))); + } } diff --git a/app/src/androidTest/java/com/orgzly/android/espresso/SyncingTest.java b/app/src/androidTest/java/com/orgzly/android/espresso/SyncingTest.java index eecbd1d24..d8ad9b7db 100644 --- a/app/src/androidTest/java/com/orgzly/android/espresso/SyncingTest.java +++ b/app/src/androidTest/java/com/orgzly/android/espresso/SyncingTest.java @@ -5,7 +5,6 @@ import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.longClick; import static androidx.test.espresso.assertion.ViewAssertions.matches; -import static androidx.test.espresso.contrib.DrawerActions.close; import static androidx.test.espresso.contrib.DrawerActions.open; import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; @@ -14,7 +13,6 @@ import static androidx.test.espresso.matcher.ViewMatchers.withText; import static com.orgzly.android.espresso.util.EspressoUtils.clickSetting; import static com.orgzly.android.espresso.util.EspressoUtils.contextualToolbarOverflowMenu; -import static com.orgzly.android.espresso.util.EspressoUtils.grantAlarmsAndRemindersPermission; import static com.orgzly.android.espresso.util.EspressoUtils.onActionItemClick; import static com.orgzly.android.espresso.util.EspressoUtils.onBook; import static com.orgzly.android.espresso.util.EspressoUtils.onListItem; @@ -24,6 +22,7 @@ import static com.orgzly.android.espresso.util.EspressoUtils.recyclerViewItemCount; import static com.orgzly.android.espresso.util.EspressoUtils.replaceTextCloseKeyboard; import static com.orgzly.android.espresso.util.EspressoUtils.settingsSetTodoKeywords; +import static com.orgzly.android.espresso.util.EspressoUtils.sync; import static org.hamcrest.Matchers.allOf; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.endsWith; @@ -69,16 +68,6 @@ public void tearDown() throws Exception { } } - /** - * Utility method for starting sync using drawer button. - */ - private void sync() { - grantAlarmsAndRemindersPermission(); - onView(withId(R.id.drawer_layout)).perform(open()); - onView(withId(R.id.sync_button_container)).perform(click()); - onView(withId(R.id.drawer_layout)).perform(close()); - } - @Test public void testRunSync() { scenario = ActivityScenario.launch(MainActivity.class); diff --git a/app/src/androidTest/java/com/orgzly/android/espresso/util/EspressoUtils.java b/app/src/androidTest/java/com/orgzly/android/espresso/util/EspressoUtils.java index 66141e453..cc401eaba 100644 --- a/app/src/androidTest/java/com/orgzly/android/espresso/util/EspressoUtils.java +++ b/app/src/androidTest/java/com/orgzly/android/espresso/util/EspressoUtils.java @@ -7,6 +7,8 @@ import static androidx.test.espresso.action.ViewActions.click; import static androidx.test.espresso.action.ViewActions.pressKey; import static androidx.test.espresso.action.ViewActions.replaceText; +import static androidx.test.espresso.contrib.DrawerActions.close; +import static androidx.test.espresso.contrib.DrawerActions.open; import static androidx.test.espresso.matcher.ViewMatchers.hasDescendant; import static androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom; import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed; @@ -512,4 +514,14 @@ public static void grantAlarmsAndRemindersPermission() { getInstrumentation().getUiAutomation().executeShellCommand(shellCmd); } } + + /** + * Utility method for starting sync using drawer button. + */ + public static void sync() { + grantAlarmsAndRemindersPermission(); + onView(withId(R.id.drawer_layout)).perform(open()); + onView(withId(R.id.sync_button_container)).perform(click()); + onView(withId(R.id.drawer_layout)).perform(close()); + } } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2a796190e..eaf761f93 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -291,7 +291,7 @@ Renamed from ā€œ%sā€ Delete linked remote notebook - Delete all linked remote notebooks + Delete any linked remote notebooks Deleting notebook(s) failed: %s Notebook(s) deleted