summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHenrique Nakashima <hnakashima@chromium.org>2024-04-25 10:40:49 -0700
committerchromeos-ci-prod <chromeos-ci-prod@chromeos-bot.iam.gserviceaccount.com>2024-04-26 04:21:57 -0700
commite937a17e1bbbed37f248c559d39009de3ddaba36 (patch)
treece089fa28fdf8197e985f2e6f5f3caa9233f932a
parent11239a66cd795deab323bd0c4fc7c1580f37037e (diff)
downloadlibchrome-e937a17e1bbbed37f248c559d39009de3ddaba36.tar.gz
[Android] ViewElements are expected to be enabled by default
They can also be expected to be displayed but disabled. Introduce ViewElement.Options and ExistsCondition.Options to configure this expectation. Move custom ViewElement ids into Options to keep the API clean. Bug: 328275348,336846333 Change-Id: I1082084c51038b17dc6a0d4791dce3729643fc9f Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5485087 Commit-Queue: Henrique Nakashima <hnakashima@chromium.org> Reviewed-by: Andrew Grieve <agrieve@chromium.org> Cr-Commit-Position: refs/heads/main@{#1292545} CrOS-Libchrome-Original-Commit: 91a8bef74b609bc551c74f3ec3114517f39c620c
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/transit/Elements.java4
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/transit/ViewConditions.java50
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java95
-rw-r--r--base/test/android/javatests/src/org/chromium/base/test/transit/ViewElementInState.java11
4 files changed, 123 insertions, 37 deletions
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/Elements.java b/base/test/android/javatests/src/org/chromium/base/test/transit/Elements.java
index 72249ca960..3286462525 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/transit/Elements.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/transit/Elements.java
@@ -18,10 +18,6 @@ import java.util.List;
* </pre>
*/
public class Elements {
-
- /** If passed as |id|, the description is considered the id. */
- public static final String DESCRIPTION_AS_ID = "__DESCRIPTION_AS_ID";
-
static final Elements EMPTY = new Elements();
private ArrayList<ElementInState> mElementsInState = new ArrayList<>();
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewConditions.java b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewConditions.java
index ac9f53c1c6..2cf5a801d3 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewConditions.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewConditions.java
@@ -32,8 +32,8 @@ import java.util.regex.Pattern;
public class ViewConditions {
/** Fulfilled when a single matching View exists and is displayed. */
public static class DisplayedCondition extends ExistsCondition {
- public DisplayedCondition(Matcher<View> matcher) {
- super(allOf(matcher, isDisplayed()));
+ public DisplayedCondition(Matcher<View> matcher, ExistsCondition.Options options) {
+ super(allOf(matcher, isDisplayed()), options);
}
}
@@ -46,9 +46,10 @@ public class ViewConditions {
private final DisplayedCondition mDisplayedCondition;
private final Condition mGate;
- public GatedDisplayedCondition(Matcher<View> matcher, Condition gate) {
+ public GatedDisplayedCondition(
+ Matcher<View> matcher, Condition gate, ExistsCondition.Options options) {
super();
- mDisplayedCondition = new DisplayedCondition(matcher);
+ mDisplayedCondition = new DisplayedCondition(matcher, options);
mGate = gate;
}
@@ -75,11 +76,13 @@ public class ViewConditions {
/** Fulfilled when a single matching View exists. */
public static class ExistsCondition extends InstrumentationThreadCondition {
private final Matcher<View> mMatcher;
+ private final Options mOptions;
private View mViewMatched;
- public ExistsCondition(Matcher<View> matcher) {
+ public ExistsCondition(Matcher<View> matcher, Options options) {
super();
- this.mMatcher = matcher;
+ mMatcher = matcher;
+ mOptions = options;
}
@Override
@@ -115,6 +118,15 @@ public class ViewConditions {
mViewMatched = view;
}
});
+ if (mOptions.mExpectEnabled) {
+ if (!mViewMatched.isEnabled()) {
+ return notFulfilled("View displayed but disabled");
+ }
+ } else { // Expected a displayed but disabled View.
+ if (mViewMatched.isEnabled()) {
+ return notFulfilled("View displayed but enabled");
+ }
+ }
return fulfilled(message[0]);
} catch (NoMatchingViewException
| NoMatchingRootException
@@ -129,6 +141,32 @@ public class ViewConditions {
return notFulfilled(e.getClass().getSimpleName());
}
}
+
+ /**
+ * @return an Options builder to customize the ViewCondition.
+ */
+ public static Options.Builder newOptions() {
+ return new Options().new Builder();
+ }
+
+ /** Extra options for declaring ExistsCondition. */
+ public static class Options {
+ boolean mExpectEnabled = true;
+
+ private Options() {}
+
+ public class Builder {
+ public Options build() {
+ return Options.this;
+ }
+
+ /** Whether the view is expected to be enabled or disabled. */
+ public Builder withExpectEnabled(boolean state) {
+ mExpectEnabled = state;
+ return this;
+ }
+ }
+ }
}
/** Fulfilled when no matching Views exist and are displayed. */
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java
index 6a44672063..444376877c 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElement.java
@@ -11,7 +11,6 @@ import static org.hamcrest.Matchers.allOf;
import android.view.View;
import androidx.annotation.IntDef;
-import androidx.annotation.Nullable;
import androidx.test.espresso.Espresso;
import androidx.test.espresso.ViewAction;
import androidx.test.espresso.ViewInteraction;
@@ -35,6 +34,7 @@ public class ViewElement {
private final Matcher<View> mViewMatcher;
private final @Scope int mScope;
private final String mId;
+ private final Options mOptions;
/** Alias for {@link #sharedViewElement(Matcher)} as the default way to declare ViewElements. */
public static ViewElement viewElement(Matcher<View> viewMatcher) {
@@ -42,11 +42,12 @@ public class ViewElement {
}
/**
- * Version of {@link #sharedViewElement(Matcher, String)} using the Matcher |description| as
- * |id|.
+ * Version of {@link #sharedViewElement(Matcher, Options)} using default Options.
+ *
+ * <p>This is a good default method to the declare ViewElements; when in doubt, use this.
*/
public static ViewElement sharedViewElement(Matcher<View> viewMatcher) {
- return new ViewElement(viewMatcher, Scope.SHARED, /* id= */ null);
+ return new ViewElement(viewMatcher, Scope.SHARED, Options.DEFAULT);
}
/**
@@ -57,19 +58,14 @@ public class ViewElement {
* <p>Shared ViewElements add an EXIT condition that no View is matched unless transitioning to
* a ConditionalState that declares a ViewElement with the same id (which usually means an equal
* Matcher<View>).
- *
- * <p>This is a good default method to the declare ViewElements; when in doubt, use this.
*/
- public static ViewElement sharedViewElement(Matcher<View> viewMatcher, String id) {
- return new ViewElement(viewMatcher, Scope.SHARED, id);
+ public static ViewElement sharedViewElement(Matcher<View> viewMatcher, Options options) {
+ return new ViewElement(viewMatcher, Scope.SHARED, options);
}
- /**
- * Version of {@link #scopedViewElement(Matcher, String)} using the Matcher |description| as
- * |id|.
- */
+ /** Version of {@link #scopedViewElement(Matcher, Options)} using default Options. */
public static ViewElement scopedViewElement(Matcher<View> viewMatcher) {
- return new ViewElement(viewMatcher, Scope.CONDITIONAL_STATE_SCOPED, /* id= */ null);
+ return new ViewElement(viewMatcher, Scope.CONDITIONAL_STATE_SCOPED, Options.DEFAULT);
}
/**
@@ -80,16 +76,13 @@ public class ViewElement {
* <p>ConditionalState-scoped ViewElements are the most restrictive; they generate an EXIT
* condition that no View is matched under any circumstances.
*/
- public static ViewElement scopedViewElement(Matcher<View> viewMatcher, String id) {
- return new ViewElement(viewMatcher, Scope.CONDITIONAL_STATE_SCOPED, id);
+ public static ViewElement scopedViewElement(Matcher<View> viewMatcher, Options options) {
+ return new ViewElement(viewMatcher, Scope.CONDITIONAL_STATE_SCOPED, options);
}
- /**
- * Version of {@link #unscopedViewElement(Matcher, String)} using the Matcher |description| as
- * |id|.
- */
+ /** Version of {@link #unscopedViewElement(Matcher, Options)} using default Options. */
public static ViewElement unscopedViewElement(Matcher<View> viewMatcher) {
- return new ViewElement(viewMatcher, Scope.UNSCOPED, /* id= */ null);
+ return new ViewElement(viewMatcher, Scope.UNSCOPED, Options.DEFAULT);
}
/**
@@ -100,16 +93,17 @@ public class ViewElement {
* <p>Unscoped ViewElements are the most permissive; they do not generate EXIT conditions,
* therefore they may or may not be gone.
*/
- public static ViewElement unscopedViewElement(Matcher<View> viewMatcher, String id) {
- return new ViewElement(viewMatcher, Scope.UNSCOPED, id);
+ public static ViewElement unscopedViewElement(Matcher<View> viewMatcher, Options options) {
+ return new ViewElement(viewMatcher, Scope.UNSCOPED, options);
}
- private ViewElement(Matcher<View> viewMatcher, @Scope int scope, @Nullable String id) {
+ private ViewElement(Matcher<View> viewMatcher, @Scope int scope, Options options) {
mViewMatcher = viewMatcher;
mScope = scope;
- if (id != null) {
- mId = id;
+ if (options.mElementId != null) {
+ // Use a custom id instead of the Matcher description.
+ mId = options.mElementId;
} else {
// Capture the description as soon as possible to compare ViewElements added to
// different
@@ -119,6 +113,8 @@ public class ViewElement {
// https://crbug.com/41494895#comment7.
mId = StringDescription.toString(mViewMatcher);
}
+
+ mOptions = options;
}
String getId() {
@@ -150,4 +146,53 @@ public class ViewElement {
public ViewInteraction perform(ViewAction action) {
return onView().perform(action);
}
+
+ /**
+ * @return the Options passed when declaring the ViewElement.
+ */
+ public Options getOptions() {
+ return mOptions;
+ }
+
+ /**
+ * @return an Options builder to customize the ViewElement further.
+ */
+ public static Options.Builder newOptions() {
+ return new Options().new Builder();
+ }
+
+ /** Extra options for declaring ViewElements. */
+ public static class Options {
+ static final Options DEFAULT = new Options();
+ protected boolean mExpectEnabled = true;
+ protected String mElementId;
+
+ protected Options() {}
+
+ public class Builder {
+ public Options build() {
+ return Options.this;
+ }
+
+ /** Use a custom Element id instead of the Matcher<View> description. */
+ public Builder elementId(String id) {
+ mElementId = id;
+ return this;
+ }
+
+ /**
+ * Expect the View to be disabled instead of enabled.
+ *
+ * <p>This is different than passing an isEnabled() Matcher.If the matcher was, for
+ * example |allOf(withId(ID), isEnabled())|, the exit condition would be considered
+ * fulfilled if the View became disabled. Meanwhile, using this option makes the exit
+ * condition only be considered fulfilled if no Views |withId(ID)|, enabled or not, were
+ * displayed.
+ */
+ public Builder expectDisabled() {
+ mExpectEnabled = false;
+ return this;
+ }
+ }
+ }
}
diff --git a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElementInState.java b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElementInState.java
index d1fe0fa8f9..5aa969303a 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElementInState.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/transit/ViewElementInState.java
@@ -11,6 +11,7 @@ import androidx.annotation.Nullable;
import org.hamcrest.Matcher;
import org.chromium.base.test.transit.ViewConditions.DisplayedCondition;
+import org.chromium.base.test.transit.ViewConditions.ExistsCondition;
import org.chromium.base.test.transit.ViewConditions.GatedDisplayedCondition;
import org.chromium.base.test.transit.ViewConditions.NotDisplayedAnymoreCondition;
import org.chromium.base.test.transit.ViewElement.Scope;
@@ -39,12 +40,18 @@ class ViewElementInState implements ElementInState {
mGate = gate;
Matcher<View> viewMatcher = mViewElement.getViewMatcher();
+ ExistsCondition.Options conditionOptions =
+ ExistsCondition.newOptions()
+ .withExpectEnabled(mViewElement.getOptions().mExpectEnabled)
+ .build();
if (mGate != null) {
GatedDisplayedCondition gatedDisplayedCondition =
- new GatedDisplayedCondition(mViewElement.getViewMatcher(), mGate);
+ new GatedDisplayedCondition(
+ mViewElement.getViewMatcher(), mGate, conditionOptions);
mEnterCondition = gatedDisplayedCondition;
} else {
- DisplayedCondition displayedCondition = new DisplayedCondition(viewMatcher);
+ DisplayedCondition displayedCondition =
+ new DisplayedCondition(viewMatcher, conditionOptions);
mEnterCondition = displayedCondition;
}