Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / extensions / content_script_apitest.cc
blob3f09251f8743173d6586fb97fb0a1da1051f3210
1 // Copyright (c) 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.
5 #include "base/bind.h"
6 #include "base/callback.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/strings/utf_string_conversions.h"
9 #include "chrome/browser/extensions/api/permissions/permissions_api.h"
10 #include "chrome/browser/extensions/extension_apitest.h"
11 #include "chrome/browser/extensions/extension_service.h"
12 #include "chrome/browser/extensions/test_extension_dir.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/tabs/tab_strip_model.h"
15 #include "chrome/common/chrome_switches.h"
16 #include "chrome/test/base/ui_test_utils.h"
17 #include "components/app_modal/javascript_dialog_extensions_client.h"
18 #include "components/app_modal/javascript_dialog_manager.h"
19 #include "content/public/browser/javascript_dialog_manager.h"
20 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/web_contents.h"
22 #include "content/public/browser/web_contents_delegate.h"
23 #include "content/public/test/browser_test_utils.h"
24 #include "extensions/browser/notification_types.h"
25 #include "extensions/common/extension.h"
26 #include "extensions/test/extension_test_message_listener.h"
27 #include "extensions/test/result_catcher.h"
28 #include "net/dns/mock_host_resolver.h"
29 #include "net/test/embedded_test_server/embedded_test_server.h"
30 #include "url/gurl.h"
32 namespace extensions {
34 namespace {
36 // A fake webstore domain.
37 const char kWebstoreDomain[] = "cws.com";
39 // Check whether or not style was injected, with |expected_injection| indicating
40 // the expected result. Also ensure that no CSS was added to the
41 // document.styleSheets array.
42 testing::AssertionResult CheckStyleInjection(Browser* browser,
43 const GURL& url,
44 bool expected_injection) {
45 ui_test_utils::NavigateToURL(browser, url);
47 bool css_injected = false;
48 if (!content::ExecuteScriptAndExtractBool(
49 browser->tab_strip_model()->GetActiveWebContents(),
50 "window.domAutomationController.send("
51 " document.defaultView.getComputedStyle(document.body, null)."
52 " getPropertyValue('display') == 'none');",
53 &css_injected)) {
54 return testing::AssertionFailure()
55 << "Failed to execute script and extract bool for injection status.";
58 if (css_injected != expected_injection) {
59 std::string message;
60 if (css_injected)
61 message = "CSS injected when no injection was expected.";
62 else
63 message = "CSS not injected when injection was expected.";
64 return testing::AssertionFailure() << message;
67 bool css_doesnt_add_to_list = false;
68 if (!content::ExecuteScriptAndExtractBool(
69 browser->tab_strip_model()->GetActiveWebContents(),
70 "window.domAutomationController.send("
71 " document.styleSheets.length == 0);",
72 &css_doesnt_add_to_list)) {
73 return testing::AssertionFailure()
74 << "Failed to execute script and extract bool for stylesheets length.";
76 if (!css_doesnt_add_to_list) {
77 return testing::AssertionFailure()
78 << "CSS injection added to number of stylesheets.";
81 return testing::AssertionSuccess();
84 class DialogClient;
86 // A helper class to hijack the dialog manager's ExtensionsClient, so that we
87 // know when dialogs are being opened.
88 // NOTE: The default implementation of the JavaScriptDialogExtensionsClient
89 // doesn't do anything, so it's safe to override it. If, at some stage, this
90 // has behavior (like if we move this into app shell), we'll need to update
91 // this (by, e.g., making DialogClient a wrapper around the implementation).
92 class DialogHelper {
93 public:
94 explicit DialogHelper(content::WebContents* web_contents);
95 ~DialogHelper();
97 // Notifies the DialogHelper that a dialog was opened. Runs |quit_closure_|,
98 // if it is non-null.
99 void DialogOpened();
101 // Closes any active dialogs.
102 void CloseDialogs();
104 void set_quit_closure(const base::Closure& quit_closure) {
105 quit_closure_ = quit_closure;
107 size_t dialog_count() const { return dialog_count_; }
109 private:
110 // The number of dialogs to appear.
111 size_t dialog_count_;
113 // The WebContents this helper is associated with.
114 content::WebContents* web_contents_;
116 // The dialog manager for |web_contents_|.
117 content::JavaScriptDialogManager* dialog_manager_;
119 // The dialog client override.
120 DialogClient* client_;
122 // The quit closure to run when a dialog appears.
123 base::Closure quit_closure_;
125 DISALLOW_COPY_AND_ASSIGN(DialogHelper);
128 // The client override for the DialogHelper.
129 class DialogClient : public app_modal::JavaScriptDialogExtensionsClient {
130 public:
131 explicit DialogClient(DialogHelper* helper) : helper_(helper) {}
132 ~DialogClient() override {}
134 void set_helper(DialogHelper* helper) { helper_ = helper; }
136 private:
137 // app_modal::JavaScriptDialogExtensionsClient:
138 void OnDialogOpened(content::WebContents* web_contents) override {
139 if (helper_)
140 helper_->DialogOpened();
142 void OnDialogClosed(content::WebContents* web_contents) override {}
143 bool GetExtensionName(content::WebContents* web_contents,
144 const GURL& origin_url,
145 std::string* name_out) override {
146 return false;
149 // The dialog helper to notify of any open dialogs.
150 DialogHelper* helper_;
152 DISALLOW_COPY_AND_ASSIGN(DialogClient);
155 DialogHelper::DialogHelper(content::WebContents* web_contents)
156 : dialog_count_(0),
157 web_contents_(web_contents),
158 dialog_manager_(nullptr),
159 client_(nullptr) {
160 app_modal::JavaScriptDialogManager* dialog_manager_impl =
161 app_modal::JavaScriptDialogManager::GetInstance();
162 dialog_manager_ =
163 web_contents_->GetDelegate()->GetJavaScriptDialogManager(web_contents_);
164 DCHECK_EQ(dialog_manager_impl, dialog_manager_);
166 client_ = new DialogClient(this);
167 dialog_manager_impl->SetExtensionsClient(make_scoped_ptr(client_));
170 DialogHelper::~DialogHelper() {
171 client_->set_helper(nullptr);
174 void DialogHelper::CloseDialogs() {
175 dialog_manager_->CancelActiveAndPendingDialogs(web_contents_);
178 void DialogHelper::DialogOpened() {
179 ++dialog_count_;
180 if (!quit_closure_.is_null()) {
181 quit_closure_.Run();
182 quit_closure_ = base::Closure();
186 // Runs all pending tasks in the renderer associated with |web_contents|, and
187 // then all pending tasks in the browser process.
188 // Returns true on success.
189 bool RunAllPending(content::WebContents* web_contents) {
190 // This is slight hack to achieve a RunPendingInRenderer() method. Since IPCs
191 // are sent synchronously, anything started prior to this method will finish
192 // before this method returns (as content::ExecuteScript() is synchronous).
193 if (!content::ExecuteScript(web_contents, "1 == 1;"))
194 return false;
195 base::RunLoop().RunUntilIdle();
196 return true;
199 // A simple extension manifest with content scripts on all pages.
200 const char kManifest[] =
202 " \"name\": \"%s\","
203 " \"version\": \"1.0\","
204 " \"manifest_version\": 2,"
205 " \"content_scripts\": [{"
206 " \"matches\": [\"*://*/*\"],"
207 " \"js\": [\"script.js\"],"
208 " \"run_at\": \"%s\""
209 " }]"
210 "}";
212 // A (blocking) content script that pops up an alert.
213 const char kBlockingScript[] = "alert('ALERT');";
215 // A (non-blocking) content script that sends a message.
216 const char kNonBlockingScript[] = "chrome.test.sendMessage('done');";
218 const char kNewTabOverrideManifest[] =
220 " \"name\": \"New tab override\","
221 " \"version\": \"0.1\","
222 " \"manifest_version\": 2,"
223 " \"description\": \"Foo!\","
224 " \"chrome_url_overrides\": {\"newtab\": \"newtab.html\"}"
225 "}";
227 const char kNewTabHtml[] = "<html>NewTabOverride!</html>";
229 } // namespace
231 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAllFrames) {
232 ASSERT_TRUE(StartEmbeddedTestServer());
233 ASSERT_TRUE(RunExtensionTest("content_scripts/all_frames")) << message_;
236 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAboutBlankIframes) {
237 ASSERT_TRUE(StartEmbeddedTestServer());
238 ASSERT_TRUE(
239 RunExtensionTest("content_scripts/about_blank_iframes")) << message_;
242 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptAboutBlankAndSrcdoc) {
243 // The optional "*://*/*" permission is requested after verifying that
244 // content script insertion solely depends on content_scripts[*].matches.
245 // The permission is needed for chrome.tabs.executeScript tests.
246 PermissionsRequestFunction::SetAutoConfirmForTests(true);
247 PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
249 ASSERT_TRUE(StartEmbeddedTestServer());
250 ASSERT_TRUE(RunExtensionTest("content_scripts/about_blank_srcdoc"))
251 << message_;
254 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionIframe) {
255 ASSERT_TRUE(StartEmbeddedTestServer());
256 ASSERT_TRUE(RunExtensionTest("content_scripts/extension_iframe")) << message_;
259 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionProcess) {
260 ASSERT_TRUE(StartEmbeddedTestServer());
261 ASSERT_TRUE(
262 RunExtensionTest("content_scripts/extension_process")) << message_;
265 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptFragmentNavigation) {
266 ASSERT_TRUE(StartEmbeddedTestServer());
267 const char extension_name[] = "content_scripts/fragment";
268 ASSERT_TRUE(RunExtensionTest(extension_name)) << message_;
271 // Times out on Linux: http://crbug.com/163097
272 #if defined(OS_LINUX)
273 #define MAYBE_ContentScriptIsolatedWorlds DISABLED_ContentScriptIsolatedWorlds
274 #else
275 #define MAYBE_ContentScriptIsolatedWorlds ContentScriptIsolatedWorlds
276 #endif
277 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_ContentScriptIsolatedWorlds) {
278 // This extension runs various bits of script and tests that they all run in
279 // the same isolated world.
280 ASSERT_TRUE(StartEmbeddedTestServer());
281 ASSERT_TRUE(RunExtensionTest("content_scripts/isolated_world1")) << message_;
283 // Now load a different extension, inject into same page, verify worlds aren't
284 // shared.
285 ASSERT_TRUE(RunExtensionTest("content_scripts/isolated_world2")) << message_;
288 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptIgnoreHostPermissions) {
289 host_resolver()->AddRule("a.com", "127.0.0.1");
290 host_resolver()->AddRule("b.com", "127.0.0.1");
291 ASSERT_TRUE(StartEmbeddedTestServer());
292 ASSERT_TRUE(RunExtensionTest(
293 "content_scripts/dont_match_host_permissions")) << message_;
296 // crbug.com/39249 -- content scripts js should not run on view source.
297 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptViewSource) {
298 ASSERT_TRUE(StartEmbeddedTestServer());
299 ASSERT_TRUE(RunExtensionTest("content_scripts/view_source")) << message_;
302 // crbug.com/126257 -- content scripts should not get injected into other
303 // extensions.
304 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptOtherExtensions) {
305 host_resolver()->AddRule("a.com", "127.0.0.1");
306 ASSERT_TRUE(StartEmbeddedTestServer());
307 // First, load extension that sets up content script.
308 ASSERT_TRUE(RunExtensionTest("content_scripts/other_extensions/injector"))
309 << message_;
310 // Then load targeted extension to make sure its content isn't changed.
311 ASSERT_TRUE(RunExtensionTest("content_scripts/other_extensions/victim"))
312 << message_;
315 class ContentScriptCssInjectionTest : public ExtensionApiTest {
316 protected:
317 // TODO(rdevlin.cronin): Make a testing switch that looks like FeatureSwitch,
318 // but takes in an optional value so that we don't have to do this.
319 void SetUpCommandLine(base::CommandLine* command_line) override {
320 ExtensionApiTest::SetUpCommandLine(command_line);
321 // We change the Webstore URL to be http://cws.com. We need to do this so
322 // we can check that css injection is not allowed on the webstore (which
323 // could lead to spoofing). Unfortunately, host_resolver seems to have
324 // problems with redirecting "chrome.google.com" to the test server, so we
325 // can't use the real Webstore's URL. If this changes, we could clean this
326 // up.
327 command_line->AppendSwitchASCII(
328 switches::kAppsGalleryURL,
329 base::StringPrintf("http://%s", kWebstoreDomain));
333 IN_PROC_BROWSER_TEST_F(ContentScriptCssInjectionTest,
334 ContentScriptInjectsStyles) {
335 ASSERT_TRUE(StartEmbeddedTestServer());
336 host_resolver()->AddRule(kWebstoreDomain, "127.0.0.1");
338 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("content_scripts")
339 .AppendASCII("css_injection")));
341 // CSS injection should be allowed on an aribitrary web page.
342 GURL url =
343 embedded_test_server()->GetURL("/extensions/test_file_with_body.html");
344 EXPECT_TRUE(CheckStyleInjection(browser(), url, true));
346 // The loaded extension has an exclude match for "extensions/test_file.html",
347 // so no CSS should be injected.
348 url = embedded_test_server()->GetURL("/extensions/test_file.html");
349 EXPECT_TRUE(CheckStyleInjection(browser(), url, false));
351 // We disallow all injection on the webstore.
352 GURL::Replacements replacements;
353 replacements.SetHostStr(kWebstoreDomain);
354 url = embedded_test_server()->GetURL("/extensions/test_file_with_body.html")
355 .ReplaceComponents(replacements);
356 EXPECT_TRUE(CheckStyleInjection(browser(), url, false));
359 // crbug.com/120762
360 IN_PROC_BROWSER_TEST_F(
361 ExtensionApiTest,
362 DISABLED_ContentScriptStylesInjectedIntoExistingRenderers) {
363 ASSERT_TRUE(StartEmbeddedTestServer());
365 content::WindowedNotificationObserver signal(
366 extensions::NOTIFICATION_USER_SCRIPTS_UPDATED,
367 content::Source<Profile>(browser()->profile()));
369 // Start with a renderer already open at a URL.
370 GURL url(test_server()->GetURL("file/extensions/test_file.html"));
371 ui_test_utils::NavigateToURL(browser(), url);
373 LoadExtension(
374 test_data_dir_.AppendASCII("content_scripts/existing_renderers"));
376 signal.Wait();
378 // And check that its styles were affected by the styles that just got loaded.
379 bool styles_injected;
380 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
381 browser()->tab_strip_model()->GetActiveWebContents(),
382 "window.domAutomationController.send("
383 " document.defaultView.getComputedStyle(document.body, null)."
384 " getPropertyValue('background-color') == 'rgb(255, 0, 0)')",
385 &styles_injected));
386 ASSERT_TRUE(styles_injected);
389 IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
390 ContentScriptCSSLocalization) {
391 ASSERT_TRUE(StartEmbeddedTestServer());
392 ASSERT_TRUE(RunExtensionTest("content_scripts/css_l10n")) << message_;
395 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptExtensionAPIs) {
396 ASSERT_TRUE(StartEmbeddedTestServer());
398 const extensions::Extension* extension = LoadExtension(
399 test_data_dir_.AppendASCII("content_scripts/extension_api"));
401 ResultCatcher catcher;
402 ui_test_utils::NavigateToURL(
403 browser(),
404 embedded_test_server()->GetURL(
405 "/extensions/api_test/content_scripts/extension_api/functions.html"));
406 EXPECT_TRUE(catcher.GetNextResult());
408 // Navigate to a page that will cause a content script to run that starts
409 // listening for an extension event.
410 ui_test_utils::NavigateToURL(
411 browser(),
412 embedded_test_server()->GetURL(
413 "/extensions/api_test/content_scripts/extension_api/events.html"));
415 // Navigate to an extension page that will fire the event events.js is
416 // listening for.
417 ui_test_utils::NavigateToURLWithDisposition(
418 browser(), extension->GetResourceURL("fire_event.html"),
419 NEW_FOREGROUND_TAB, ui_test_utils::BROWSER_TEST_NONE);
420 EXPECT_TRUE(catcher.GetNextResult());
423 // Flaky on Windows. http://crbug.com/248418
424 #if defined(OS_WIN)
425 #define MAYBE_ContentScriptPermissionsApi DISABLED_ContentScriptPermissionsApi
426 #else
427 #define MAYBE_ContentScriptPermissionsApi ContentScriptPermissionsApi
428 #endif
429 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_ContentScriptPermissionsApi) {
430 extensions::PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
431 extensions::PermissionsRequestFunction::SetAutoConfirmForTests(true);
432 host_resolver()->AddRule("*.com", "127.0.0.1");
433 ASSERT_TRUE(StartEmbeddedTestServer());
434 ASSERT_TRUE(RunExtensionTest("content_scripts/permissions")) << message_;
437 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptBypassPageCSP) {
438 ASSERT_TRUE(StartEmbeddedTestServer());
439 ASSERT_TRUE(RunExtensionTest("content_scripts/bypass_page_csp")) << message_;
442 // Test that when injecting a blocking content script, other scripts don't run
443 // until the blocking script finishes.
444 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptBlockingScript) {
445 ASSERT_TRUE(StartEmbeddedTestServer());
447 // Load up two extensions.
448 TestExtensionDir ext_dir1;
449 ext_dir1.WriteManifest(
450 base::StringPrintf(kManifest, "ext1", "document_start"));
451 ext_dir1.WriteFile(FILE_PATH_LITERAL("script.js"), kBlockingScript);
452 const Extension* ext1 = LoadExtension(ext_dir1.unpacked_path());
453 ASSERT_TRUE(ext1);
455 TestExtensionDir ext_dir2;
456 ext_dir2.WriteManifest(base::StringPrintf(kManifest, "ext2", "document_end"));
457 ext_dir2.WriteFile(FILE_PATH_LITERAL("script.js"), kNonBlockingScript);
458 const Extension* ext2 = LoadExtension(ext_dir2.unpacked_path());
459 ASSERT_TRUE(ext2);
461 content::WebContents* web_contents =
462 browser()->tab_strip_model()->GetActiveWebContents();
463 DialogHelper dialog_helper(web_contents);
464 base::RunLoop run_loop;
465 dialog_helper.set_quit_closure(run_loop.QuitClosure());
467 ExtensionTestMessageListener listener("done", false);
468 listener.set_extension_id(ext2->id());
470 // Navigate! Both extensions will try to inject.
471 ui_test_utils::NavigateToURLWithDisposition(
472 browser(),
473 embedded_test_server()->GetURL("/empty.html"),
474 CURRENT_TAB,
475 ui_test_utils::BROWSER_TEST_NONE);
477 run_loop.Run();
478 // Right now, the alert dialog is showing and blocking injection of anything
479 // after it, so the listener shouldn't be satisfied.
480 EXPECT_TRUE(RunAllPending(web_contents));
481 EXPECT_FALSE(listener.was_satisfied());
482 EXPECT_EQ(1u, dialog_helper.dialog_count());
483 dialog_helper.CloseDialogs();
485 // After closing the dialog, the rest of the scripts should be able to
486 // inject.
487 EXPECT_TRUE(listener.WaitUntilSatisfied());
490 // Test that closing a tab with a blocking script results in no further scripts
491 // running (and we don't crash).
492 IN_PROC_BROWSER_TEST_F(ExtensionApiTest, ContentScriptBlockingScriptTabClosed) {
493 ASSERT_TRUE(StartEmbeddedTestServer());
495 // We're going to close a tab in this test, so make a new one (to ensure
496 // we don't close the browser).
497 ui_test_utils::NavigateToURLWithDisposition(
498 browser(),
499 embedded_test_server()->GetURL("/empty.html"),
500 NEW_FOREGROUND_TAB,
501 ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
503 // Set up the same as the previous test case.
504 TestExtensionDir ext_dir1;
505 ext_dir1.WriteManifest(
506 base::StringPrintf(kManifest, "ext1", "document_start"));
507 ext_dir1.WriteFile(FILE_PATH_LITERAL("script.js"), kBlockingScript);
508 const Extension* ext1 = LoadExtension(ext_dir1.unpacked_path());
509 ASSERT_TRUE(ext1);
511 TestExtensionDir ext_dir2;
512 ext_dir2.WriteManifest(base::StringPrintf(kManifest, "ext2", "document_end"));
513 ext_dir2.WriteFile(FILE_PATH_LITERAL("script.js"), kNonBlockingScript);
514 const Extension* ext2 = LoadExtension(ext_dir2.unpacked_path());
515 ASSERT_TRUE(ext2);
517 content::WebContents* web_contents =
518 browser()->tab_strip_model()->GetActiveWebContents();
519 DialogHelper dialog_helper(web_contents);
520 base::RunLoop run_loop;
521 dialog_helper.set_quit_closure(run_loop.QuitClosure());
523 ExtensionTestMessageListener listener("done", false);
524 listener.set_extension_id(ext2->id());
526 // Navitate!
527 ui_test_utils::NavigateToURLWithDisposition(
528 browser(),
529 embedded_test_server()->GetURL("/empty.html"),
530 CURRENT_TAB,
531 ui_test_utils::BROWSER_TEST_NONE);
533 // Now, instead of closing the dialog, just close the tab. Later scripts
534 // should never get a chance to run (and we shouldn't crash).
535 run_loop.Run();
536 EXPECT_TRUE(RunAllPending(web_contents));
537 EXPECT_FALSE(listener.was_satisfied());
538 EXPECT_TRUE(browser()->tab_strip_model()->CloseWebContentsAt(
539 browser()->tab_strip_model()->active_index(), 0));
540 EXPECT_FALSE(listener.was_satisfied());
543 // There was a bug by which content scripts that blocked and ran on
544 // document_idle could be injected twice (crbug.com/431263). Test for
545 // regression.
546 IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
547 ContentScriptBlockingScriptsDontRunTwice) {
548 ASSERT_TRUE(StartEmbeddedTestServer());
550 // Load up an extension.
551 TestExtensionDir ext_dir1;
552 ext_dir1.WriteManifest(
553 base::StringPrintf(kManifest, "ext1", "document_idle"));
554 ext_dir1.WriteFile(FILE_PATH_LITERAL("script.js"), kBlockingScript);
555 const Extension* ext1 = LoadExtension(ext_dir1.unpacked_path());
556 ASSERT_TRUE(ext1);
558 content::WebContents* web_contents =
559 browser()->tab_strip_model()->GetActiveWebContents();
560 DialogHelper dialog_helper(web_contents);
561 base::RunLoop run_loop;
562 dialog_helper.set_quit_closure(run_loop.QuitClosure());
564 // Navigate!
565 ui_test_utils::NavigateToURLWithDisposition(
566 browser(),
567 embedded_test_server()->GetURL("/empty.html"),
568 CURRENT_TAB,
569 ui_test_utils::BROWSER_TEST_NONE);
571 run_loop.Run();
573 // The extension will have injected at idle, but it should only inject once.
574 EXPECT_TRUE(RunAllPending(web_contents));
575 EXPECT_EQ(1u, dialog_helper.dialog_count());
576 dialog_helper.CloseDialogs();
577 EXPECT_TRUE(RunAllPending(web_contents));
578 EXPECT_EQ(1u, dialog_helper.dialog_count());
581 // Bug fix for crbug.com/507461.
582 IN_PROC_BROWSER_TEST_F(ExtensionApiTest,
583 DocumentStartInjectionFromExtensionTabNavigation) {
584 ASSERT_TRUE(StartEmbeddedTestServer());
586 TestExtensionDir new_tab_override_dir;
587 new_tab_override_dir.WriteManifest(kNewTabOverrideManifest);
588 new_tab_override_dir.WriteFile(FILE_PATH_LITERAL("newtab.html"), kNewTabHtml);
589 const Extension* new_tab_override =
590 LoadExtension(new_tab_override_dir.unpacked_path());
591 ASSERT_TRUE(new_tab_override);
593 TestExtensionDir injector_dir;
594 injector_dir.WriteManifest(
595 base::StringPrintf(kManifest, "injector", "document_start"));
596 injector_dir.WriteFile(FILE_PATH_LITERAL("script.js"), kNonBlockingScript);
597 const Extension* injector = LoadExtension(injector_dir.unpacked_path());
598 ASSERT_TRUE(injector);
600 ExtensionTestMessageListener listener("done", false);
601 AddTabAtIndex(0, GURL("chrome://newtab"), ui::PAGE_TRANSITION_LINK);
602 browser()->tab_strip_model()->ActivateTabAt(0, false);
603 content::WebContents* tab_contents =
604 browser()->tab_strip_model()->GetActiveWebContents();
606 EXPECT_EQ(new_tab_override->GetResourceURL("newtab.html"),
607 tab_contents->GetMainFrame()->GetLastCommittedURL());
608 EXPECT_FALSE(listener.was_satisfied());
609 listener.Reset();
611 ui_test_utils::NavigateToURLWithDisposition(
612 browser(), embedded_test_server()->GetURL("/empty.html"),
613 CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
614 base::RunLoop().RunUntilIdle();
615 EXPECT_TRUE(listener.was_satisfied());
618 } // namespace extensions