I am trying to get an instance of a WebView, so that I can call evaluateJavascript() on it.
I wrote a custom matcher and then tried to assign the WebView to a static variable as below:
public static WebView view1;
public static Matcher<View> isJavascriptEnabled1() {
return new BoundedMatcher<View, WebView>(WebView.class) {
@Override
public void describeTo(Description description) {
description.appendText("WebView with JS enabled");
}
@Override
public boolean matchesSafely(WebView webView) {
view1 =webView;
return webView.getSettings().getJavaScriptEnabled();
}
};
}
And in my test class I call:
CustomMatcher.isJavascriptEnabled1();
CustomMatcher.view1.evaluateJavascript("$('.status dl dd').get(0).innerText.replace('pts.', '').replace(',', '').trim()\"]",new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints asd
}
});
I get the error: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.webkit.WebView.evaluateJavascript(java.lang.String, android.webkit.ValueCallback)' on a null object reference
You are not using the Matcher to match a view. It's not working because calling isJavascriptEnabled1() just creates a new instance of your custom Matcher. But e.g. matchesSafely() is never executed and thats why CustomMatcher.view1 is null.
To make your code work you have to use Espresso.onView() together with your Matcher:
// Use onView and the matcher to find a web view with enabled java script
Espresso.onView(CustomMatcher.isJavascriptEnabled1());
// Now CustomMatcher.view1 should not be null (if there is a web view)
CustomMatcher.view1.evaluateJavascript("$('.status dl dd').get(0).innerText.replace('pts.', '').replace(',', '').trim()\"]",new ValueCallback<String>() {
@Override
public void onReceiveValue(String s) {
Log.d("LogName", s); // Prints asd
}
});
But thats still not correct. The method evaluateJavascript() is asynchronous and Espresso will not wait for the callback (onReceiveValue()) to be called. So the test will most likely finish before onReceive() is called.
There is also Espresso Web for testing WebViews. Depending on your goal you might find it useful. Espresso Web executes java script under the hood, too.
Without using Espresso Web I would suggest to write a custom ViewAction, that will be performed on the matched WebView. This action can use the WebView to evaluate java script:
/**
* {@link ViewAction} that evaluates javascript in a {@link WebView}.
*/
public class EvaluateJsAction implements ViewAction, ValueCallback<String> {
private static final long TIME_OUT = 5000;
private final String mJsString;
private final AtomicBoolean mEvaluateFinished = new AtomicBoolean(false);
public EvaluateJsAction(final String javaScriptString) {
mJsString = javaScriptString;
}
@Override
public Matcher<View> getConstraints() {
return isAssignableFrom(WebView.class);
}
@Override
public String getDescription() {
return "evaluate '" + mJsString + "' on webview";
}
@Override
public void perform(UiController uiController, View view) {
uiController.loopMainThreadUntilIdle();
final WebView webView = (WebView) view;
webView.evaluateJavascript(mJsString, this);
final long timeOut = System.currentTimeMillis() + TIME_OUT;
while (!mEvaluateFinished.get()) {
if (timeOut < System.currentTimeMillis()) {
throw new PerformException.Builder()
.withActionDescription(this.getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(new RuntimeException(String.format(Locale.US,
"Evaluating java script did not finish after %d ms of waiting.", TIME_OUT)))
.build();
}
uiController.loopMainThreadForAtLeast(50);
}
}
@Override
public void onReceiveValue(String value) {
mEvaluateFinished.set(true);
}
}
Then use this action:
onView(withJavaScriptEnabled()).perform(new EvaluateJsAction(theJavaScriptString));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With