1 // Copyright 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.content.browser; 6 7 import android.test.suitebuilder.annotation.SmallTest; 8 9 import org.chromium.base.test.util.Feature; 10 11 /** 12 * Part of the test suite for the WebView's Java Bridge. 13 * 14 * Ensures that injected objects are exposed to child frames as well as the 15 * main frame. 16 */ 17 public class JavaBridgeChildFrameTest extends JavaBridgeTestBase { 18 private class TestController extends Controller { 19 private String mStringValue; 20 21 @SuppressWarnings("unused") // Called via reflection setStringValue(String x)22 public synchronized void setStringValue(String x) { 23 mStringValue = x; 24 notifyResultIsReady(); 25 } waitForStringValue()26 public synchronized String waitForStringValue() { 27 waitForResult(); 28 return mStringValue; 29 } 30 } 31 32 TestController mTestController; 33 34 @Override setUp()35 protected void setUp() throws Exception { 36 super.setUp(); 37 mTestController = new TestController(); 38 setUpContentView(mTestController, "testController"); 39 } 40 41 @SmallTest 42 @Feature({"AndroidWebView", "Android-JavaBridge"}) testInjectedObjectPresentInChildFrame()43 public void testInjectedObjectPresentInChildFrame() throws Throwable { 44 loadDataSync(getContentViewCore(), 45 "<html><body><iframe></iframe></body></html>", "text/html", false); 46 // We are not executing this code as a part of page loading routine to avoid races 47 // with internal Blink events that notify Java Bridge about window object updates. 48 assertEquals("\"object\"", executeJavaScriptAndGetResult( 49 getContentViewCore(), "typeof window.frames[0].testController")); 50 executeJavaScriptAndGetResult( 51 getContentViewCore(), "window.frames[0].testController.setStringValue('PASS')"); 52 assertEquals("PASS", mTestController.waitForStringValue()); 53 } 54 55 // Verify that loading an iframe doesn't ruin JS wrapper of the main page. 56 // This is a regression test for the problem described in b/15572824. 57 @SmallTest 58 @Feature({"AndroidWebView", "Android-JavaBridge"}) testMainPageWrapperIsNotBrokenByChildFrame()59 public void testMainPageWrapperIsNotBrokenByChildFrame() throws Throwable { 60 loadDataSync(getContentViewCore(), 61 "<html><body><iframe></iframe></body></html>", "text/html", false); 62 // In case there is anything wrong with the JS wrapper, an attempt 63 // to look up its properties will result in an exception being thrown. 64 String script = 65 "(function(){ try {" + 66 " return typeof testController.setStringValue;" + 67 "} catch (e) {" + 68 " return e.toString();" + 69 "} })()"; 70 assertEquals("\"function\"", 71 executeJavaScriptAndGetResult(getContentViewCore(), script)); 72 // Make sure calling a method also works. 73 executeJavaScriptAndGetResult(getContentViewCore(), 74 "testController.setStringValue('PASS');"); 75 assertEquals("PASS", mTestController.waitForStringValue()); 76 } 77 78 // Verify that parent page and child frame each has own JS wrapper object. 79 // Failing to do so exposes parent's context to the child. 80 @SmallTest 81 @Feature({"AndroidWebView", "Android-JavaBridge"}) testWrapperIsNotSharedWithChildFrame()82 public void testWrapperIsNotSharedWithChildFrame() throws Throwable { 83 // Test by setting a custom property on the parent page's injected 84 // object and then checking that child frame doesn't see the property. 85 loadDataSync(getContentViewCore(), 86 "<html><head>" + 87 "<script>" + 88 " window.wProperty = 42;" + 89 " testController.tcProperty = 42;" + 90 " function queryProperties(w) {" + 91 " return w.wProperty + ' / ' + w.testController.tcProperty;" + 92 " }" + 93 "</script>" + 94 "</head><body><iframe></iframe></body></html>", "text/html", false); 95 assertEquals("\"42 / 42\"", 96 executeJavaScriptAndGetResult(getContentViewCore(), "queryProperties(window)")); 97 assertEquals("\"undefined / undefined\"", 98 executeJavaScriptAndGetResult(getContentViewCore(), 99 "queryProperties(window.frames[0])")); 100 } 101 executeJavaScriptAndGetResult(final ContentViewCore contentViewCore, final String script)102 private String executeJavaScriptAndGetResult(final ContentViewCore contentViewCore, 103 final String script) throws Throwable { 104 final String[] result = new String[1]; 105 class ResultCallback extends JavaBridgeTestBase.Controller 106 implements ContentViewCore.JavaScriptCallback { 107 @Override 108 public void handleJavaScriptResult(String jsonResult) { 109 result[0] = jsonResult; 110 notifyResultIsReady(); 111 } 112 } 113 final ResultCallback resultCallback = new ResultCallback(); 114 runTestOnUiThread(new Runnable() { 115 @Override 116 public void run() { 117 contentViewCore.evaluateJavaScript(script, resultCallback); 118 } 119 }); 120 resultCallback.waitForResult(); 121 return result[0]; 122 } 123 } 124