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