blob: 607a611785c24f4bdbd54a5457bef8eec9d03524 [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) {
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:3545 scoped_feature_list_.InitAndEnableFeature(
46 extensions_features::kNativeCrxBindings);
Devlin Cronina3fe3d602017-11-22 04:47:4347 } else {
48 DCHECK_EQ(JAVASCRIPT_BINDINGS, GetParam());
Mostyn Bramley-Mooreb6a37c62018-09-04 21:43:3549 scoped_feature_list_.InitAndDisableFeature(
50 extensions_features::kNativeCrxBindings);
Devlin Cronina3fe3d602017-11-22 04:47:4351 }
52 ExtensionApiTest::SetUp();
Devlin Croninc3a1e5072017-08-17 17:02:4953 }
54
jochen7923c2a2015-07-14 10:04:4555 void SetUpOnMainThread() override {
rdevlin.cronin17160cc62016-11-23 05:33:0856 ExtensionApiTest::SetUpOnMainThread();
rdevlin.cronine6e20022017-06-13 18:23:4057 host_resolver()->AddRule("*", "127.0.0.1");
58 ASSERT_TRUE(StartEmbeddedTestServer());
jochen7923c2a2015-07-14 10:04:4559 }
Devlin Cronina3fe3d602017-11-22 04:47:4360
61 private:
62 base::test::ScopedFeatureList scoped_feature_list_;
63
64 DISALLOW_COPY_AND_ASSIGN(ExtensionBindingsApiTest);
jochen7923c2a2015-07-14 10:04:4565};
[email protected]adafe5b2013-08-09 10:35:0466
Devlin Croninc3a1e5072017-08-17 17:02:4967IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
[email protected]7eef3942013-08-14 02:53:4968 UnavailableBindingsNeverRegistered) {
69 // Test will request the 'storage' permission.
70 PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
71 ASSERT_TRUE(RunExtensionTest(
72 "bindings/unavailable_bindings_never_registered")) << message_;
73}
74
Devlin Croninc3a1e5072017-08-17 17:02:4975IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
[email protected]adafe5b2013-08-09 10:35:0476 ExceptionInHandlerShouldNotCrash) {
[email protected]c80b8ee2011-12-03 04:26:5277 ASSERT_TRUE(RunExtensionSubtest(
78 "bindings/exception_in_handler_should_not_crash",
79 "page.html")) << message_;
80}
[email protected]fad73672012-06-15 23:26:0681
82// Tests that an error raised during an async function still fires
[email protected]754ea8b72013-01-08 15:10:3183// the callback, but sets chrome.runtime.lastError.
Devlin Croninc3a1e5072017-08-17 17:02:4984IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, LastError) {
[email protected]fad73672012-06-15 23:26:0685 ASSERT_TRUE(LoadExtension(
Devlin Croninc3a1e5072017-08-17 17:02:4986 test_data_dir_.AppendASCII("bindings").AppendASCII("last_error")));
[email protected]fad73672012-06-15 23:26:0687
88 // Get the ExtensionHost that is hosting our background page.
[email protected]98b6d942013-11-10 00:34:0789 extensions::ProcessManager* manager =
reillyg0ea3fa902014-10-28 15:30:2390 extensions::ProcessManager::Get(browser()->profile());
[email protected]3a1dc572012-07-31 22:25:1391 extensions::ExtensionHost* host = FindHostWithPath(manager, "/bg.html", 1);
[email protected]fad73672012-06-15 23:26:0692
93 bool result = false;
David Benjamin5a792652018-06-08 02:15:4294 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(host->host_contents(),
95 "testLastError()", &result));
[email protected]fad73672012-06-15 23:26:0696 EXPECT_TRUE(result);
97}
[email protected]52eafbd2013-04-03 04:43:1998
[email protected]adafe5b2013-08-09 10:35:0499// Regression test that we don't delete our own bindings with about:blank
100// iframes.
Devlin Croninc3a1e5072017-08-17 17:02:49101IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, AboutBlankIframe) {
[email protected]adafe5b2013-08-09 10:35:04102 ResultCatcher catcher;
103 ExtensionTestMessageListener listener("load", true);
104
105 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("bindings")
106 .AppendASCII("about_blank_iframe")));
107
108 ASSERT_TRUE(listener.WaitUntilSatisfied());
109
110 const Extension* extension = LoadExtension(
111 test_data_dir_.AppendASCII("bindings")
112 .AppendASCII("internal_apis_not_on_chrome_object"));
113 ASSERT_TRUE(extension);
114 listener.Reply(extension->id());
115
116 ASSERT_TRUE(catcher.GetNextResult()) << message_;
117}
118
Devlin Croninc3a1e5072017-08-17 17:02:49119IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
[email protected]adafe5b2013-08-09 10:35:04120 InternalAPIsNotOnChromeObject) {
[email protected]52eafbd2013-04-03 04:43:19121 ASSERT_TRUE(RunExtensionSubtest(
122 "bindings/internal_apis_not_on_chrome_object",
123 "page.html")) << message_;
124}
[email protected]adafe5b2013-08-09 10:35:04125
[email protected]fc034482013-08-09 20:25:14126// Tests that we don't override events when bindings are re-injected.
127// Regression test for http://crbug.com/269149.
rpaquay96bf3b7d2014-11-26 00:19:08128// Regression test for http://crbug.com/436593.
Henrik Grunell6b7d9db2017-06-14 10:27:20129// Flaky on Mac. http://crbug.com/733064.
Giovanni Ortuño Urquidi7ce215452017-06-14 03:34:08130#if defined(OS_MACOSX)
131#define MAYBE_EventOverriding DISABLED_EventOverriding
132#else
133#define MAYBE_EventOverriding EventOverriding
134#endif
Devlin Croninc3a1e5072017-08-17 17:02:49135IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, MAYBE_EventOverriding) {
[email protected]fc034482013-08-09 20:25:14136 ASSERT_TRUE(RunExtensionTest("bindings/event_overriding")) << message_;
rdevlin.cronind734f682017-06-13 21:23:11137 // The extension test removes a window and, during window removal, sends the
138 // success message. Make sure we flush all pending tasks.
139 base::RunLoop().RunUntilIdle();
[email protected]fc034482013-08-09 20:25:14140}
141
kalman1bd5b182015-01-13 19:01:18142// Tests the effectiveness of the 'nocompile' feature file property.
143// Regression test for http://crbug.com/356133.
Devlin Croninc3a1e5072017-08-17 17:02:49144IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, Nocompile) {
kalman1bd5b182015-01-13 19:01:18145 ASSERT_TRUE(RunExtensionSubtest("bindings/nocompile", "page.html"))
146 << message_;
147}
148
Devlin Croninc3a1e5072017-08-17 17:02:49149IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, ApiEnums) {
rdevlin.cronin2ba3c88d2015-03-03 01:18:22150 ASSERT_TRUE(RunExtensionTest("bindings/api_enums")) << message_;
151};
152
jochen7923c2a2015-07-14 10:04:45153// Regression test for http://crbug.com/504011 - proper access checks on
154// getModuleSystem().
Devlin Croninc3a1e5072017-08-17 17:02:49155IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, ModuleSystem) {
jochen7923c2a2015-07-14 10:04:45156 ASSERT_TRUE(RunExtensionTest("bindings/module_system")) << message_;
157}
158
Devlin Croninc3a1e5072017-08-17 17:02:49159IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, NoExportOverriding) {
rdevlin.cronin83a4b3a2015-10-28 21:43:58160 // We need to create runtime bindings in the web page. An extension that's
161 // externally connectable will do that for us.
162 ASSERT_TRUE(LoadExtension(
163 test_data_dir_.AppendASCII("bindings")
164 .AppendASCII("externally_connectable_everywhere")));
165
166 ui_test_utils::NavigateToURL(
167 browser(),
168 embedded_test_server()->GetURL(
169 "/extensions/api_test/bindings/override_exports.html"));
170
171 // See chrome/test/data/extensions/api_test/bindings/override_exports.html.
172 std::string result;
173 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
174 browser()->tab_strip_model()->GetActiveWebContents(),
175 "window.domAutomationController.send("
176 "document.getElementById('status').textContent.trim());",
177 &result));
178 EXPECT_EQ("success", result);
179}
180
Devlin Croninc3a1e5072017-08-17 17:02:49181IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, NoGinDefineOverriding) {
rdevlin.cronin415b73b2015-11-13 01:14:47182 // We need to create runtime bindings in the web page. An extension that's
183 // externally connectable will do that for us.
184 ASSERT_TRUE(LoadExtension(
185 test_data_dir_.AppendASCII("bindings")
186 .AppendASCII("externally_connectable_everywhere")));
187
188 ui_test_utils::NavigateToURL(
189 browser(),
190 embedded_test_server()->GetURL(
191 "/extensions/api_test/bindings/override_gin_define.html"));
192 ASSERT_FALSE(
193 browser()->tab_strip_model()->GetActiveWebContents()->IsCrashed());
194
195 // See chrome/test/data/extensions/api_test/bindings/override_gin_define.html.
196 std::string result;
197 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
198 browser()->tab_strip_model()->GetActiveWebContents(),
199 "window.domAutomationController.send("
200 "document.getElementById('status').textContent.trim());",
201 &result));
202 EXPECT_EQ("success", result);
203}
204
Devlin Croninc3a1e5072017-08-17 17:02:49205IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, HandlerFunctionTypeChecking) {
rdevlin.cronina5ecbc82015-10-29 23:41:29206 ui_test_utils::NavigateToURL(
207 browser(),
208 embedded_test_server()->GetURL(
209 "/extensions/api_test/bindings/handler_function_type_checking.html"));
210 content::WebContents* web_contents =
211 browser()->tab_strip_model()->GetActiveWebContents();
212 EXPECT_FALSE(web_contents->IsCrashed());
213 // See handler_function_type_checking.html.
214 std::string result;
215 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
216 web_contents,
217 "window.domAutomationController.send("
218 "document.getElementById('status').textContent.trim());",
219 &result));
220 EXPECT_EQ("success", result);
221}
222
Devlin Croninc3a1e5072017-08-17 17:02:49223IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
rdevlin.cronin75b803b2016-03-02 00:13:47224 MoreNativeFunctionInterceptionTests) {
rdevlin.cronin75b803b2016-03-02 00:13:47225 // We need to create runtime bindings in the web page. An extension that's
226 // externally connectable will do that for us.
227 ASSERT_TRUE(
228 LoadExtension(test_data_dir_.AppendASCII("bindings")
229 .AppendASCII("externally_connectable_everywhere")));
230
231 ui_test_utils::NavigateToURL(
232 browser(),
233 embedded_test_server()->GetURL(
234 "/extensions/api_test/bindings/function_interceptions.html"));
235 content::WebContents* web_contents =
236 browser()->tab_strip_model()->GetActiveWebContents();
237 EXPECT_FALSE(web_contents->IsCrashed());
238 // See function_interceptions.html.
239 std::string result;
240 EXPECT_TRUE(content::ExecuteScriptAndExtractString(
241 web_contents, "window.domAutomationController.send(window.testStatus);",
242 &result));
243 EXPECT_EQ("success", result);
244}
245
asargent79b64c32016-08-04 17:17:14246class FramesExtensionBindingsApiTest : public ExtensionBindingsApiTest {
247 public:
248 void SetUpCommandLine(base::CommandLine* command_line) override {
249 ExtensionBindingsApiTest::SetUpCommandLine(command_line);
Devlin Croninc3a1e5072017-08-17 17:02:49250 command_line->AppendSwitch(::switches::kDisablePopupBlocking);
asargent79b64c32016-08-04 17:17:14251 }
252};
253
254// This tests that web pages with iframes or child windows pointing at
255// chrome-extenison:// urls, both web_accessible and nonexistent pages, don't
256// get improper extensions bindings injected while they briefly still point at
257// about:blank and are still scriptable by their parent.
258//
259// The general idea is to load up 2 extensions, one which listens for external
260// messages ("receiver") and one which we'll try first faking messages from in
261// the web page's iframe, as well as actually send a message from later
262// ("sender").
Dave Tapuska61ed7fbb2017-09-05 21:42:08263IN_PROC_BROWSER_TEST_P(FramesExtensionBindingsApiTest, FramesBeforeNavigation) {
asargent79b64c32016-08-04 17:17:14264 // Load the sender and receiver extensions, and make sure they are ready.
265 ExtensionTestMessageListener sender_ready("sender_ready", true);
266 const Extension* sender = LoadExtension(
267 test_data_dir_.AppendASCII("bindings").AppendASCII("message_sender"));
268 ASSERT_NE(nullptr, sender);
269 ASSERT_TRUE(sender_ready.WaitUntilSatisfied());
270
271 ExtensionTestMessageListener receiver_ready("receiver_ready", false);
272 const Extension* receiver =
273 LoadExtension(test_data_dir_.AppendASCII("bindings")
274 .AppendASCII("external_message_listener"));
275 ASSERT_NE(nullptr, receiver);
276 ASSERT_TRUE(receiver_ready.WaitUntilSatisfied());
277
278 // Load the web page which tries to impersonate the sender extension via
279 // scripting iframes/child windows before they finish navigating to pages
280 // within the sender extension.
asargent79b64c32016-08-04 17:17:14281 ui_test_utils::NavigateToURL(
282 browser(),
283 embedded_test_server()->GetURL(
284 "/extensions/api_test/bindings/frames_before_navigation.html"));
285
286 bool page_success = false;
287 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
288 browser()->tab_strip_model()->GetWebContentsAt(0), "getResult()",
289 &page_success));
290 EXPECT_TRUE(page_success);
291
292 // Reply to |sender|, causing it to send a message over to |receiver|, and
293 // then ask |receiver| for the total message count. It should be 1 since
294 // |receiver| should not have received any impersonated messages.
295 sender_ready.Reply(receiver->id());
296 int message_count = 0;
297 ASSERT_TRUE(content::ExecuteScriptAndExtractInt(
298 ProcessManager::Get(profile())
299 ->GetBackgroundHostForExtension(receiver->id())
300 ->host_contents(),
301 "getMessageCountAfterReceivingRealSenderMessage()", &message_count));
302 EXPECT_EQ(1, message_count);
303}
304
Devlin Croninc3a1e5072017-08-17 17:02:49305IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, TestFreezingChrome) {
rdevlin.cronin741da002017-04-24 20:27:41306 ui_test_utils::NavigateToURL(
307 browser(), embedded_test_server()->GetURL(
308 "/extensions/api_test/bindings/freeze.html"));
309 content::WebContents* web_contents =
310 browser()->tab_strip_model()->GetActiveWebContents();
311 ASSERT_FALSE(web_contents->IsCrashed());
312}
313
rdevlin.cronine6e20022017-06-13 18:23:40314// Tests interaction with event filter parsing.
Devlin Croninc3a1e5072017-08-17 17:02:49315IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, TestEventFilterParsing) {
rdevlin.cronine6e20022017-06-13 18:23:40316 ExtensionTestMessageListener listener("ready", false);
317 ASSERT_TRUE(
318 LoadExtension(test_data_dir_.AppendASCII("bindings/event_filter")));
319 ASSERT_TRUE(listener.WaitUntilSatisfied());
320
321 ResultCatcher catcher;
322 ui_test_utils::NavigateToURL(
323 browser(), embedded_test_server()->GetURL("example.com", "/title1.html"));
324 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
325}
326
rdevlin.cronin350824d42017-06-16 14:47:35327// crbug.com/733337
Devlin Croninc3a1e5072017-08-17 17:02:49328IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, ValidationInterception) {
rdevlin.cronin350824d42017-06-16 14:47:35329 // We need to create runtime bindings in the web page. An extension that's
330 // externally connectable will do that for us.
331 ASSERT_TRUE(
332 LoadExtension(test_data_dir_.AppendASCII("bindings")
333 .AppendASCII("externally_connectable_everywhere")));
334
335 content::WebContents* web_contents =
336 browser()->tab_strip_model()->GetActiveWebContents();
337 ui_test_utils::NavigateToURL(
338 browser(),
339 embedded_test_server()->GetURL(
340 "/extensions/api_test/bindings/validation_interception.html"));
341 content::WaitForLoadStop(web_contents);
342 ASSERT_FALSE(web_contents->IsCrashed());
343 bool caught = false;
344 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
345 web_contents, "domAutomationController.send(caught)", &caught));
346 EXPECT_TRUE(caught);
347}
348
Devlin Cronin5cf20f02017-10-10 14:25:04349IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, UncaughtExceptionLogging) {
350 ASSERT_TRUE(RunExtensionTest("bindings/uncaught_exception_logging"))
351 << message_;
352}
353
Alex Moshchuke63b9e92017-10-14 00:27:22354// Verify that when a web frame embeds an extension subframe, and that subframe
355// is the only active portion of the extension, the subframe gets proper JS
356// bindings. See https://crbug.com/760341.
357IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
358 ExtensionSubframeGetsBindings) {
359 // Load an extension that does not have a background page or popup, so it
360 // won't be activated just yet.
361 const extensions::Extension* extension =
362 LoadExtension(test_data_dir_.AppendASCII("bindings")
363 .AppendASCII("extension_subframe_gets_bindings"));
364 ASSERT_TRUE(extension);
365
366 // Navigate current tab to a web URL with a subframe.
367 content::WebContents* web_contents =
368 browser()->tab_strip_model()->GetActiveWebContents();
369 ui_test_utils::NavigateToURL(browser(),
370 embedded_test_server()->GetURL("/iframe.html"));
371
372 // Navigate the subframe to the extension URL, which should activate the
373 // extension.
374 GURL extension_url(extension->GetResourceURL("page.html"));
375 ResultCatcher catcher;
376 content::NavigateIframeToURL(web_contents, "test", extension_url);
377 ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
378}
379
Devlin Croninb15c4f4e2017-12-15 21:20:11380IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
381 ExtensionListenersRemoveContext) {
382 const Extension* extension = LoadExtension(
383 test_data_dir_.AppendASCII("bindings/listeners_destroy_context"));
384 ASSERT_TRUE(extension);
385
386 ExtensionTestMessageListener listener("ready", true);
387
388 // Navigate to a web page with an iframe (the iframe is title1.html).
389 GURL main_frame_url = embedded_test_server()->GetURL("a.com", "/iframe.html");
390 ui_test_utils::NavigateToURL(browser(), main_frame_url);
391
392 content::WebContents* tab =
393 browser()->tab_strip_model()->GetActiveWebContents();
394
395 content::RenderFrameHost* main_frame = tab->GetMainFrame();
396 content::RenderFrameHost* subframe = ChildFrameAt(main_frame, 0);
397 content::RenderFrameDeletedObserver subframe_deleted(subframe);
398
399 // Wait for the extension's content script to be ready.
400 ASSERT_TRUE(listener.WaitUntilSatisfied());
401
402 // It's actually critical to the test that these frames are in the same
403 // process, because otherwise a crash in the iframe wouldn't be detectable
404 // (since we rely on JS execution in the main frame to tell if the renderer
405 // crashed - see comment below).
406 content::RenderProcessHost* main_frame_process = main_frame->GetProcess();
407 EXPECT_EQ(main_frame_process, subframe->GetProcess());
408
409 ExtensionTestMessageListener failure_listener("failed", false);
410
411 // Tell the extension to register listeners that will remove the iframe, and
412 // trigger them.
413 listener.Reply("go!");
414
415 // The frame will be deleted.
416 subframe_deleted.WaitUntilDeleted();
417
418 // Unfortunately, we don't have a good way of checking if something crashed
419 // after the frame was removed. WebContents::IsCrashed() seems like it should
420 // work, but is insufficient. Instead, use JS execution as the source of
421 // true.
422 EXPECT_FALSE(tab->IsCrashed());
423 EXPECT_EQ(main_frame_url, main_frame->GetLastCommittedURL());
424 EXPECT_EQ(main_frame_process, main_frame->GetProcess());
425 bool renderer_valid = false;
426 EXPECT_TRUE(content::ExecuteScriptAndExtractBool(
427 main_frame, "domAutomationController.send(true);", &renderer_valid));
428 EXPECT_TRUE(renderer_valid);
429 EXPECT_FALSE(failure_listener.was_satisfied());
430}
431
Devlin Croninb48b6f92018-01-12 23:17:59432IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, UseAPIsAfterContextRemoval) {
433 EXPECT_TRUE(RunExtensionTest("bindings/invalidate_context")) << message_;
434}
435
Devlin Cronin47e79042018-02-02 18:32:26436// TODO(devlin): Can this be combined with
437// ExtensionBindingsApiTest.UseAPIsAfterContextRemoval?
438IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest, UseAppAPIAfterFrameRemoval) {
439 ASSERT_TRUE(RunExtensionTest("crazy_extension"));
440}
441
Devlin Cronind2389082018-08-14 01:53:26442// Tests attaching two listeners from the same extension but different pages,
443// then removing one, and ensuring the second is still notified.
444// Regression test for https://crbug.com/868763.
445IN_PROC_BROWSER_TEST_P(
446 ExtensionBindingsApiTest,
447 MultipleEventListenersFromDifferentContextsAndTheSameExtension) {
448 // A script that listens for tab creation and populates the result in a
449 // global variable.
450 constexpr char kTestPageScript[] = R"(
451 window.tabEventId = -1;
452 function registerListener() {
453 chrome.tabs.onCreated.addListener((tab) => {
454 window.tabEventId = tab.id;
455 });
456 }
457 )";
458 TestExtensionDir test_dir;
459 test_dir.WriteManifest(R"(
460 {
461 "name": "Duplicate event listeners",
462 "manifest_version": 2,
463 "version": "0.1"
464 })");
465 test_dir.WriteFile(FILE_PATH_LITERAL("page.html"),
466 R"(<html><script src="page.js"></script></html>)");
467 test_dir.WriteFile(FILE_PATH_LITERAL("page.js"), kTestPageScript);
468
469 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
470 ASSERT_TRUE(extension);
471
472 // Set up: open two tabs to the same extension page, and wait for each to
473 // load.
474 const GURL page_url = extension->GetResourceURL("page.html");
475 ui_test_utils::NavigateToURLWithDisposition(
476 browser(), page_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
477 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
478 content::WebContents* first_tab =
479 browser()->tab_strip_model()->GetActiveWebContents();
480 ui_test_utils::NavigateToURLWithDisposition(
481 browser(), page_url, WindowOpenDisposition::NEW_FOREGROUND_TAB,
482 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
483 content::WebContents* second_tab =
484 browser()->tab_strip_model()->GetActiveWebContents();
485
486 // Initially, there are no listeners registered.
487 EventRouter* event_router = EventRouter::Get(profile());
488 EXPECT_FALSE(event_router->ExtensionHasEventListener(extension->id(),
489 "tabs.onCreated"));
490
491 // Register both lsiteners, and verify they were added.
492 ASSERT_TRUE(content::ExecuteScript(first_tab, "registerListener()"));
493 ASSERT_TRUE(content::ExecuteScript(second_tab, "registerListener()"));
494 EXPECT_TRUE(event_router->ExtensionHasEventListener(extension->id(),
495 "tabs.onCreated"));
496
497 // Close one of the extension pages.
498 constexpr bool add_to_history = false;
499 content::WebContentsDestroyedWatcher watcher(second_tab);
500 chrome::CloseWebContents(browser(), second_tab, add_to_history);
501 watcher.Wait();
502 // Hacky round trip to the renderer to flush IPCs.
503 ASSERT_TRUE(content::ExecuteScript(first_tab, ""));
504
505 // Since the second page is still open, the extension should still be
506 // registered as a listener.
507 EXPECT_TRUE(event_router->ExtensionHasEventListener(extension->id(),
508 "tabs.onCreated"));
509
510 // Open a new tab.
511 ui_test_utils::NavigateToURLWithDisposition(
512 browser(), GURL("chrome://newtab"),
513 WindowOpenDisposition::NEW_FOREGROUND_TAB,
514 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
515 content::WebContents* new_tab =
516 browser()->tab_strip_model()->GetActiveWebContents();
517
518 // The extension should have been notified about the new tab, and have
519 // recorded the result.
520 int result_tab_id = -1;
521 EXPECT_TRUE(content::ExecuteScriptAndExtractInt(
522 first_tab, "domAutomationController.send(window.tabEventId)",
523 &result_tab_id));
524 EXPECT_EQ(SessionTabHelper::IdForTab(new_tab).id(), result_tab_id);
525}
526
Devlin Croninc3d017992018-09-11 01:21:20527// Verifies that user gestures are carried through extension messages.
528IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
529 UserGestureFromExtensionMessageTest) {
530 TestExtensionDir test_dir;
531 test_dir.WriteManifest(
532 R"({
533 "name": "User Gesture Content Script",
534 "manifest_version": 2,
535 "version": "0.1",
536 "background": { "scripts": ["background.js"] },
537 "content_scripts": [{
538 "matches": ["*://*.example.com:*/*"],
539 "js": ["content_script.js"],
540 "run_at": "document_end"
541 }]
542 })");
543 test_dir.WriteFile(FILE_PATH_LITERAL("content_script.js"),
544 R"(const button = document.getElementById('go-button');
545 button.addEventListener('click', () => {
546 chrome.runtime.sendMessage('clicked');
547 });)");
548 test_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
549 R"(chrome.runtime.onMessage.addListener((message) => {
550 chrome.test.sendMessage(
551 'Clicked: ' +
552 chrome.test.isProcessingUserGesture());
553 });)");
554
555 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
556 ASSERT_TRUE(extension);
557
558 const GURL url = embedded_test_server()->GetURL(
559 "example.com", "/extensions/page_with_button.html");
560 ui_test_utils::NavigateToURL(browser(), url);
561
562 content::WebContents* tab =
563 browser()->tab_strip_model()->GetActiveWebContents();
564
565 {
566 // Passing a message without an active user gesture shouldn't result in a
567 // gesture being active on the receiving end.
568 ExtensionTestMessageListener listener(false);
569 content::EvalJsResult result =
570 content::EvalJs(tab, "document.getElementById('go-button').click()",
571 content::EXECUTE_SCRIPT_NO_USER_GESTURE);
572 EXPECT_TRUE(result.value.is_none());
573
574 EXPECT_TRUE(listener.WaitUntilSatisfied());
575 EXPECT_EQ("Clicked: false", listener.message());
576 }
577
578 {
579 // If there is an active user gesture when the message is sent, we should
580 // synthesize a user gesture on the receiving end.
581 ExtensionTestMessageListener listener(false);
582 content::EvalJsResult result =
583 content::EvalJs(tab, "document.getElementById('go-button').click()");
584 EXPECT_TRUE(result.value.is_none());
585
586 EXPECT_TRUE(listener.WaitUntilSatisfied());
587 EXPECT_EQ("Clicked: true", listener.message());
588 }
589}
590
591// Verifies that user gestures from API calls are active when the callback is
592// triggered.
593IN_PROC_BROWSER_TEST_P(ExtensionBindingsApiTest,
594 UserGestureInExtensionAPICallback) {
595 TestExtensionDir test_dir;
596 test_dir.WriteManifest(
597 R"({
598 "name": "User Gesture Extension API Callback",
599 "manifest_version": 2,
600 "version": "0.1"
601 })");
602 test_dir.WriteFile(FILE_PATH_LITERAL("page.html"), "<html></html>");
603
604 const Extension* extension = LoadExtension(test_dir.UnpackedPath());
605 ASSERT_TRUE(extension);
606
607 const GURL extension_page = extension->GetResourceURL("page.html");
608 ui_test_utils::NavigateToURL(browser(), extension_page);
609
610 content::WebContents* tab =
611 browser()->tab_strip_model()->GetActiveWebContents();
612
613 constexpr char kScript[] =
614 R"(chrome.tabs.query({}, (tabs) => {
615 let message;
616 if (chrome.runtime.lastError)
617 message = 'Unexpected error: ' + chrome.runtime.lastError;
618 else
619 message = 'Has gesture: ' + chrome.test.isProcessingUserGesture();
620 domAutomationController.send(message);
621 });)";
622
623 {
624 // Triggering an API without an active gesture shouldn't result in a
625 // gesture in the callback.
626 std::string message;
627 EXPECT_TRUE(content::ExecuteScriptWithoutUserGestureAndExtractString(
628 tab, kScript, &message));
629 EXPECT_EQ("Has gesture: false", message);
630 }
631 {
632 // If there was an active gesture at the time of the API call, there should
633 // be an active gesture in the callback.
634 std::string message;
635 EXPECT_TRUE(content::ExecuteScriptAndExtractString(tab, kScript, &message));
636 EXPECT_EQ("Has gesture: true", message);
637 }
638}
639
Devlin Croninc3a1e5072017-08-17 17:02:49640// Run core bindings API tests with both native and JS-based bindings. This
641// ensures we have some minimum level of coverage while in the experimental
642// phase, when native bindings may be enabled on trunk but not at 100% stable.
643INSTANTIATE_TEST_CASE_P(Native,
644 ExtensionBindingsApiTest,
645 ::testing::Values(NATIVE_BINDINGS));
646INSTANTIATE_TEST_CASE_P(JavaScript,
647 ExtensionBindingsApiTest,
648 ::testing::Values(JAVASCRIPT_BINDINGS));
649
650INSTANTIATE_TEST_CASE_P(Native,
651 FramesExtensionBindingsApiTest,
652 ::testing::Values(NATIVE_BINDINGS));
653INSTANTIATE_TEST_CASE_P(JavaScript,
654 FramesExtensionBindingsApiTest,
655 ::testing::Values(JAVASCRIPT_BINDINGS));
656
[email protected]adafe5b2013-08-09 10:35:04657} // namespace
658} // namespace extensions