Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable custom list child interactions #314

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ clearText(R.id.edittext)
```java
clickListItem(R.id.list, 4);
clickListItemChild(R.id.list, 3, R.id.row_button);
doOnListItemChild(R.id.list, 5, R.id.edittext, replaceText("Yet another great text"));
scrollListToPosition(R.id.list, 4);

clickSpinnerItem(R.id.spinner, 1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.FailureHandler
import androidx.test.espresso.NoMatchingViewException
import androidx.test.espresso.ViewAction
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.scrollTo
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition
Expand All @@ -23,8 +24,8 @@ import androidx.test.espresso.matcher.ViewMatchers.withId
import com.adevinta.android.barista.internal.failurehandler.SpyFailureHandler
import com.adevinta.android.barista.internal.failurehandler.description
import com.adevinta.android.barista.internal.failurehandler.withFailureHandler
import com.adevinta.android.barista.internal.viewaction.ClickChildAction.clickChildWithId
import com.adevinta.android.barista.internal.viewaction.PerformClickAction.clickUsingPerformClick
import com.adevinta.android.barista.internal.viewaction.ChildActions.onChildWithId
import org.hamcrest.CoreMatchers.allOf
import org.hamcrest.CoreMatchers.anyOf
import org.hamcrest.CoreMatchers.anything
Expand Down Expand Up @@ -53,9 +54,15 @@ object BaristaListInteractions {
@JvmStatic
@JvmOverloads
fun clickListItemChild(@IdRes id: Int? = null, position: Int, @IdRes childId: Int) {
doOnListItemChild(id, position, childId, click())
}

@JvmStatic
@JvmOverloads
fun doOnListItemChild(@IdRes id: Int? = null, position: Int, @IdRes childId: Int, viewAction: ViewAction) {
performMagicAction(id, position,
recyclerAction = actionOnItemAtPosition<ViewHolder>(position, clickChildWithId(childId)),
listViewAction = clickChildWithId(childId)
recyclerAction = actionOnItemAtPosition<ViewHolder>(position, onChildWithId(childId, viewAction)),
listViewAction = onChildWithId(childId, viewAction)
Comment on lines +62 to +65

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for adding this functionality. As a user, what if I wanted to identify the child view using a ViewMatcher? Perhaps this function should use onChildWithMatcher instead of onChildWithId for greater flexibility from an end-user perspective?

)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.adevinta.android.barista.internal.viewaction

import android.view.View
import androidx.annotation.IdRes
import androidx.test.espresso.PerformException
import androidx.test.espresso.UiController
import androidx.test.espresso.ViewAction
import androidx.test.espresso.matcher.ViewMatchers.hasDescendant
import androidx.test.espresso.matcher.ViewMatchers.isDisplayed
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.util.HumanReadables
import com.adevinta.android.barista.internal.failurehandler.description
import com.adevinta.android.barista.internal.util.ViewTreeAnalyzer
import org.hamcrest.Matcher
import org.hamcrest.Matchers.allOf

object ChildActions {

@JvmStatic
fun onChildWithId(@IdRes childId: Int, viewAction: ViewAction): ViewAction {
return onChildWithMatcher(withId(childId), viewAction)
}

@JvmStatic
fun onChildWithMatcher(childMatcher: Matcher<View>, viewAction: ViewAction): ViewAction {
return object : ViewAction {
override fun getConstraints(): Matcher<View> {
return allOf<View>(isDisplayed(), hasDescendant(childMatcher))
}

override fun getDescription(): String {
return "Perform " + viewAction.description + " on a child view " + childMatcher.description()
}

override fun perform(uiController: UiController, view: View) {
var foundTarget = false

for (child in ViewTreeAnalyzer.getAllChildren(view)) {
if (childMatcher.matches(child)) {
foundTarget = true
viewAction.perform(uiController, child)
break
}
}

if (!foundTarget) {
throw PerformException.Builder()
.withActionDescription(description)
.withViewDescription(HumanReadables.describe(view))
.withCause(IllegalArgumentException("Didn't find any view " + childMatcher.description()))
.build()
}
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,18 @@
import org.junit.runner.RunWith;

import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.action.ViewActions.replaceText;
import static androidx.test.espresso.assertion.ViewAssertions.matches;
import static androidx.test.espresso.matcher.ViewMatchers.withId;
import static androidx.test.espresso.matcher.ViewMatchers.withText;
import static com.adevinta.android.barista.interaction.BaristaKeyboardInteractions.closeKeyboard;
import static com.adevinta.android.barista.interaction.BaristaListInteractions.clickListItemChild;
import static com.adevinta.android.barista.sample.ListsActivity.IntentBuilder;
import static com.adevinta.android.barista.interaction.BaristaListInteractions.doOnListItemChild;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;

@RunWith(AndroidJUnit4.class)
public class ListsChildClickTest {
public class ListsChildTest {

@Rule
public ActivityTestRule<ListsActivity> activity = new ActivityTestRule<>(ListsActivity.class, true, false);
Expand All @@ -36,7 +38,7 @@ public void clickRecyclerItemChild() {

clickListItemChild(20, R.id.yes);

assertResult("yes");
assertClickResult("yes");
spyFailureHandlerRule.assertNoEspressoFailures();
}

Expand All @@ -48,7 +50,7 @@ public void clickListViewItemChild() {

clickListItemChild(20, R.id.yes);

assertResult("yes");
assertClickResult("yes");
spyFailureHandlerRule.assertNoEspressoFailures();
}

Expand All @@ -60,7 +62,7 @@ public void clickGridViewItemChild() {

clickListItemChild(20, R.id.yes);

assertResult("yes");
assertClickResult("yes");
spyFailureHandlerRule.assertNoEspressoFailures();
}

Expand All @@ -72,7 +74,7 @@ public void clickMultipleRecyclerItemChild_byId() {

clickListItemChild(R.id.recycler, 20, R.id.yes);

assertResult("yes");
assertClickResult("yes");
spyFailureHandlerRule.assertNoEspressoFailures();
}

Expand All @@ -84,7 +86,7 @@ public void clickMultipleListViewItemChild_byId() {

clickListItemChild(R.id.listview, 20, R.id.yes);

assertResult("yes");
assertClickResult("yes");
spyFailureHandlerRule.assertNoEspressoFailures();
}

Expand All @@ -96,7 +98,46 @@ public void clickMultipleGridViewItemChild_byId() {

clickListItemChild(R.id.gridview, 20, R.id.yes);

assertResult("yes");
assertClickResult("yes");
spyFailureHandlerRule.assertNoEspressoFailures();
}

@Test
public void actionMultipleRecyclerItemChild_byId() {
openActivity(ListsActivity.buildIntent()
.withRecyclers(R.id.recycler, R.id.recycler2)
);

String text = "It works";
doOnListItemChild(R.id.recycler, 20, R.id.edittext, replaceText(text));

assertPerformActionResult(text);
spyFailureHandlerRule.assertNoEspressoFailures();
}

@Test
public void actionMultipleListViewItemChild_byId() {
openActivity(ListsActivity.buildIntent()
.withComplexLists(R.id.listview, R.id.listview2)
);

String text = "It works";
doOnListItemChild(R.id.listview, 20, R.id.edittext, replaceText(text));

assertPerformActionResult(text);
spyFailureHandlerRule.assertNoEspressoFailures();
}

@Test
public void actionMultipleGridViewItemChild_byId() {
openActivity(ListsActivity.buildIntent()
.withComplexGrids(R.id.gridview, R.id.gridview2)
);

String text = "It works";
doOnListItemChild(R.id.gridview, 20, R.id.edittext, replaceText(text));

assertPerformActionResult(text);
spyFailureHandlerRule.assertNoEspressoFailures();
}

Expand All @@ -110,7 +151,8 @@ public void fails_whenRecyclerChildNotExist() {

spyFailureHandlerRule.assertEspressoFailures(1);
assertThat(thrown).isInstanceOf(BaristaException.class)
.hasMessageContaining("Could not perform action (actionOnItemAtPosition performing ViewAction: Click on a child view ")
.hasMessageContaining(
"Could not perform action (actionOnItemAtPosition performing ViewAction: Perform single click on a child view with id: ")
.hasMessageContaining("on item at position: 20) on RecyclerView")
.hasCauseInstanceOf(PerformException.class)
.hasStackTraceContaining("Didn't find any view with id");
Expand All @@ -126,16 +168,21 @@ public void fails_whenListViewChildNotExist() {

spyFailureHandlerRule.assertEspressoFailures(1);
assertThat(thrown).isInstanceOf(BaristaException.class)
.hasMessageContaining("Could not perform action (Click on a child view ")
.hasMessageContaining("Could not perform action (Perform single click on a child view with id: ")
.hasMessageContaining("on ListView")
.hasCauseInstanceOf(PerformException.class);
}

private void openActivity(IntentBuilder intentBuilder) {
private void openActivity(ListsActivity.IntentBuilder intentBuilder) {
activity.launchActivity(intentBuilder.build(ApplicationProvider.getApplicationContext()));
closeKeyboard();
}

private void assertResult(String text) {
private void assertClickResult(String text) {
onView(withId(R.id.clicked_text_result)).check(matches(withText(text)));
}

private void assertPerformActionResult(String text) {
onView(withId(R.id.typed_text_result)).check(matches(withText(text)));
}
}
Loading