[WebLayer] Change Tab#executeScript() to return String directly
Clients wish to be able to process the result in ways other than it becoming a JSONObject. For convenience, we leave the test method that wraps this public API returning a JSONObject; the wrapping of the String into a JSONObject now occurs in that test API rather than in the public API. Bug: 1284580 Change-Id: Idf4e8c3e8cfe624ab047cf018316168bf51bb5b9 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3370223 Reviewed-by: Scott Violet <sky@chromium.org> Commit-Queue: Colin Blundell <blundell@chromium.org> Cr-Commit-Position: refs/heads/main@{#956422}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
b12c10a7f6
commit
272cece5fe
weblayer
browser
android
javatests
src
org
chromium
public
java
org
chromium
weblayer
@ -14,7 +14,6 @@ import org.junit.runner.RunWith;
|
|||||||
|
|
||||||
import org.chromium.base.test.util.UrlUtils;
|
import org.chromium.base.test.util.UrlUtils;
|
||||||
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
||||||
import org.chromium.weblayer.Tab;
|
|
||||||
import org.chromium.weblayer.shell.InstrumentationActivity;
|
import org.chromium.weblayer.shell.InstrumentationActivity;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,7 +34,8 @@ public class ExecuteScriptTest {
|
|||||||
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
|
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
|
||||||
JSONObject result = mActivityTestRule.executeScriptSync(
|
JSONObject result = mActivityTestRule.executeScriptSync(
|
||||||
"document.body.innerHTML", true /* useSeparateIsolate */);
|
"document.body.innerHTML", true /* useSeparateIsolate */);
|
||||||
Assert.assertEquals(result.getString(Tab.SCRIPT_RESULT_KEY), "foo");
|
Assert.assertEquals(
|
||||||
|
result.getString(InstrumentationActivityTestRule.SCRIPT_RESULT_KEY), "foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -44,7 +44,7 @@ public class ExecuteScriptTest {
|
|||||||
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
|
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
|
||||||
JSONObject result =
|
JSONObject result =
|
||||||
mActivityTestRule.executeScriptSync("bar", true /* useSeparateIsolate */);
|
mActivityTestRule.executeScriptSync("bar", true /* useSeparateIsolate */);
|
||||||
Assert.assertTrue(result.isNull(Tab.SCRIPT_RESULT_KEY));
|
Assert.assertTrue(result.isNull(InstrumentationActivityTestRule.SCRIPT_RESULT_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -53,7 +53,7 @@ public class ExecuteScriptTest {
|
|||||||
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
|
InstrumentationActivity activity = mActivityTestRule.launchShellWithUrl(DATA_URL);
|
||||||
JSONObject result =
|
JSONObject result =
|
||||||
mActivityTestRule.executeScriptSync("bar", false /* useSeparateIsolate */);
|
mActivityTestRule.executeScriptSync("bar", false /* useSeparateIsolate */);
|
||||||
Assert.assertEquals(result.getInt(Tab.SCRIPT_RESULT_KEY), 10);
|
Assert.assertEquals(result.getInt(InstrumentationActivityTestRule.SCRIPT_RESULT_KEY), 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -63,7 +63,7 @@ public class ExecuteScriptTest {
|
|||||||
mActivityTestRule.executeScriptSync("var foo = 20;", true /* useSeparateIsolate */);
|
mActivityTestRule.executeScriptSync("var foo = 20;", true /* useSeparateIsolate */);
|
||||||
JSONObject result =
|
JSONObject result =
|
||||||
mActivityTestRule.executeScriptSync("foo", true /* useSeparateIsolate */);
|
mActivityTestRule.executeScriptSync("foo", true /* useSeparateIsolate */);
|
||||||
Assert.assertEquals(result.getInt(Tab.SCRIPT_RESULT_KEY), 20);
|
Assert.assertEquals(result.getInt(InstrumentationActivityTestRule.SCRIPT_RESULT_KEY), 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -76,7 +76,7 @@ public class ExecuteScriptTest {
|
|||||||
mActivityTestRule.navigateAndWait(newUrl);
|
mActivityTestRule.navigateAndWait(newUrl);
|
||||||
JSONObject result =
|
JSONObject result =
|
||||||
mActivityTestRule.executeScriptSync("foo", true /* useSeparateIsolate */);
|
mActivityTestRule.executeScriptSync("foo", true /* useSeparateIsolate */);
|
||||||
Assert.assertTrue(result.isNull(Tab.SCRIPT_RESULT_KEY));
|
Assert.assertTrue(result.isNull(InstrumentationActivityTestRule.SCRIPT_RESULT_KEY));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -37,7 +37,6 @@ import org.chromium.base.test.util.MinAndroidSdkLevel;
|
|||||||
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
import org.chromium.content_public.browser.test.util.TestThreadUtils;
|
||||||
import org.chromium.net.test.util.TestWebServer;
|
import org.chromium.net.test.util.TestWebServer;
|
||||||
import org.chromium.weblayer.Browser;
|
import org.chromium.weblayer.Browser;
|
||||||
import org.chromium.weblayer.Tab;
|
|
||||||
import org.chromium.weblayer.TestWebLayer;
|
import org.chromium.weblayer.TestWebLayer;
|
||||||
import org.chromium.weblayer.shell.InstrumentationActivity;
|
import org.chromium.weblayer.shell.InstrumentationActivity;
|
||||||
|
|
||||||
@ -242,8 +241,9 @@ public final class GeolocationTest {
|
|||||||
false);
|
false);
|
||||||
CriteriaHelper.pollInstrumentationThread(() -> {
|
CriteriaHelper.pollInstrumentationThread(() -> {
|
||||||
try {
|
try {
|
||||||
String result = mActivityTestRule.executeScriptSync("queryResult || ''", false)
|
String result =
|
||||||
.getString(Tab.SCRIPT_RESULT_KEY);
|
mActivityTestRule.executeScriptSync("queryResult || ''", false)
|
||||||
|
.getString(InstrumentationActivityTestRule.SCRIPT_RESULT_KEY);
|
||||||
Criteria.checkThat(result, Matchers.not(""));
|
Criteria.checkThat(result, Matchers.not(""));
|
||||||
} catch (JSONException ex) {
|
} catch (JSONException ex) {
|
||||||
throw new CriteriaNotSatisfiedException(ex);
|
throw new CriteriaNotSatisfiedException(ex);
|
||||||
@ -251,7 +251,7 @@ public final class GeolocationTest {
|
|||||||
});
|
});
|
||||||
Assert.assertEquals("prompt",
|
Assert.assertEquals("prompt",
|
||||||
mActivityTestRule.executeScriptSync("queryResult", false)
|
mActivityTestRule.executeScriptSync("queryResult", false)
|
||||||
.getString(Tab.SCRIPT_RESULT_KEY));
|
.getString(InstrumentationActivityTestRule.SCRIPT_RESULT_KEY));
|
||||||
CriteriaHelper.pollInstrumentationThread(
|
CriteriaHelper.pollInstrumentationThread(
|
||||||
() -> { return mTestWebLayer.isPermissionDialogShown(); });
|
() -> { return mTestWebLayer.isPermissionDialogShown(); });
|
||||||
}
|
}
|
||||||
@ -277,7 +277,7 @@ public final class GeolocationTest {
|
|||||||
int result = -1;
|
int result = -1;
|
||||||
try {
|
try {
|
||||||
result = mActivityTestRule.executeScriptSync(variableName, false)
|
result = mActivityTestRule.executeScriptSync(variableName, false)
|
||||||
.getInt(Tab.SCRIPT_RESULT_KEY);
|
.getInt(InstrumentationActivityTestRule.SCRIPT_RESULT_KEY);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Assert.fail("Unable to get " + variableName);
|
Assert.fail("Unable to get " + variableName);
|
||||||
}
|
}
|
||||||
|
@ -43,17 +43,20 @@ import java.util.concurrent.TimeoutException;
|
|||||||
*/
|
*/
|
||||||
public class InstrumentationActivityTestRule
|
public class InstrumentationActivityTestRule
|
||||||
extends WebLayerActivityTestRule<InstrumentationActivity> {
|
extends WebLayerActivityTestRule<InstrumentationActivity> {
|
||||||
|
/** The top level key of the JSON object returned by executeScriptSync(). */
|
||||||
|
public static final String SCRIPT_RESULT_KEY = "result";
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
private EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
|
private EmbeddedTestServerRule mTestServerRule = new EmbeddedTestServerRule();
|
||||||
|
|
||||||
private static final class JSONCallbackHelper extends CallbackHelper {
|
private static final class StringCallbackHelper extends CallbackHelper {
|
||||||
private JSONObject mResult;
|
private String mResult;
|
||||||
|
|
||||||
public JSONObject getResult() {
|
public String getResult() {
|
||||||
return mResult;
|
return mResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void notifyCalled(JSONObject result) {
|
public void notifyCalled(String result) {
|
||||||
mResult = result;
|
mResult = result;
|
||||||
notifyCalled();
|
notifyCalled();
|
||||||
}
|
}
|
||||||
@ -149,22 +152,31 @@ public class InstrumentationActivityTestRule
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the script passed in and waits for the result.
|
* Executes the script passed in and waits for the result. Wraps that result in a JSONObject for
|
||||||
|
* convenience of callers that want to process that result as a type other than String.
|
||||||
*/
|
*/
|
||||||
public JSONObject executeScriptSync(String script, boolean useSeparateIsolate, Tab tab) {
|
public JSONObject executeScriptSync(String script, boolean useSeparateIsolate, Tab tab) {
|
||||||
JSONCallbackHelper callbackHelper = new JSONCallbackHelper();
|
StringCallbackHelper callbackHelper = new StringCallbackHelper();
|
||||||
int count = callbackHelper.getCallCount();
|
int count = callbackHelper.getCallCount();
|
||||||
TestThreadUtils.runOnUiThreadBlocking(() -> {
|
TestThreadUtils.runOnUiThreadBlocking(() -> {
|
||||||
Tab scriptTab = tab == null ? getActivity().getBrowser().getActiveTab() : tab;
|
Tab scriptTab = tab == null ? getActivity().getBrowser().getActiveTab() : tab;
|
||||||
scriptTab.executeScript(script, useSeparateIsolate,
|
scriptTab.executeScript(script, useSeparateIsolate,
|
||||||
(JSONObject result) -> { callbackHelper.notifyCalled(result); });
|
(String result) -> { callbackHelper.notifyCalled(result); });
|
||||||
});
|
});
|
||||||
try {
|
try {
|
||||||
callbackHelper.waitForCallback(count);
|
callbackHelper.waitForCallback(count);
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
return callbackHelper.getResult();
|
JSONObject resultAsJSONObject;
|
||||||
|
try {
|
||||||
|
resultAsJSONObject = new JSONObject(
|
||||||
|
"{\"" + SCRIPT_RESULT_KEY + "\":" + callbackHelper.getResult() + "}");
|
||||||
|
} catch (JSONException e) {
|
||||||
|
// This should never happen since the result should be well formed.
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return resultAsJSONObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject executeScriptSync(String script, boolean useSeparateIsolate) {
|
public JSONObject executeScriptSync(String script, boolean useSeparateIsolate) {
|
||||||
@ -174,7 +186,7 @@ public class InstrumentationActivityTestRule
|
|||||||
public int executeScriptAndExtractInt(String script) {
|
public int executeScriptAndExtractInt(String script) {
|
||||||
try {
|
try {
|
||||||
return executeScriptSync(script, true /* useSeparateIsolate */)
|
return executeScriptSync(script, true /* useSeparateIsolate */)
|
||||||
.getInt(Tab.SCRIPT_RESULT_KEY);
|
.getInt(SCRIPT_RESULT_KEY);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -186,7 +198,7 @@ public class InstrumentationActivityTestRule
|
|||||||
|
|
||||||
public String executeScriptAndExtractString(String script, boolean useSeparateIsolate) {
|
public String executeScriptAndExtractString(String script, boolean useSeparateIsolate) {
|
||||||
try {
|
try {
|
||||||
return executeScriptSync(script, useSeparateIsolate).getString(Tab.SCRIPT_RESULT_KEY);
|
return executeScriptSync(script, useSeparateIsolate).getString(SCRIPT_RESULT_KEY);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -198,7 +210,7 @@ public class InstrumentationActivityTestRule
|
|||||||
|
|
||||||
public boolean executeScriptAndExtractBoolean(String script, boolean useSeparateIsolate) {
|
public boolean executeScriptAndExtractBoolean(String script, boolean useSeparateIsolate) {
|
||||||
try {
|
try {
|
||||||
return executeScriptSync(script, useSeparateIsolate).getBoolean(Tab.SCRIPT_RESULT_KEY);
|
return executeScriptSync(script, useSeparateIsolate).getBoolean(SCRIPT_RESULT_KEY);
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,6 @@ import android.webkit.ValueCallback;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import org.chromium.weblayer_private.interfaces.APICallException;
|
import org.chromium.weblayer_private.interfaces.APICallException;
|
||||||
import org.chromium.weblayer_private.interfaces.IClientNavigation;
|
import org.chromium.weblayer_private.interfaces.IClientNavigation;
|
||||||
import org.chromium.weblayer_private.interfaces.IContextMenuParams;
|
import org.chromium.weblayer_private.interfaces.IContextMenuParams;
|
||||||
@ -42,9 +39,6 @@ import java.util.Set;
|
|||||||
* configuring state of the tab, such as delegates and callbacks.
|
* configuring state of the tab, such as delegates and callbacks.
|
||||||
*/
|
*/
|
||||||
public class Tab {
|
public class Tab {
|
||||||
/** The top level key of the JSON object returned by executeScript(). */
|
|
||||||
public static final String SCRIPT_RESULT_KEY = "result";
|
|
||||||
|
|
||||||
// Maps from id (as returned from ITab.getId()) to Tab.
|
// Maps from id (as returned from ITab.getId()) to Tab.
|
||||||
private static final Map<Integer, Tab> sTabMap = new HashMap<Integer, Tab>();
|
private static final Map<Integer, Tab> sTabMap = new HashMap<Integer, Tab>();
|
||||||
|
|
||||||
@ -233,9 +227,7 @@ public class Tab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the script, and returns the result as a JSON object to the callback if provided. The
|
* Executes the script, and returns the result to the callback if provided.
|
||||||
* object passed to the callback will have a single key SCRIPT_RESULT_KEY which will hold the
|
|
||||||
* result of running the script.
|
|
||||||
* @param useSeparateIsolate If true, runs the script in a separate v8 Isolate. This uses more
|
* @param useSeparateIsolate If true, runs the script in a separate v8 Isolate. This uses more
|
||||||
* memory, but separates the injected scrips from scripts in the page. This prevents any
|
* memory, but separates the injected scrips from scripts in the page. This prevents any
|
||||||
* potentially malicious interaction between first-party scripts in the page, and injected
|
* potentially malicious interaction between first-party scripts in the page, and injected
|
||||||
@ -243,24 +235,11 @@ public class Tab {
|
|||||||
* or you need to interact with first-party scripts.
|
* or you need to interact with first-party scripts.
|
||||||
*/
|
*/
|
||||||
public void executeScript(@NonNull String script, boolean useSeparateIsolate,
|
public void executeScript(@NonNull String script, boolean useSeparateIsolate,
|
||||||
@Nullable ValueCallback<JSONObject> callback) {
|
@Nullable ValueCallback<String> callback) {
|
||||||
ThreadCheck.ensureOnUiThread();
|
ThreadCheck.ensureOnUiThread();
|
||||||
throwIfDestroyed();
|
throwIfDestroyed();
|
||||||
try {
|
try {
|
||||||
ValueCallback<String> stringCallback = (String result) -> {
|
mImpl.executeScript(script, useSeparateIsolate, ObjectWrapper.wrap(callback));
|
||||||
if (callback == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
callback.onReceiveValue(
|
|
||||||
new JSONObject("{\"" + SCRIPT_RESULT_KEY + "\":" + result + "}"));
|
|
||||||
} catch (JSONException e) {
|
|
||||||
// This should never happen since the result should be well formed.
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
mImpl.executeScript(script, useSeparateIsolate, ObjectWrapper.wrap(stringCallback));
|
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw new APICallException(e);
|
throw new APICallException(e);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user