1 /*
2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.example.androidx.webkit;
18 
19 import static androidx.test.espresso.Espresso.onData;
20 import static androidx.test.espresso.Espresso.onView;
21 import static androidx.test.espresso.action.ViewActions.click;
22 import static androidx.test.espresso.assertion.ViewAssertions.matches;
23 import static androidx.test.espresso.matcher.ViewMatchers.withId;
24 import static androidx.test.espresso.matcher.ViewMatchers.withText;
25 import static androidx.test.espresso.web.assertion.WebViewAssertions.webMatches;
26 import static androidx.test.espresso.web.sugar.Web.onWebView;
27 import static androidx.test.espresso.web.webdriver.DriverAtoms.findElement;
28 import static androidx.test.espresso.web.webdriver.DriverAtoms.getText;
29 
30 import static org.hamcrest.Matchers.containsString;
31 import static org.hamcrest.Matchers.equalTo;
32 import static org.hamcrest.Matchers.hasToString;
33 
34 import android.content.Context;
35 
36 import androidx.annotation.IdRes;
37 import androidx.annotation.StringRes;
38 import androidx.test.espresso.web.webdriver.Locator;
39 import androidx.test.platform.app.InstrumentationRegistry;
40 import androidx.webkit.WebViewFeature;
41 
42 import org.jspecify.annotations.NonNull;
43 import org.junit.Assume;
44 
45 /**
46  * Helper methods for testing.
47  */
48 public final class WebkitTestHelpers {
49 
50     /**
51      * Click on a MenuListView entry.
52      *
53      * @param resourceId string id of menu item
54      */
clickMenuListItemWithString(@tringRes int resourceId)55     public static void clickMenuListItemWithString(@StringRes int resourceId) {
56         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
57         onData(hasToString(equalTo(context.getString(resourceId)))).perform(click());
58     }
59 
60     /**
61      * Click on a view by id.
62      *
63      * @param viewId view to be clicked on
64      */
clickViewWithId(@dRes int viewId)65     public static void clickViewWithId(@IdRes int viewId) {
66         onView(withId(viewId)).perform(click());
67     }
68 
69     /**
70      * Asserts that a view displays the expected text.
71      *
72      * @param viewId the view to be checked
73      * @param stringResourceId the text's resource id
74      * @param formatArgs optional format args used by the text string
75      */
assertViewHasText(@dRes int viewId, @StringRes int stringResourceId, Object... formatArgs)76     public static void assertViewHasText(@IdRes int viewId, @StringRes int stringResourceId,
77             Object... formatArgs) {
78         Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
79         onView(withId(viewId))
80                 .check(matches(withText(context.getString(stringResourceId, formatArgs))));
81     }
82 
83     /**
84      * Assert that an HTML element in the given WebView object contains the given text.
85      *
86      * @param webViewId ID of the WebView object that contains the HTML object.
87      * @param tagId the ID attribute of the HTML tag.
88      * @param text the expected text inside the HTML element.
89      */
assertHtmlElementContainsText(@dRes int webViewId, @NonNull String tagId, @NonNull String text)90     public static void assertHtmlElementContainsText(@IdRes int webViewId,
91             @NonNull String tagId, @NonNull String text) {
92         onWebView(withId(webViewId))
93                 .withElement(findElement(Locator.ID, tagId))
94                 .check(webMatches(getText(),
95                         containsString(text)));
96     }
97 
98     /**
99      * Throws {@link org.junit.AssumptionViolatedException} if the device does not support the
100      * particular feature, otherwise returns.
101      *
102      * <p>
103      * This provides a more descriptive message than a bare {@code assumeTrue} call.
104      *
105      * @param featureName the feature to be checked
106      */
assumeFeature(@ebViewFeature.WebViewSupportFeature String featureName)107     public static void assumeFeature(@WebViewFeature.WebViewSupportFeature String featureName) {
108         final String msg = "This device does not have the feature '" +  featureName + "'";
109         final boolean hasFeature = WebViewFeature.isFeatureSupported(featureName);
110         Assume.assumeTrue(msg, hasFeature);
111     }
112 
113     /**
114      * Throws {@link org.junit.AssumptionViolatedException} if the device supports the
115      * particular feature, otherwise returns.
116      *
117      * <p>
118      * This provides a more descriptive message than a bare {@code assumeFalse} call.
119      *
120      * @param featureName the feature to be checked
121      */
assumeFeatureNotAvailable( @ebViewFeature.WebViewSupportFeature String featureName)122     public static void assumeFeatureNotAvailable(
123             @WebViewFeature.WebViewSupportFeature String featureName) {
124         final String msg = "This device has the feature '" +  featureName + "'";
125         final boolean hasFeature = WebViewFeature.isFeatureSupported(featureName);
126         Assume.assumeFalse(msg, hasFeature);
127     }
128 
129     /**
130      * Throws {@link org.junit.AssumptionViolatedException} if the device does not support the
131      * particular startup feature, otherwise returns.
132      *
133      * <p>
134      * This provides a more descriptive message than a bare {@code assumeTrue} call.
135      *
136      * @param featureName the feature to be checked
137      */
assumeStartupFeature( @ebViewFeature.WebViewStartupFeature String featureName, Context context)138     public static void assumeStartupFeature(
139             @WebViewFeature.WebViewStartupFeature String featureName,
140             Context context) {
141         final String msg = "This device does not have the feature '" +  featureName + "'";
142         final boolean hasFeature = WebViewFeature.isStartupFeatureSupported(context, featureName);
143         Assume.assumeTrue(msg, hasFeature);
144     }
145 
146     /**
147      * Throws {@link org.junit.AssumptionViolatedException} if the device supports the
148      * particular startup feature, otherwise returns.
149      *
150      * <p>
151      * This provides a more descriptive message than a bare {@code assumeFalse} call.
152      *
153      * @param featureName the feature to be checked
154      */
assumeStartupFeatureNotAvailable( @ebViewFeature.WebViewStartupFeature String featureName, Context context)155     public static void assumeStartupFeatureNotAvailable(
156             @WebViewFeature.WebViewStartupFeature String featureName, Context context) {
157         final String msg = "This device has the feature '" +  featureName + "'";
158         final boolean hasFeature = WebViewFeature.isStartupFeatureSupported(context, featureName);
159         Assume.assumeFalse(msg, hasFeature);
160     }
161 
162     /**
163      * Javascript has to be enabled for espresso tests to work.
164      *
165      * @param webViewIds WebView IDs for which to enable JavaScript
166      */
enableJavaScript(@dRes int... webViewIds)167     public static void enableJavaScript(@IdRes int... webViewIds) {
168         for (int webViewId : webViewIds) {
169             onWebView(withId(webViewId)).forceJavascriptEnabled();
170         }
171     }
172 
173     // Do not instantiate this class.
WebkitTestHelpers()174     private WebkitTestHelpers() {}
175 }
176