[go: nahoru, domu]

blob: 69b444559d935d5a49482f44ef1d47e450d009d6 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.android_webview.test;
import static org.chromium.android_webview.test.AwActivityTestRule.WAIT_TIMEOUT_MS;
import android.graphics.Color;
import android.util.Pair;
import android.webkit.JavascriptInterface;
import android.webkit.WebView.HitTestResult;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
import org.chromium.android_webview.AwContents;
import org.chromium.android_webview.common.AwSwitches;
import org.chromium.android_webview.test.util.AwTestTouchUtils;
import org.chromium.android_webview.test.util.CommonResources;
import org.chromium.android_webview.test.util.GraphicsTestUtils;
import org.chromium.android_webview.test.util.JavascriptEventObserver;
import org.chromium.base.test.util.CallbackHelper;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.DoNotBatch;
import org.chromium.base.test.util.Feature;
import org.chromium.net.test.util.TestWebServer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeoutException;
/** Test for creating fenced frames in Android WebView. */
@DoNotBatch(reason = "Test instrumentation only supports one hardware compositing view.")
@CommandLineFlags.Add(AwSwitches.WEBVIEW_FENCED_FRAMES)
@RunWith(Parameterized.class)
@UseParametersRunnerFactory(AwJUnit4ClassRunnerWithParameters.Factory.class)
public class FencedFrameTest extends AwParameterizedTest {
@Rule public AwActivityTestRule mActivityTestRule;
private TestAwContentsClient mContentsClient;
private AwTestContainerView mTestView;
private AwContents mAwContents;
private TestWebServer mWebServer;
public FencedFrameTest(AwSettingsMutation param) {
this.mActivityTestRule = new AwActivityTestRule(param.getMutation());
}
@Before
public void setUp() throws Exception {
mContentsClient = new TestAwContentsClient();
mTestView = mActivityTestRule.createAwTestContainerViewOnMainSync(mContentsClient);
mAwContents = mTestView.getAwContents();
mWebServer = TestWebServer.startSsl();
}
@After
public void tearDown() {
if (mWebServer != null) {
mWebServer.shutdown();
}
}
/**
* Allocate an URL from the webserver that stores a main document and a fenced frame
* resource to be returned. The result should then be loaded in the WebContents.
*/
private String generateFencedFrame(String fencedFrameHtml) {
String path = "/fenced_frame.html";
final List<Pair<String, String>> headers = new ArrayList<Pair<String, String>>();
headers.add(new Pair("Supports-Loading-Mode", " fenced-frame"));
String fencedFrameUrl = mWebServer.setResponse(path, fencedFrameHtml, headers);
String mainPath = "/main_document.html";
String mainResponseStr =
"<html><body><fencedframe style='width: 100%; height: 100%'></fencedframe>"
+ "<script>const url = new URL(\""
+ fencedFrameUrl
+ "\");document.querySelector(\"fencedframe\").config = new"
+ " FencedFrameConfig(url);</script></body></html>";
return mWebServer.setResponse(mainPath, mainResponseStr, null);
}
/**
* Test that a java object is mirrored in a fenced frame.
**/
@Test
@SmallTest
@Feature({"AndroidWebView", "Android-JavaBridge"})
public void testInjectedObjectPresentInFencedFrame() throws Throwable {
String fencedFrameSource = "<script>fencedFrameObserver.notifyJava();</script>";
String mainUrl = generateFencedFrame(fencedFrameSource);
final JavascriptEventObserver fencedFrameObserver = new JavascriptEventObserver();
final String fencedFrameObserverName = "fencedFrameObserver";
AwActivityTestRule.enableJavaScriptOnUiThread(mAwContents);
InstrumentationRegistry.getInstrumentation()
.runOnMainSync(
() -> {
fencedFrameObserver.register(
mTestView.getWebContents(), fencedFrameObserverName);
});
mActivityTestRule.loadUrlSync(
mAwContents, mContentsClient.getOnPageFinishedHelper(), mainUrl);
Assert.assertTrue(fencedFrameObserver.waitForEvent(WAIT_TIMEOUT_MS));
}
/**
* Test that an object that is mutated in the main frame can be observed in
* the fenced frame.
*/
@Test
@SmallTest
@Feature({"AndroidWebView", "Android-JavaBridge"})
public void testCommunicationBetweenFrames() throws Throwable {
String fencedFrameSource =
"<script>"
+ " function step() {"
+ " if (testObserver.getValue() == 'SET') {"
+ " testObserver.notifyJava(); "
+ " } else {"
+ " requestAnimationFrame(step);"
+ " }"
+ " }"
+ " requestAnimationFrame(step);"
+ "</script>";
String mainUrl = generateFencedFrame(fencedFrameSource);
class TestObserver {
private String mValue = "UNSET";
private CallbackHelper mCallbackHelper = new CallbackHelper();
@JavascriptInterface
public String getValue() {
return mValue;
}
@JavascriptInterface
public void setString(String value) {
mValue = value;
}
@JavascriptInterface
public void notifyJava() {
mCallbackHelper.notifyCalled();
}
public void waitForEvent() throws TimeoutException {
mCallbackHelper.waitForNext();
}
}
AwActivityTestRule.enableJavaScriptOnUiThread(mAwContents);
TestObserver testObserver = new TestObserver();
AwActivityTestRule.addJavascriptInterfaceOnUiThread(
mAwContents, testObserver, "testObserver");
mActivityTestRule.loadUrlSync(
mAwContents, mContentsClient.getOnPageFinishedHelper(), mainUrl);
mActivityTestRule.runOnUiThread(
() -> {
mAwContents.evaluateJavaScript("testObserver.setString('SET');", null);
});
testObserver.waitForEvent();
}
/**
* Test that a hit test in a fenced frame produces the correct results on the WebView API.
**/
@Test
@SmallTest
@Feature({"AndroidWebView", "Android-JavaBridge"})
public void hitTestFencedFrame() throws Throwable {
String fencedFrameSource =
CommonResources.makeHtmlPageFrom(
"",
"<a href='http://foo/' class='full_view' false;'>Test</a>"
+ "<script>fencedFrameObserver.notifyJava();</script>");
String mainUrl = generateFencedFrame(fencedFrameSource);
final JavascriptEventObserver fencedFrameObserver = new JavascriptEventObserver();
final String fencedFrameObserverName = "fencedFrameObserver";
AwActivityTestRule.enableJavaScriptOnUiThread(mAwContents);
InstrumentationRegistry.getInstrumentation()
.runOnMainSync(
() -> {
fencedFrameObserver.register(
mTestView.getWebContents(), fencedFrameObserverName);
});
mActivityTestRule.loadUrlSync(
mAwContents, mContentsClient.getOnPageFinishedHelper(), mainUrl);
// We need to wait for the fenced frame to load because loadUrlSync only waits
// for the outermost main frame.
Assert.assertTrue(fencedFrameObserver.waitForEvent(WAIT_TIMEOUT_MS));
mActivityTestRule.pollUiThread(
() -> {
// The hit testing regions may not be available on the first calls and there is
// no way of knowing when they are ready and it is safe to send input, so we
// send it every iteration.
AwTestTouchUtils.simulateTouchCenterOfView(mTestView);
AwContents.HitTestData data = mAwContents.getLastHitTestResult();
return HitTestResult.SRC_ANCHOR_TYPE == data.hitTestResultType
&& "http://foo/".equals(data.hitTestResultExtraData);
});
}
/**
* Test that a fenced frame is rastered correctly.
**/
@Test
@SmallTest
@Feature({"AndroidWebView", "Android-JavaBridge"})
public void fencedFrameDrawingSmokeTest() throws Throwable {
String fencedFrameSource =
"<html>"
+ " <body style=\""
+ " padding: 0;"
+ " margin: 0;"
+ " display: grid;"
+ " display: grid;"
+ " grid-template-columns: 50% 50%;"
+ " grid-template-rows: 50% 50%;\">"
+ " <div style=\"background-color: rgb(255, 0, 0);\"></div>"
+ " <div style=\"background-color: rgb(0, 255, 0);\"></div>"
+ " <div style=\"background-color: rgb(0, 0, 255);\"></div>"
+ " <div style=\"background-color: rgb(128, 128, 128);\"></div>"
+ " <script>fencedFrameObserver.notifyJava();</script>"
+ " </body>"
+ "</html>";
String mainUrl = generateFencedFrame(fencedFrameSource);
final JavascriptEventObserver fencedFrameObserver = new JavascriptEventObserver();
final String fencedFrameObserverName = "fencedFrameObserver";
AwActivityTestRule.enableJavaScriptOnUiThread(mAwContents);
InstrumentationRegistry.getInstrumentation()
.runOnMainSync(
() -> {
fencedFrameObserver.register(
mTestView.getWebContents(), fencedFrameObserverName);
});
mActivityTestRule.loadUrlSync(
mAwContents, mContentsClient.getOnPageFinishedHelper(), mainUrl);
// We need to wait for the fenced frame to load because loadUrlSync only waits
// for the outermost main frame.
Assert.assertTrue(fencedFrameObserver.waitForEvent(WAIT_TIMEOUT_MS));
mActivityTestRule.waitForVisualStateCallback(mAwContents);
int expectedQuadrantColors[] = {
Color.rgb(255, 0, 0),
Color.rgb(0, 255, 0),
Color.rgb(0, 0, 255),
Color.rgb(128, 128, 128)
};
GraphicsTestUtils.pollForQuadrantColors(mTestView, expectedQuadrantColors);
}
}