| // Copyright 2012 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| package org.chromium.content.browser; |
| |
| import android.test.suitebuilder.annotation.SmallTest; |
| |
| import org.chromium.base.test.util.Feature; |
| import org.chromium.content_public.browser.JavaScriptCallback; |
| import org.chromium.content_public.browser.WebContents; |
| |
| /** |
| * Part of the test suite for the WebView's Java Bridge. |
| * |
| * Ensures that injected objects are exposed to child frames as well as the |
| * main frame. |
| */ |
| public class JavaBridgeChildFrameTest extends JavaBridgeTestBase { |
| private class TestController extends Controller { |
| private String mStringValue; |
| |
| @SuppressWarnings("unused") // Called via reflection |
| public synchronized void setStringValue(String x) { |
| mStringValue = x; |
| notifyResultIsReady(); |
| } |
| |
| public synchronized String waitForStringValue() { |
| waitForResult(); |
| return mStringValue; |
| } |
| } |
| |
| TestController mTestController; |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| mTestController = new TestController(); |
| setUpContentView(mTestController, "testController"); |
| } |
| |
| @SmallTest |
| @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| public void testInjectedObjectPresentInChildFrame() throws Throwable { |
| loadDataSync(getWebContents().getNavigationController(), |
| "<html><body><iframe></iframe></body></html>", "text/html", false); |
| // We are not executing this code as a part of page loading routine to avoid races |
| // with internal Blink events that notify Java Bridge about window object updates. |
| assertEquals("\"object\"", executeJavaScriptAndGetResult( |
| getWebContents(), "typeof window.frames[0].testController")); |
| executeJavaScriptAndGetResult( |
| getWebContents(), "window.frames[0].testController.setStringValue('PASS')"); |
| assertEquals("PASS", mTestController.waitForStringValue()); |
| } |
| |
| // Verify that loading an iframe doesn't ruin JS wrapper of the main page. |
| // This is a regression test for the problem described in b/15572824. |
| @SmallTest |
| @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| public void testMainPageWrapperIsNotBrokenByChildFrame() throws Throwable { |
| loadDataSync(getWebContents().getNavigationController(), |
| "<html><body><iframe></iframe></body></html>", "text/html", false); |
| // In case there is anything wrong with the JS wrapper, an attempt |
| // to look up its properties will result in an exception being thrown. |
| String script = |
| "(function(){ try {" + |
| " return typeof testController.setStringValue;" + |
| "} catch (e) {" + |
| " return e.toString();" + |
| "} })()"; |
| assertEquals("\"function\"", |
| executeJavaScriptAndGetResult(getWebContents(), script)); |
| // Make sure calling a method also works. |
| executeJavaScriptAndGetResult(getWebContents(), |
| "testController.setStringValue('PASS');"); |
| assertEquals("PASS", mTestController.waitForStringValue()); |
| } |
| |
| // Verify that parent page and child frame each has own JS wrapper object. |
| // Failing to do so exposes parent's context to the child. |
| @SmallTest |
| @Feature({"AndroidWebView", "Android-JavaBridge"}) |
| public void testWrapperIsNotSharedWithChildFrame() throws Throwable { |
| // Test by setting a custom property on the parent page's injected |
| // object and then checking that child frame doesn't see the property. |
| loadDataSync(getWebContents().getNavigationController(), |
| "<html><head>" + |
| "<script>" + |
| " window.wProperty = 42;" + |
| " testController.tcProperty = 42;" + |
| " function queryProperties(w) {" + |
| " return w.wProperty + ' / ' + w.testController.tcProperty;" + |
| " }" + |
| "</script>" + |
| "</head><body><iframe></iframe></body></html>", "text/html", false); |
| assertEquals("\"42 / 42\"", |
| executeJavaScriptAndGetResult(getWebContents(), "queryProperties(window)")); |
| assertEquals("\"undefined / undefined\"", |
| executeJavaScriptAndGetResult(getWebContents(), |
| "queryProperties(window.frames[0])")); |
| } |
| |
| private String executeJavaScriptAndGetResult(final WebContents webContents, |
| final String script) throws Throwable { |
| final String[] result = new String[1]; |
| class ResultCallback extends JavaBridgeTestBase.Controller |
| implements JavaScriptCallback { |
| @Override |
| public void handleJavaScriptResult(String jsonResult) { |
| result[0] = jsonResult; |
| notifyResultIsReady(); |
| } |
| } |
| final ResultCallback resultCallback = new ResultCallback(); |
| runTestOnUiThread(new Runnable() { |
| @Override |
| public void run() { |
| webContents.evaluateJavaScript(script, resultCallback); |
| } |
| }); |
| resultCallback.waitForResult(); |
| return result[0]; |
| } |
| } |