1 // Copyright 2014 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.android_webview.test; 6 7 import android.support.test.InstrumentationRegistry; 8 import android.webkit.JavascriptInterface; 9 10 import androidx.test.filters.SmallTest; 11 12 import org.junit.Assert; 13 import org.junit.Before; 14 import org.junit.Rule; 15 import org.junit.Test; 16 import org.junit.runner.RunWith; 17 18 import org.chromium.android_webview.AwContents; 19 import org.chromium.base.test.util.Feature; 20 import org.chromium.content_public.browser.test.util.TestThreadUtils; 21 22 /** 23 * Test suite for the WebView specific JavaBridge features. 24 */ 25 @RunWith(AwJUnit4ClassRunner.class) 26 public class AwJavaBridgeTest { 27 @Rule 28 public AwActivityTestRule mActivityTestRule = new AwActivityTestRule(); 29 30 private TestAwContentsClient mContentsClient = new TestAwContentsClient(); 31 private AwTestContainerView mTestContainerView; 32 33 // The system retains a strong ref to the last focused view (in InputMethodManager) 34 // so allow for 1 'leaked' instance. 35 private static final int MAX_IDLE_INSTANCES = 1; 36 37 @Before setUp()38 public void setUp() { 39 mTestContainerView = mActivityTestRule.createAwTestContainerViewOnMainSync(mContentsClient); 40 } 41 42 @Test 43 @SmallTest 44 @Feature({"AndroidWebView", "Android-JavaBridge"}) testDestroyFromJavaObject()45 public void testDestroyFromJavaObject() throws Throwable { 46 final String html = "<html>Hello World</html>"; 47 final TestAwContentsClient client2 = new TestAwContentsClient(); 48 final AwTestContainerView view2 = 49 mActivityTestRule.createAwTestContainerViewOnMainSync(client2); 50 final AwContents awContents = mTestContainerView.getAwContents(); 51 52 class Test { 53 @JavascriptInterface 54 public void destroy() { 55 try { 56 InstrumentationRegistry.getInstrumentation().runOnMainSync( 57 () -> awContents.destroy()); 58 // Destroying one AwContents from within the JS callback should still 59 // leave others functioning. Note that we must do this asynchronously, 60 // as Blink thread is currently blocked waiting for this method to finish. 61 mActivityTestRule.loadDataAsync( 62 view2.getAwContents(), html, "text/html", false); 63 } catch (Throwable t) { 64 throw new RuntimeException(t); 65 } 66 } 67 } 68 69 AwActivityTestRule.enableJavaScriptOnUiThread(awContents); 70 AwActivityTestRule.addJavascriptInterfaceOnUiThread(awContents, new Test(), "test"); 71 72 mActivityTestRule.loadDataSync( 73 awContents, mContentsClient.getOnPageFinishedHelper(), html, "text/html", false); 74 75 // Ensure the JS interface object is there, and invoke the test method. 76 Assert.assertEquals("\"function\"", 77 mActivityTestRule.executeJavaScriptAndWaitForResult( 78 awContents, mContentsClient, "typeof test.destroy")); 79 int currentCallCount = client2.getOnPageFinishedHelper().getCallCount(); 80 TestThreadUtils.runOnUiThreadBlocking( 81 () -> awContents.evaluateJavaScriptForTests("test.destroy()", null)); 82 83 client2.getOnPageFinishedHelper().waitForCallback(currentCallCount); 84 } 85 86 @Test 87 @SmallTest 88 @Feature({"AndroidWebView", "Android-JavaBridge"}) testTwoWebViewsCreatedSimultaneously()89 public void testTwoWebViewsCreatedSimultaneously() throws Throwable { 90 final AwContents awContents1 = mTestContainerView.getAwContents(); 91 final TestAwContentsClient client2 = new TestAwContentsClient(); 92 final AwTestContainerView view2 = 93 mActivityTestRule.createAwTestContainerViewOnMainSync(client2); 94 final AwContents awContents2 = view2.getAwContents(); 95 96 AwActivityTestRule.enableJavaScriptOnUiThread(awContents1); 97 AwActivityTestRule.enableJavaScriptOnUiThread(awContents2); 98 99 class Test { 100 Test(int value) { 101 mValue = value; 102 } 103 @JavascriptInterface 104 public int getValue() { 105 return mValue; 106 } 107 private int mValue; 108 } 109 110 AwActivityTestRule.addJavascriptInterfaceOnUiThread(awContents1, new Test(1), "test"); 111 AwActivityTestRule.addJavascriptInterfaceOnUiThread(awContents2, new Test(2), "test"); 112 final String html = "<html>Hello World</html>"; 113 mActivityTestRule.loadDataSync( 114 awContents1, mContentsClient.getOnPageFinishedHelper(), html, "text/html", false); 115 mActivityTestRule.loadDataSync( 116 awContents2, client2.getOnPageFinishedHelper(), html, "text/html", false); 117 118 Assert.assertEquals("1", 119 mActivityTestRule.executeJavaScriptAndWaitForResult( 120 awContents1, mContentsClient, "test.getValue()")); 121 Assert.assertEquals("2", 122 mActivityTestRule.executeJavaScriptAndWaitForResult( 123 awContents2, client2, "test.getValue()")); 124 } 125 126 @Test 127 @SmallTest 128 @Feature({"AndroidWebView", "Android-JavaBridge"}) testTwoWebViewsSecondCreatedAfterLoadingInFirst()129 public void testTwoWebViewsSecondCreatedAfterLoadingInFirst() throws Throwable { 130 final AwContents awContents1 = mTestContainerView.getAwContents(); 131 AwActivityTestRule.enableJavaScriptOnUiThread(awContents1); 132 133 class Test { 134 Test(int value) { 135 mValue = value; 136 } 137 @JavascriptInterface 138 public int getValue() { 139 return mValue; 140 } 141 private int mValue; 142 } 143 144 AwActivityTestRule.addJavascriptInterfaceOnUiThread(awContents1, new Test(1), "test"); 145 final String html = "<html>Hello World</html>"; 146 mActivityTestRule.loadDataSync( 147 awContents1, mContentsClient.getOnPageFinishedHelper(), html, "text/html", false); 148 Assert.assertEquals("1", 149 mActivityTestRule.executeJavaScriptAndWaitForResult( 150 awContents1, mContentsClient, "test.getValue()")); 151 152 final TestAwContentsClient client2 = new TestAwContentsClient(); 153 final AwTestContainerView view2 = 154 mActivityTestRule.createAwTestContainerViewOnMainSync(client2); 155 final AwContents awContents2 = view2.getAwContents(); 156 AwActivityTestRule.enableJavaScriptOnUiThread(awContents2); 157 158 AwActivityTestRule.addJavascriptInterfaceOnUiThread(awContents2, new Test(2), "test"); 159 mActivityTestRule.loadDataSync( 160 awContents2, client2.getOnPageFinishedHelper(), html, "text/html", false); 161 162 Assert.assertEquals("1", 163 mActivityTestRule.executeJavaScriptAndWaitForResult( 164 awContents1, mContentsClient, "test.getValue()")); 165 Assert.assertEquals("2", 166 mActivityTestRule.executeJavaScriptAndWaitForResult( 167 awContents2, client2, "test.getValue()")); 168 } 169 } 170