package com.orgzly.android.espresso;
import android.support.test.rule.ActivityTestRule;
import android.widget.DatePicker;
import android.widget.TimePicker;
import com.orgzly.R;
import com.orgzly.android.OrgzlyTest;
import com.orgzly.android.ui.MainActivity;
import org.junit.Rule;
import org.junit.Test;
import java.io.IOException;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.openContextualActionModeOverflowMenu;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.longClick;
import static android.support.test.espresso.action.ViewActions.replaceText;
import static android.support.test.espresso.action.ViewActions.scrollTo;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.contrib.DrawerActions.open;
import static android.support.test.espresso.contrib.PickerActions.setDate;
import static android.support.test.espresso.contrib.PickerActions.setTime;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
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 com.orgzly.android.espresso.EspressoUtils.closeSoftKeyboardWithDelay;
import static com.orgzly.android.espresso.EspressoUtils.listViewItemCount;
import static com.orgzly.android.espresso.EspressoUtils.onListItem;
import static com.orgzly.android.espresso.EspressoUtils.searchForText;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.startsWith;
/**
*
*/
@SuppressWarnings("unchecked")
public class QueryFragmentTest extends OrgzlyTest {
@Rule
public ActivityTestRule activityRule = new ActivityTestRule<>(MainActivity.class, true, false);
private void defaultSetUp() {
shelfTestUtils.setupBook("book-one",
"First book used for testing\n" +
"* Note A.\n" +
"** [#A] Note B.\n" +
"* TODO Note C.\n" +
"SCHEDULED: <2014-01-01>\n" +
"** Note D.\n" +
"*** TODO Note E.\n" +
"*** Same title in different notebooks.\n" +
"*** Another note.\n" +
"");
shelfTestUtils.setupBook("book-two",
"Sample book used for tests\n" +
"* Note #1.\n" +
"* Note #2.\n" +
"** TODO Note #3.\n" +
"** Note #4.\n" +
"*** DONE Note #5.\n" +
"CLOSED: [2014-06-03 Tue 13:34]\n" +
"**** Note #6.\n" +
"** Note #7.\n" +
"* DONE Note #8.\n" +
"CLOSED: [2014-06-03 Tue 3:34]\n" +
"**** Note #9.\n" +
"SCHEDULED: <2014-05-26 Mon>\n" +
"** Note #10.\n" +
"** Same title in different notebooks.\n" +
"** Note #11.\n" +
"** Note #12.\n" +
"** Note #13.\n" +
"DEADLINE: <2014-05-26 Mon>\n" +
"** Note #14.\n" +
"** [#A] Note #15.\n" +
"** [#A] Note #16.\n" +
"** [#B] Note #17.\n" +
"** [#C] Note #18.\n" +
"** Note #19.\n" +
"** Note #20.\n" +
"** Note #21.\n" +
"** Note #22.\n" +
"** Note #23.\n" +
"** Note #24.\n" +
"** Note #25.\n" +
"** Note #26.\n" +
"** Note #27.\n" +
"** Note #28.\n" +
"");
activityRule.launchActivity(null);
}
@Test
public void testSearchFromBookOneResult() {
defaultSetUp();
onView(allOf(withText("book-one"), isDisplayed())).perform(click());
searchForText("b.book-one another note");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(1)));
onListItem(0).onChildView(withId(R.id.item_head_title)).check(matches(allOf(withText("Another note."), isDisplayed())));
}
@Test
public void testSearchFromBookMultipleResults() {
defaultSetUp();
onView(allOf(withText("book-one"), isDisplayed())).perform(click());
searchForText("b.book-one note");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(7)));
}
@Test
public void testSearchTwice() {
defaultSetUp();
searchForText("different");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
searchForText("another");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(1)));
}
@Test
public void testSearchExpressionTodo() {
defaultSetUp();
searchForText("i.todo");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(3)));
}
@Test
public void testSearchExpressionsToday() {
defaultSetUp();
searchForText("s.today");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
}
@Test
public void testSearchExpressionsPriority() {
defaultSetUp();
searchForText("p.a");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(3)));
onListItem(0).onChildView(withId(R.id.item_head_title)).check(matches(allOf(withText("#A Note B."), isDisplayed())));
onListItem(1).onChildView(withId(R.id.item_head_title)).check(matches(allOf(withText("#A Note #15."), isDisplayed())));
onListItem(2).onChildView(withId(R.id.item_head_title)).check(matches(allOf(withText("#A Note #16."), isDisplayed())));
}
@Test
public void testSearchInBook() {
defaultSetUp();
searchForText("b.book-one note");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(7)));
}
/**
* Starting with 3 displayed to-do notes, removing state from one, expecting 2 to-do notes left.
*/
@Test
public void testEditChangeState() {
defaultSetUp();
onView(withId(R.id.drawer_layout)).perform(open());
onView(withText("To Do")).perform(click());
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(3)));
onView(allOf(withText(endsWith("Note C.")), isDisplayed())).perform(longClick());
onView(withId(R.id.query_cab_edit)).perform(click());
onView(withText(R.string.state)).perform(click());
onView(withText("NOTE")).perform(click());
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
}
/**
* Clicks on the last note and expects it opened.
*/
@Test
public void testClickingNote() {
defaultSetUp();
onView(allOf(withText("book-two"), isDisplayed())).perform(click());
searchForText("b.book-two Note");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(29)));
onListItem(27).perform(click());
onView(withId(R.id.fragment_note_view_flipper)).check(matches(isDisplayed()));
onView(withText("Note #28.")).check(matches(isDisplayed()));
}
@Test
public void testSchedulingNote() {
defaultSetUp();
onView(withId(R.id.drawer_layout)).perform(open());
onView(withText("Scheduled")).perform(click());
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
onView(allOf(withText(endsWith("Note C.")), isDisplayed())).perform(longClick());
onView(withId(R.id.query_cab_edit)).perform(click());
onView(withText(R.string.schedule)).perform(click());
onView(withId(R.id.dialog_timestamp_date_picker)).perform(click());
onView(withClassName(equalTo(DatePicker.class.getName()))).perform(setDate(2014, 4, 1));
onView(withText(R.string.ok)).perform(click());
onView(withId(R.id.dialog_timestamp_time_picker)).perform(scrollTo(), click());
onView(withClassName(equalTo(TimePicker.class.getName()))).perform(setTime(9, 15));
onView(withText(R.string.ok)).perform(click());
onView(withText(R.string.set)).perform(click());
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
onView(withText(userDateTime("<2014-04-01 Tue 09:15>"))).check(matches(isDisplayed()));
}
@Test
public void testSearchExpressionsDefaultPriority() {
shelfTestUtils.setupBook("book-one",
"* Note A.\n" +
"** [#A] Note B.\n" +
"* TODO [#B] Note C.\n" +
"SCHEDULED: <2014-01-01>\n" +
"** [#C] Note D.\n" +
"*** TODO Note E.");
shelfTestUtils.setupBook("book-two", "* Note #1.\n");
activityRule.launchActivity(null);
searchForText("p.b");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(4)));
}
@Test
public void testMultipleNotState() {
shelfTestUtils.setupBook("notebook-1",
"* Note A.\n" +
"** [#A] Note B.\n" +
"* TODO Note C.\n" +
"SCHEDULED: <2014-01-01>\n" +
"** Note D.\n" +
"");
shelfTestUtils.setupBook("notebook-2",
"* Note #1.\n" +
"** TODO Note #3.\n" +
"** Note #4.\n" +
"*** DONE Note #5.\n" +
"CLOSED: [2014-06-03 Tue 13:34]\n" +
"");
activityRule.launchActivity(null);
searchForText(".i.todo .i.done");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(5)));
}
/**
* Added after a bug when using insertWithOnConflict for timestamps,
* due to https://code.google.com/p/android/issues/detail?id=13045
*/
@Test
public void testNotesWithSameScheduledTimeString() throws IOException {
shelfTestUtils.setupBook("notebook-1", "* Note A\nSCHEDULED: <2014-01-01>");
shelfTestUtils.setupBook("notebook-2", "* Note B\nSCHEDULED: <2014-01-01>");
activityRule.launchActivity(null);
searchForText("s.today");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
}
@Test
public void testNotesWithSameDeadlineTimeString() throws IOException {
shelfTestUtils.setupBook("notebook-1", "* Note A\nDEADLINE: <2014-01-01>");
shelfTestUtils.setupBook("notebook-2", "* Note B\nDEADLINE: <2014-01-01>");
activityRule.launchActivity(null);
searchForText("d.today");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
}
@Test
public void testInheritedTagSearchWhenMultipleAncestorsMatch() {
shelfTestUtils.setupBook("notebook-1",
"* Note A :tagtag:\n" +
"** Note B :tag:\n" +
"*** Note C\n" +
"*** Note D\n" +
"");
activityRule.launchActivity(null);
onView(allOf(withText("notebook-1"), isDisplayed())).perform(click());
searchForText("t.tag");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(4)));
}
@Test
public void testInheritedAndOwnTag() {
shelfTestUtils.setupBook("notebook-1",
"* Note A :tag1:\n" +
"** Note B :tag2:\n" +
"*** Note C\n" +
"*** Note D\n" +
"");
activityRule.launchActivity(null);
onView(allOf(withText("notebook-1"), isDisplayed())).perform(click());
searchForText("t.tag1 t.tag2");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(3)));
onListItem(0).onChildView(withId(R.id.item_head_title)).check(matches(allOf(withText(startsWith("Note B")), isDisplayed())));
onListItem(1).onChildView(withId(R.id.item_head_title)).check(matches(allOf(withText(startsWith("Note C")), isDisplayed())));
onListItem(2).onChildView(withId(R.id.item_head_title)).check(matches(allOf(withText(startsWith("Note D")), isDisplayed())));
}
@Test
public void testInheritedTagsAfterMovingNote() {
shelfTestUtils.setupBook("notebook-1",
"* Note A :tag1:\n" +
"** Note B :tag2:\n" +
"*** Note C :tag3:\n" +
"*** Note D :tag3:\n" +
"");
activityRule.launchActivity(null);
onView(allOf(withText("notebook-1"), isDisplayed())).perform(click());
/* Move Note C down. */
onListItem(2).perform(longClick());
openContextualActionModeOverflowMenu();
onView(withText(R.string.move)).perform(click());
onView(withId(R.id.notes_action_move_down)).perform(click());
pressBack();
searchForText("t.tag3");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
onListItem(0).onChildView(withId(R.id.item_head_title))
.check(matches(allOf(withText("Note D tag3 • tag2 tag1"), isDisplayed())));
onListItem(1).onChildView(withId(R.id.item_head_title))
.check(matches(allOf(withText("Note C tag3 • tag2 tag1"), isDisplayed())));
}
@Test
public void testInheritedTagsAfterDemotingSubtree() {
shelfTestUtils.setupBook("notebook-1",
"* Note A :tag1:\n" +
"* Note B :tag2:\n" +
"** Note C :tag3:\n" +
"** Note D :tag3:\n" +
"");
activityRule.launchActivity(null);
onView(allOf(withText("notebook-1"), isDisplayed())).perform(click());
/* Demote Note B. */
onListItem(1).perform(longClick());
openContextualActionModeOverflowMenu();
onView(withText(R.string.move)).perform(click());
onView(withId(R.id.notes_action_move_right)).perform(click());
pressBack();
searchForText("t.tag3");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
onListItem(0).onChildView(withId(R.id.item_head_title))
.check(matches(allOf(withText("Note C tag3 • tag1 tag2"), isDisplayed())));
onListItem(1).onChildView(withId(R.id.item_head_title))
.check(matches(allOf(withText("Note D tag3 • tag1 tag2"), isDisplayed())));
}
@Test
public void testInheritedTagsAfterCutAndPasting() {
shelfTestUtils.setupBook("notebook-1",
"* Note A :tag1:\n" +
"* Note B :tag2:\n" +
"** Note C :tag3:\n" +
"** Note D :tag3:\n" +
"");
activityRule.launchActivity(null);
onView(allOf(withText("notebook-1"), isDisplayed())).perform(click());
/* Cut Note B. */
onListItem(1).perform(longClick());
openContextualActionModeOverflowMenu();
onView(withText(R.string.cut)).perform(click());
/* Paste under Note A. */
onListItem(0).perform(longClick());
openContextualActionModeOverflowMenu();
onView(withText(R.string.paste)).perform(click());
onView(withText(R.string.heads_action_menu_item_paste_under)).perform(click());
searchForText("t.tag3");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
onListItem(0).onChildView(withId(R.id.item_head_title))
.check(matches(allOf(withText("Note C tag3 • tag1 tag2"), isDisplayed())));
onListItem(1).onChildView(withId(R.id.item_head_title))
.check(matches(allOf(withText("Note D tag3 • tag1 tag2"), isDisplayed())));
}
@Test
public void testSearchOrderScheduled() {
shelfTestUtils.setupBook("notebook-1",
"* Note A\n" +
"SCHEDULED: <2014-02-01>\n" +
"** Note B\n" +
"SCHEDULED: <2014-01-01>\n" +
"*** Note C\n" +
"*** Note D\n" +
"");
activityRule.launchActivity(null);
onView(allOf(withText("notebook-1"), isDisplayed())).perform(click());
searchForText("note o.scheduled");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onListItem(0).onChildView(withId(R.id.item_head_title)).check(matches(withText("Note B")));
onListItem(1).onChildView(withId(R.id.item_head_title)).check(matches(withText("Note A")));
}
@Test
public void testNotebookNameInListAfterRename() {
defaultSetUp();
searchForText("note");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onListItem(0).onChildView(withId(R.id.item_head_book_name_text)).check(matches(withText("book-one")));
onView(withId(R.id.drawer_layout)).perform(open());
onView(withText(R.string.notebooks)).perform(click());
onListItem(0).perform(longClick());
onView(withText(R.string.books_context_menu_item_rename)).perform(click());
onView(withId(R.id.name)).perform(replaceText("renamed book-one"), closeSoftKeyboardWithDelay());
onView(withText(R.string.rename)).perform(click());
/* The other book is now first. Rename it too to keep the order of notes the same. */
onListItem(0).perform(longClick());
onView(withText(R.string.books_context_menu_item_rename)).perform(click());
onView(withId(R.id.name)).perform(replaceText("renamed book-two"), closeSoftKeyboardWithDelay());
onView(withText(R.string.rename)).perform(click());
pressBack();
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onListItem(0).onChildView(withId(R.id.item_head_book_name_text)).check(matches(withText("renamed book-one")));
}
@Test
public void testSearchForNonExistentTagShouldReturnAllNotes() {
shelfTestUtils.setupBook("notebook",
"* Note A :a:\n" +
"** Note B :b:\n" +
"*** Note C\n" +
"* Note D\n");
activityRule.launchActivity(null);
onView(allOf(withText("notebook"), isDisplayed())).perform(click());
searchForText(".t.c");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(4)));
}
@Test
public void testNotTagShouldReturnSomeNotes() {
shelfTestUtils.setupBook("notebook",
"* Note A :a:\n" +
"** Note B :b:\n" +
"*** Note C\n" +
"* Note D\n");
activityRule.launchActivity(null);
onView(allOf(withText("notebook"), isDisplayed())).perform(click());
searchForText(".t.b");
onView(withId(R.id.fragment_query_view_flipper)).check(matches(isDisplayed()));
onView(allOf(withId(android.R.id.list), isDisplayed())).check(matches(listViewItemCount(2)));
onListItem(0).onChildView(withId(R.id.item_head_title)).check(matches(allOf(withText("Note A a"), isDisplayed())));
onListItem(1).onChildView(withId(R.id.item_head_title)).check(matches(allOf(withText("Note D"), isDisplayed())));
}
}