blob: c18fccc4474fb5782faf541ebb1bac87aa902d60 [file] [log] [blame]
[email protected]fad73672012-06-15 23:26:061// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]c80b8ee2011-12-03 04:26:522// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Contains holistic tests of the bindings infrastructure
6
Gabriel Charette078e3662017-08-28 22:59:047#include "base/run_loop.h"
Devlin Cronina3fe3d602017-11-22 04:47:438#include "base/test/scoped_feature_list.h"
[email protected]7eef3942013-08-14 02:53:499#include "chrome/browser/extensions/api/permissions/permissions_api.h"
[email protected]c80b8ee2011-12-03 04:26:5210#include "chrome/browser/extensions/extension_apitest.h"
jochen7923c2a2015-07-14 10:04:4511#include "chrome/browser/net/url_request_mock_util.h"
Devlin Cronind2389082018-08-14 01:53:2612#include "chrome/browser/sessions/session_tab_helper.h"
[email protected]fad73672012-06-15 23:26:0613#include "chrome/browser/ui/browser.h"
Devlin Cronind2389082018-08-14 01:53:2614#include "chrome/browser/ui/browser_tabstrip.h"
rdevlin.cronin83a4b3a2015-10-28 21:43:5815#include "chrome/browser/ui/tabs/tab_strip_model.h"
asargent79b64c32016-08-04 17:17:1416#include "chrome/common/chrome_switches.h"
rdevlin.cronin83a4b3a2015-10-28 21:43:5817#include "chrome/test/base/ui_test_utils.h"
jochen7923c2a2015-07-14 10:04:4518#include "content/public/browser/browser_thread.h"
Devlin Croninb15c4f4e2017-12-15 21:20:1119#include "content/public/browser/render_frame_host.h"
[email protected]7d478cb2012-07-24 17:19:4220#include "content/public/test/browser_test_utils.h"
Devlin Cronind2389082018-08-14 01:53:2621#include "extensions/browser/event_router.h"
[email protected]22401dc2014-03-21 01:38:5722#include "extensions/browser/extension_host.h"
[email protected]98b6d942013-11-10 00:34:0723#include "extensions/browser/process_manager.h"
Devlin Cronina3fe3d602017-11-22 04:47:4324#include "extensions/common/extension_features.h"
lfg910f2f92014-09-19 05:31:0925#include "extensions/test/extension_test_message_listener.h"
yoze8dc2f12014-09-09 23:16:3226#include "extensions/test/result_catcher.h"
Devlin Cronind2389082018-08-14 01:53:2627#include "extensions/test/test_extension_dir.h"
rdevlin.cronine6e20022017-06-13 18:23:4028#include "net/dns/mock_host_resolver.h"
rdevlin.cronin83a4b3a2015-10-28 21:43:5829#include "net/test/embedded_test_server/embedded_test_server.h"
[email protected]fad73672012-06-15 23:26:0630
[email protected]adafe5b2013-08-09 10:35:0431namespace extensions {
32namespace {
33
Devlin Croninc3a1e5072017-08-17 17:02:4934enum BindingsType { NATIVE_BINDINGS, JAVASCRIPT_BINDINGS };
35
36class ExtensionBindingsApiTest
37 : public ExtensionApiTest,
38 public ::testing::WithParamInterface<BindingsType> {
jochen7923c2a2015-07-14 10:04:4539 public:
Devlin Cronina3fe3d602017-11-22 04:47:4340 ExtensionBindingsApiTest() {}
41 ~ExtensionBindingsApiTest() override {}
42
43 void SetUp() override {
44 if (GetParam() == NATIVE_BINDINGS) {
45 scoped_feature_list_.InitAndEnableFeature(features::kNativeCrxBindings);
46 } else {
47 DCHECK_EQ(JAVASCRIPT_BINDINGS, GetParam());
48 scoped_feature_list_.InitAndDisableFeature(features::kNativeCrxBindings);
49 }
50 ExtensionApiTest::SetUp();
Devlin Croninc3a1e5072017-08-17 17:02:4951 }
52
jochen7923c2a2015-07-14 10:04:4553 void SetUpOnMainThread() override {
rdevlin.cronin17160cc62016-11-23 05:33:0854 ExtensionApiTest::SetUpOnMainThread();
rdevlin.cronine6e20022017-06-13 18:23:4055 host_resolver()->AddRule("*", "127.0.0.1");
56 ASSERT_TRUE(StartEmbeddedTestServer());
jochen7923c2a2015-07-14 10:04:4557 }
Devlin Cronina3fe3d602017-11-22 04:47:4358
59 private:
60 base::test::ScopedFeatureList scoped_feature_list_;
61
62 DISALLOW_COPY_AND_ASSIGN(ExtensionBindingsApiTest);
jochen7923c2a2015-07-14 10:04:4563};
[email protected]adafe5b2013-08-09 10:35:0464
Devlin Croninc3a1e5072017-08-17 17:02:4965IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
[email protected]7eef3942013-08-14 02:53:4966 UnavailableBindingsNeverRegistered) {
67 // Test will request the 'storage' permission.
68 PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
69 ASSERT_TRUE(RunExtensionTest(
70 "bindings/unavailable_bindings_never_registered")) << message_;
71}
72
Devlin Croninc3a1e5072017-08-17 17:02:4973IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
[email protected]adafe5b2013-08-09 10:35:0474 ExceptionInHandlerShouldNotCrash) {
[email protected]c80b8ee2011-12-03 04:26:5275 ASSERT_TRUE(RunExtensionSubtest(
76 "bindings/exception_in_handler_should_not_crash",
77 "page.html")) << message_;
78}
[email protected]fad73672012-06-15 23:26:0679
80// Tests that an error raised during an async function still fires
[email protected]754ea8b72013-01-08 15:10:3181// the callback, but sets chrome.runtime.lastError.
Devlin Croninc3a1e5072017-08-17 17:02:4982IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, LastError) {
[email protected]fad73672012-06-15 23:26:0683 ASSERT_TRUE(LoadExtension(
Devlin Croninc3a1e5072017-08-17 17:02:4984 test_data_dir_.AppendASCII("bindings").AppendASCII("last_error")));
[email protected]fad73672012-06-15 23:26:0685
86 // Get the ExtensionHost that is hosting our background page.
[email protected]98b6d942013-11-10 00:34:0787 extensions::ProcessManager* manager =
reillyg0ea3fa902014-10-28 15:30:2388 extensions::ProcessManager::Get(browser()->profile());
[email protected]3a1dc572012-07-31 22:25:1389 extensions::ExtensionHost* host = FindHostWithPath(manager, "/bg.html", 1);
[email protected]fad73672012-06-15 23:26:0690
91 bool result = false;
David Benjamin5a792652018-06-08 02:15:4292 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(host->host_contents(),
93 "testLastError()", &result));
[email protected]fad73672012-06-15 23:26:0694 EXPECT_TRUE(result);
95}
[email protected]52eafbd2013-04-03 04:43:1996
[email protected]adafe5b2013-08-09 10:35:0497// Regression test that we don't delete our own bindings with about:blank
98// iframes.
Devlin Croninc3a1e5072017-08-17 17:02:4999IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, AboutBlankIframe) {
[email protected]adafe5b2013-08-09 10:35:04100 ResultCatcher catcher;
101 ExtensionTestMessageListener listener("load", true);
102
103 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("bindings")
104 .AppendASCII("about_blank_iframe")));
105
106 ASSERT_TRUE(listener.WaitUntilSatisfied());
107
108 const Extension* extension = LoadExtension(
109 test_data_dir_.AppendASCII("bindings")
110 .AppendASCII("internal_apis_not_on_chrome_object"));
111 ASSERT_TRUE(extension);
112 listener.Reply(extension->id());
113
114 ASSERT_TRUE(catcher.GetNextResult()) << message_;
115}
116
Devlin Croninc3a1e5072017-08-17 17:02:49117IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
[email protected]adafe5b2013-08-09 10:35:04118 InternalAPIsNotOnChromeObject) {
[email protected]52eafbd2013-04-03 04:43:19119 ASSERT_TRUE(RunExtensionSubtest(
120 "bindings/internal_apis_not_on_chrome_object",
121 "page.html")) << message_;
122}
[email protected]adafe5b2013-08-09 10:35:04123
[email protected]fc034482013-08-09 20:25:14124// Tests that we don't override events when bindings are re-injected.
125// Regression test for http://crbug.com/269149.
rpaquay96bf3b7d2014-11-26 00:19:08126// Regression test for http://crbug.com/436593.
Henrik Grunell6b7d9db2017-06-14 10:27:20127// Flaky on Mac. http://crbug.com/733064.
Giovanni Ortuño Urquidi7ce215452017-06-14 03:34:08128#if defined(OS_MACOSX)
129#define MAYBE_EventOverriding DISABLED_EventOverriding
130#else
131#define MAYBE_EventOverriding EventOverriding
132#endif
Devlin Croninc3a1e5072017-08-17 17:02:49133IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, MAYBE_EventOverriding) {
[email protected]fc034482013-08-09 20:25:14134 ASSERT_TRUE(RunExtensionTest("bindings/event_overriding")) << message_;
rdevlin.cronind734f682017-06-13 21:23:11135 // The extension test removes a window and, during window removal, sends the
136 // success message. Make sure we flush all pending tasks.
137 base::RunLoop().RunUntilIdle();
[email protected]fc034482013-08-09 20:25:14138}
139
kalman1bd5b182015-01-13 19:01:18140// Tests the effectiveness of the 'nocompile' feature file property.
141// Regression test for http://crbug.com/356133.
Devlin Croninc3a1e5072017-08-17 17:02:49142IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, Nocompile) {
kalman1bd5b182015-01-13 19:01:18143 ASSERT_TRUE(RunExtensionSubtest("bindings/nocompile", "page.html"))
144 << message_;
145}
146
Devlin Croninc3a1e5072017-08-17 17:02:49147IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, ApiEnums) {
rdevlin.cronin2ba3c88d2015-03-03 01:18:22148 ASSERT_TRUE(RunExtensionTest("bindings/api_enums")) << message_;
149};
150
jochen7923c2a2015-07-14 10:04:45151// Regression test for http://crbug.com/504011 - proper access checks on
152// getModuleSystem().
Devlin Croninc3a1e5072017-08-17 17:02:49153IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, ModuleSystem) {
jochen7923c2a2015-07-14 10:04:45154 ASSERT_TRUE(RunExtensionTest("bindings/module_system")) << message_;
155}
156
Devlin Croninc3a1e5072017-08-17 17:02:49157IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, NoExportOverriding) {
rdevlin.cronin83a4b3a2015-10-28 21:43:58158 // We need to create runtime bindings in the web page. An extension that's
159 // externally connectable will do that for us.
160 ASSERT_TRUE(LoadExtension(
161 test_data_dir_.AppendASCII("bindings")
162 .AppendASCII("externally_connectable_everywhere")));
163
164 ui_test_utils::NavigateToURL(
165 browser(),
166 embedded_test_server()->GetURL(
167 "/extensions/api_test/bindings/override_exports.html"));
168
169 // See chrome/test/data/extensions/api_test/bindings/override_exports.html.
170 std::string result;
171 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
172 browser()->tab_strip_model()->GetActiveWebContents(),
173 "window.domAutomationController.send("
174 "document.getElementById('status').textContent.trim());",
175 &result));
176 EXPECT_EQ("success", result);
177}
178
Devlin Croninc3a1e5072017-08-17 17:02:49179IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, NoGinDefineOverriding) {
rdevlin.cronin415b73b2015-11-13 01:14:47180 // We need to create runtime bindings in the web page. An extension that's
181 // externally connectable will do that for us.
182 ASSERT_TRUE(LoadExtension(
183 test_data_dir_.AppendASCII("bindings")
184 .AppendASCII("externally_connectable_everywhere")));
185
186 ui_test_utils::NavigateToURL(
187 browser(),
188 embedded_test_server()->GetURL(
189 "/extensions/api_test/bindings/override_gin_define.html"));
190 ASSERT_FALSE(
191 browser()->tab_strip_model()->GetActiveWebContents()->IsCrashed());
192
193 // See chrome/test/data/extensions/api_test/bindings/override_gin_define.html.
194 std::string result;
195 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
196 browser()->tab_strip_model()->GetActiveWebContents(),
197 "window.domAutomationController.send("
198 "document.getElementById('status').textContent.trim());",
199 &result));
200 EXPECT_EQ("success", result);
201}
202
Devlin Croninc3a1e5072017-08-17 17:02:49203IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, HandlerFunctionTypeChecking) {
rdevlin.cronina5ecbc82015-10-29 23:41:29204 ui_test_utils::NavigateToURL(
205 browser(),
206 embedded_test_server()->GetURL(
207 "/extensions/api_test/bindings/handler_function_type_checking.html"));
208 content::WebContents* web_contents =
209 browser()->tab_strip_model()->GetActiveWebContents();
210 EXPECT_FALSE(web_contents->IsCrashed());
211 // See handler_function_type_checking.html.
212 std::string result;
213 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
214 web_contents,
215 "window.domAutomationController.send("
216 "document.getElementById('status').textContent.trim());",
217 &result));
218 EXPECT_EQ("success", result);
219}
220
Devlin Croninc3a1e5072017-08-17 17:02:49221IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
rdevlin.cronin75b803b2016-03-02 00:13:47222 MoreNativeFunctionInterceptionTests) {
rdevlin.cronin75b803b2016-03-02 00:13:47223 // We need to create runtime bindings in the web page. An extension that's
224 // externally connectable will do that for us.
225 ASSERT_TRUE(
226 LoadExtension(test_data_dir_.AppendASCII("bindings")
227 .AppendASCII("externally_connectable_everywhere")));
228
229 ui_test_utils::NavigateToURL(
230 browser(),
231 embedded_test_server()->GetURL(
232 "/extensions/api_test/bindings/function_interceptions.html"));
233 content::WebContents* web_contents =
234 browser()->tab_strip_model()->GetActiveWebContents();
235 EXPECT_FALSE(web_contents->IsCrashed());
236 // See function_interceptions.html.
237 std::string result;
238 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
239 web_contents, "window.domAutomationController.send(window.testStatus);",
240 &result));
241 EXPECT_EQ("success", result);
242}
243
asargent79b64c32016-08-04 17:17:14244class FramesExtensionBindingsApiTest : public ExtensionBindingsApiTest {
245 public:
246 void SetUpCommandLine(base::CommandLine* command_line) override {
247 ExtensionBindingsApiTest::SetUpCommandLine(command_line);
Devlin Croninc3a1e5072017-08-17 17:02:49248 command_line->AppendSwitch(::switches::kDisablePopupBlocking);
asargent79b64c32016-08-04 17:17:14249 }
250};
251
252// This tests that web pages with iframes or child windows pointing at
253// chrome-extenison:// urls, both web_accessible and nonexistent pages, don't
254// get improper extensions bindings injected while they briefly still point at
255// about:blank and are still scriptable by their parent.
256//
257// The general idea is to load up 2 extensions, one which listens for external
258// messages ("receiver") and one which we'll try first faking messages from in
259// the web page's iframe, as well as actually send a message from later
260// ("sender").
Dave Tapuska61ed7fbb2017-09-05 21:42:08261IN_PROC_BROWSER_TEST_P(FramesExtensionBindingsApiTest, FramesBeforeNavigation) {
asargent79b64c32016-08-04 17:17:14262 // Load the sender and receiver extensions, and make sure they are ready.
263 ExtensionTestMessageListener sender_ready("sender_ready", true);
264 const Extension* sender = LoadExtension(
265 test_data_dir_.AppendASCII("bindings").AppendASCII("message_sender"));
266 ASSERT_NE(nullptr, sender);
267 ASSERT_TRUE(sender_ready.WaitUntilSatisfied());
268
269 ExtensionTestMessageListener receiver_ready("receiver_ready", false);
270 const Extension* receiver =
271 LoadExtension(test_data_dir_.AppendASCII("bindings")
272 .AppendASCII("external_message_listener"));
273 ASSERT_NE(nullptr, receiver);
274 ASSERT_TRUE(receiver_ready.WaitUntilSatisfied());
275
276 // Load the web page which tries to impersonate the sender extension via
277 // scripting iframes/child windows before they finish navigating to pages
278 // within the sender extension.
asargent79b64c32016-08-04 17:17:14279 ui_test_utils::NavigateToURL(
280 browser(),
281 embedded_test_server()->GetURL(
282 "/extensions/api_test/bindings/frames_before_navigation.html"));
283
284 bool page_success = false;
285 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
286 browser()->tab_strip_model()->GetWebContentsAt(0), "getResult()",
287 &page_success));
288 EXPECT_TRUE(page_success);
289
290 // Reply to |sender|, causing it to send a message over to |receiver|, and
291 // then ask |receiver| for the total message count. It should be 1 since
292 // |receiver| should not have received any impersonated messages.
293 sender_ready.Reply(receiver->id());
294 int message_count = 0;
295 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
296 ProcessManager::Get(profile())
297 ->GetBackgroundHostForExtension(receiver->id())
298 ->host_contents(),
299 "getMessageCountAfterReceivingRealSenderMessage()", &message_count));
300 EXPECT_EQ(1, message_count);
301}
302
Devlin Croninc3a1e5072017-08-17 17:02:49303IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, TestFreezingChrome) {
rdevlin.cronin741da002017-04-24 20:27:41304 ui_test_utils::NavigateToURL(
305 browser(), embedded_test_server()->GetURL(
306 "/extensions/api_test/bindings/freeze.html"));
307 content::WebContents* web_contents =
308 browser()->tab_strip_model()->GetActiveWebContents();
309 ASSERT_FALSE(web_contents->IsCrashed());
310}
311
rdevlin.cronine6e20022017-06-13 18:23:40312// Tests interaction with event filter parsing.
Devlin Croninc3a1e5072017-08-17 17:02:49313IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, TestEventFilterParsing) {
rdevlin.cronine6e20022017-06-13 18:23:40314 ExtensionTestMessageListener listener("ready", false);
315 ASSERT_TRUE(
316 LoadExtension(test_data_dir_.AppendASCII("bindings/event_filter")));
317 ASSERT_TRUE(listener.WaitUntilSatisfied());
318
319 ResultCatcher catcher;
320 ui_test_utils::NavigateToURL(
321 browser(), embedded_test_server()->GetURL("example.com", "/title1.html"));
322 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
323}
324
rdevlin.cronin350824d42017-06-16 14:47:35325// crbug.com/733337
Devlin Croninc3a1e5072017-08-17 17:02:49326IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, ValidationInterception) {
rdevlin.cronin350824d42017-06-16 14:47:35327 // We need to create runtime bindings in the web page. An extension that's
328 // externally connectable will do that for us.
329 ASSERT_TRUE(
330 LoadExtension(test_data_dir_.AppendASCII("bindings")
331 .AppendASCII("externally_connectable_everywhere")));
332
333 content::WebContents* web_contents =
334 browser()->tab_strip_model()->GetActiveWebContents();
335 ui_test_utils::NavigateToURL(
336 browser(),
337 embedded_test_server()->GetURL(
338 "/extensions/api_test/bindings/validation_interception.html"));
339 content::WaitForLoadStop(web_contents);
340 ASSERT_FALSE(web_contents->IsCrashed());
341 bool caught = false;
342 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
343 web_contents, "domAutomationController.send(caught)", &caught));
344 EXPECT_TRUE(caught);
345}
346
Devlin Cronin5cf20f02017-10-10 14:25:04347IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, UncaughtExceptionLogging) {
348 ASSERT_TRUE(RunExtensionTest("bindings/uncaught_exception_logging"))
349 << message_;
350}
351
Alex Moshchuke63b9e92017-10-14 00:27:22352// Verify that when a web frame embeds an extension subframe, and that subframe
353// is the only active portion of the extension, the subframe gets proper JS
354// bindings. See https://crbug.com/760341.
355IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
356 ExtensionSubframeGetsBindings) {
357 // Load an extension that does not have a background page or popup, so it
358 // won't be activated just yet.
359 const extensions::Extension* extension =
360 LoadExtension(test_data_dir_.AppendASCII("bindings")
361 .AppendASCII("extension_subframe_gets_bindings"));
362 ASSERT_TRUE(extension);
363
364 // Navigate current tab to a web URL with a subframe.
365 content::WebContents* web_contents =
366 browser()->tab_strip_model()->GetActiveWebContents();
367 ui_test_utils::NavigateToURL(browser(),
368 embedded_test_server()->GetURL("/iframe.html"));
369
370 // Navigate the subframe to the extension URL, which should activate the
371 // extension.
372 GURL extension_url(extension->GetResourceURL("page.html"));
373 ResultCatcher catcher;
374 content::NavigateIframeToURL(web_contents, "test", extension_url);
375 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
376}
377
Devlin Croninb15c4f4e2017-12-15 21:20:11378IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
379 ExtensionListenersRemoveContext) {
380 const Extension* extension = LoadExtension(
381 test_data_dir_.AppendASCII("bindings/listeners_destroy_context"));
382 ASSERT_TRUE(extension);
383
384 ExtensionTestMessageListener listener("ready", true);
385
386 // Navigate to a web page with an iframe (the iframe is title1.html).
387 GURL main_frame_url = embedded_test_server()->GetURL("a.com", "/iframe.html");
388 ui_test_utils::NavigateToURL(browser(), main_frame_url);
389
390 content::WebContents* tab =
391 browser()->tab_strip_model()->GetActiveWebContents();
392
393 content::RenderFrameHost* main_frame = tab->GetMainFrame();
394 content::RenderFrameHost* subframe = ChildFrameAt(main_frame, 0);
395 content::RenderFrameDeletedObserver subframe_deleted(subframe);
396
397 // Wait for the extension's content script to be ready.
398 ASSERT_TRUE(listener.WaitUntilSatisfied());
399
400 // It's actually critical to the test that these frames are in the same
401 // process, because otherwise a crash in the iframe wouldn't be detectable
402 // (since we rely on JS execution in the main frame to tell if the renderer
403 // crashed - see comment below).
404 content::RenderProcessHost* main_frame_process = main_frame->GetProcess();
405 EXPECT_EQ(main_frame_process, subframe->GetProcess());
406
407 ExtensionTestMessageListener failure_listener("failed", false);
408
409 // Tell the extension to register listeners that will remove the iframe, and
410 // trigger them.
411 listener.Reply("go!");
412
413 // The frame will be deleted.
414 subframe_deleted.WaitUntilDeleted();
415
416 // Unfortunately, we don't have a good way of checking if something crashed
417 // after the frame was removed. WebContents::IsCrashed() seems like it should
418 // work, but is insufficient. Instead, use JS execution as the source of
419 // true.
420 EXPECT_FALSE(tab->IsCrashed());
421 EXPECT_EQ(main_frame_url, main_frame->GetLastCommittedURL());
422 EXPECT_EQ(main_frame_process, main_frame->GetProcess());
423 bool renderer_valid = false;
424 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
425 main_frame, "domAutomationController.send(true);", &renderer_valid));
426 EXPECT_TRUE(renderer_valid);
427 EXPECT_FALSE(failure_listener.was_satisfied());
428}
429
Devlin Croninb48b6f92018-01-12 23:17:59430IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, UseAPIsAfterContextRemoval) {
431 EXPECT_TRUE(RunExtensionTest("bindings/invalidate_context")) << message_;
432}
433
Devlin Cronin47e79042018-02-02 18:32:26434// TODO(devlin): Can this be combined with
435// ExtensionBindingsApiTest.UseAPIsAfterContextRemoval?
436IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, UseAppAPIAfterFrameRemoval) {
437 ASSERT_TRUE(RunExtensionTest("crazy_extension"));
438}
439
Devlin Cronind2389082018-08-14 01:53:26440// Tests attaching two listeners from the same extension but different pages,
441// then removing one, and ensuring the second is still notified.
442// Regression test for https://crbug.com/868763.
443IN_PROC_BROWSER_TEST_P(
444 ExtensionBindingsApiTest,
445 MultipleEventListenersFromDifferentContextsAndTheSameExtension) {
446 // A script that listens for tab creation and populates the result in a
447 // global variable.
448 constexpr char kTestPageScript[] = R"(
449 window.tabEventId = -1;
450 function registerListener() {
451 chrome.tabs.onCreated.addListener((tab) => {
452 window.tabEventId = tab.id;
453 });
454 }
455 )";
456 TestExtensionDir test_dir;
457 test_dir.WriteManifest(R"(
458 {
459 "name": "Duplicate event listeners",
460 "manifest_version": 2,
461 "version": "0.1"
462 })");
463 test_dir.WriteFile(FILE_PATH_LITERAL("page.html"),
464 R"(<html><script src="page.js"></script></html>)");
465 test_dir.WriteFile(FILE_PATH_LITERAL("page.js"), kTestPageScript);
466
467 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
468 ASSERT_TRUE(extension);
469
470 // Set up: open two tabs to the same extension page, and wait for each to
471 // load.
472 const GURL page_url = extension->GetResourceURL("page.html");
473 ui_test_utils::NavigateToURLWithDisposition(
474 browser(), page_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
475 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
476 content::WebContents* first_tab =
477 browser()->tab_strip_model()->GetActiveWebContents();
478 ui_test_utils::NavigateToURLWithDisposition(
479 browser(), page_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
480 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
481 content::WebContents* second_tab =
482 browser()->tab_strip_model()->GetActiveWebContents();
483
484 // Initially, there are no listeners registered.
485 EventRouter* event_router = EventRouter::Get(profile());
486 EXPECT_FALSE(event_router->ExtensionHasEventListener(extension->id(),
487 "tabs.onCreated"));
488
489 // Register both lsiteners, and verify they were added.
490 ASSERT_TRUE(content::ExecuteScript(first_tab, "registerListener()"));
491 ASSERT_TRUE(content::ExecuteScript(second_tab, "registerListener()"));
492 EXPECT_TRUE(event_router->ExtensionHasEventListener(extension->id(),
493 "tabs.onCreated"));
494
495 // Close one of the extension pages.
496 constexpr bool add_to_history = false;
497 content::WebContentsDestroyedWatcher watcher(second_tab);
498 chrome::CloseWebContents(browser(), second_tab, add_to_history);
499 watcher.Wait();
500 // Hacky round trip to the renderer to flush IPCs.
501 ASSERT_TRUE(content::ExecuteScript(first_tab, ""));
502
503 // Since the second page is still open, the extension should still be
504 // registered as a listener.
505 EXPECT_TRUE(event_router->ExtensionHasEventListener(extension->id(),
506 "tabs.onCreated"));
507
508 // Open a new tab.
509 ui_test_utils::NavigateToURLWithDisposition(
510 browser(), GURL("chrome://newtab"),
511 WindowOpenDisposition::NEW_FOREGROUND_TAB,
512 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
513 content::WebContents* new_tab =
514 browser()->tab_strip_model()->GetActiveWebContents();
515
516 // The extension should have been notified about the new tab, and have
517 // recorded the result.
518 int result_tab_id = -1;
519 EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
520 first_tab, "domAutomationController.send(window.tabEventId)",
521 &result_tab_id));
522 EXPECT_EQ(SessionTabHelper::IdForTab(new_tab).id(), result_tab_id);
523}
524
Devlin Croninc3a1e5072017-08-17 17:02:49525// Run core bindings API tests with both native and JS-based bindings. This
526// ensures we have some minimum level of coverage while in the experimental
527// phase, when native bindings may be enabled on trunk but not at 100% stable.
528INSTANTIATE_TEST_CASE_P(Native,
529 ExtensionBindingsApiTest,
530 ::testing::Values(NATIVE_BINDINGS));
531INSTANTIATE_TEST_CASE_P(JavaScript,
532 ExtensionBindingsApiTest,
533 ::testing::Values(JAVASCRIPT_BINDINGS));
534
535INSTANTIATE_TEST_CASE_P(Native,
536 FramesExtensionBindingsApiTest,
537 ::testing::Values(NATIVE_BINDINGS));
538INSTANTIATE_TEST_CASE_P(JavaScript,
539 FramesExtensionBindingsApiTest,
540 ::testing::Values(JAVASCRIPT_BINDINGS));
541
[email protected]adafe5b2013-08-09 10:35:04542} // namespace
543} // namespace extensions