Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / extensions / extension_browsertest.cc
blob002163ec357b72d069409eaf9a6bfd7e19966497
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 "chrome/browser/extensions/extension_browsertest.h"
7 #include <vector>
9 #include "base/command_line.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/path_service.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/extensions/browsertest_util.h"
18 #include "chrome/browser/extensions/component_loader.h"
19 #include "chrome/browser/extensions/crx_installer.h"
20 #include "chrome/browser/extensions/extension_creator.h"
21 #include "chrome/browser/extensions/extension_error_reporter.h"
22 #include "chrome/browser/extensions/extension_install_prompt.h"
23 #include "chrome/browser/extensions/extension_install_prompt_show_params.h"
24 #include "chrome/browser/extensions/extension_service.h"
25 #include "chrome/browser/extensions/extension_util.h"
26 #include "chrome/browser/extensions/unpacked_installer.h"
27 #include "chrome/browser/extensions/updater/extension_cache_fake.h"
28 #include "chrome/browser/extensions/updater/extension_updater.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/browser/profiles/profile_manager.h"
31 #include "chrome/browser/ui/browser.h"
32 #include "chrome/browser/ui/browser_window.h"
33 #include "chrome/browser/ui/tabs/tab_strip_model.h"
34 #include "chrome/common/chrome_paths.h"
35 #include "chrome/common/chrome_switches.h"
36 #include "chrome/common/chrome_version_info.h"
37 #include "content/public/browser/navigation_controller.h"
38 #include "content/public/browser/navigation_entry.h"
39 #include "content/public/browser/notification_registrar.h"
40 #include "content/public/browser/notification_service.h"
41 #include "content/public/browser/render_view_host.h"
42 #include "content/public/test/browser_test_utils.h"
43 #include "content/public/test/test_utils.h"
44 #include "extensions/browser/extension_host.h"
45 #include "extensions/browser/extension_prefs.h"
46 #include "extensions/browser/extension_registry.h"
47 #include "extensions/browser/extension_system.h"
48 #include "extensions/browser/notification_types.h"
49 #include "extensions/browser/uninstall_reason.h"
50 #include "extensions/common/constants.h"
51 #include "extensions/common/extension_set.h"
52 #include "sync/api/string_ordinal.h"
54 #if defined(OS_CHROMEOS)
55 #include "chromeos/chromeos_switches.h"
56 #endif
58 using extensions::Extension;
59 using extensions::ExtensionCreator;
60 using extensions::ExtensionRegistry;
61 using extensions::FeatureSwitch;
62 using extensions::Manifest;
64 ExtensionBrowserTest::ExtensionBrowserTest()
65 : loaded_(false),
66 installed_(false),
67 #if defined(OS_CHROMEOS)
68 set_chromeos_user_(true),
69 #endif
70 // Default channel is STABLE but override with UNKNOWN so that unlaunched
71 // or incomplete APIs can write tests.
72 current_channel_(chrome::VersionInfo::CHANNEL_UNKNOWN),
73 override_prompt_for_external_extensions_(
74 FeatureSwitch::prompt_for_external_extensions(),
75 false),
76 #if defined(OS_WIN)
77 user_desktop_override_(base::DIR_USER_DESKTOP),
78 common_desktop_override_(base::DIR_COMMON_DESKTOP),
79 user_quick_launch_override_(base::DIR_USER_QUICK_LAUNCH),
80 start_menu_override_(base::DIR_START_MENU),
81 common_start_menu_override_(base::DIR_COMMON_START_MENU),
82 #endif
83 profile_(NULL) {
84 EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
87 ExtensionBrowserTest::~ExtensionBrowserTest() {
90 Profile* ExtensionBrowserTest::profile() {
91 if (!profile_) {
92 if (browser())
93 profile_ = browser()->profile();
94 else
95 profile_ = ProfileManager::GetActiveUserProfile();
97 return profile_;
100 // static
101 const Extension* ExtensionBrowserTest::GetExtensionByPath(
102 const extensions::ExtensionSet& extensions,
103 const base::FilePath& path) {
104 base::FilePath extension_path = base::MakeAbsoluteFilePath(path);
105 EXPECT_TRUE(!extension_path.empty());
106 for (const scoped_refptr<const Extension>& extension : extensions) {
107 if (extension->path() == extension_path) {
108 return extension.get();
111 return NULL;
114 void ExtensionBrowserTest::SetUp() {
115 test_extension_cache_.reset(new extensions::ExtensionCacheFake());
116 InProcessBrowserTest::SetUp();
119 void ExtensionBrowserTest::SetUpCommandLine(base::CommandLine* command_line) {
120 PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
121 test_data_dir_ = test_data_dir_.AppendASCII("extensions");
122 observer_.reset(new ExtensionTestNotificationObserver(browser()));
124 #if defined(OS_CHROMEOS)
125 if (set_chromeos_user_) {
126 // This makes sure that we create the Default profile first, with no
127 // ExtensionService and then the real profile with one, as we do when
128 // running on chromeos.
129 command_line->AppendSwitchASCII(chromeos::switches::kLoginUser,
130 "TestUser@gmail.com");
131 command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
133 #endif
136 void ExtensionBrowserTest::SetUpOnMainThread() {
137 InProcessBrowserTest::SetUpOnMainThread();
138 observer_.reset(new ExtensionTestNotificationObserver(browser()));
139 if (extension_service()->updater()) {
140 extension_service()->updater()->SetExtensionCacheForTesting(
141 test_extension_cache_.get());
145 const Extension* ExtensionBrowserTest::LoadExtension(
146 const base::FilePath& path) {
147 return LoadExtensionWithFlags(path, kFlagEnableFileAccess);
150 const Extension* ExtensionBrowserTest::LoadExtensionIncognito(
151 const base::FilePath& path) {
152 return LoadExtensionWithFlags(path,
153 kFlagEnableFileAccess | kFlagEnableIncognito);
156 const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
157 const base::FilePath& path, int flags) {
158 return LoadExtensionWithInstallParam(path, flags, std::string());
161 const extensions::Extension*
162 ExtensionBrowserTest::LoadExtensionWithInstallParam(
163 const base::FilePath& path,
164 int flags,
165 const std::string& install_param) {
166 ExtensionService* service = extensions::ExtensionSystem::Get(
167 profile())->extension_service();
168 ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
170 observer_->Watch(extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
171 content::NotificationService::AllSources());
173 scoped_refptr<extensions::UnpackedInstaller> installer(
174 extensions::UnpackedInstaller::Create(service));
175 installer->set_prompt_for_plugins(false);
176 installer->set_require_modern_manifest_version(
177 (flags & kFlagAllowOldManifestVersions) == 0);
178 installer->Load(path);
180 observer_->Wait();
183 // Find the loaded extension by its path. See crbug.com/59531 for why
184 // we cannot just use last_loaded_extension_id().
185 const Extension* extension =
186 GetExtensionByPath(registry->enabled_extensions(), path);
187 if (!extension)
188 return NULL;
190 if (!(flags & kFlagIgnoreManifestWarnings)) {
191 const std::vector<extensions::InstallWarning>& install_warnings =
192 extension->install_warnings();
193 if (!install_warnings.empty()) {
194 std::string install_warnings_message = base::StringPrintf(
195 "Unexpected warnings when loading test extension %s:\n",
196 path.AsUTF8Unsafe().c_str());
198 for (std::vector<extensions::InstallWarning>::const_iterator it =
199 install_warnings.begin(); it != install_warnings.end(); ++it) {
200 install_warnings_message += " " + it->message + "\n";
203 EXPECT_EQ(0u, extension->install_warnings().size())
204 << install_warnings_message;
205 return NULL;
209 const std::string extension_id = extension->id();
211 if (!install_param.empty()) {
212 extensions::ExtensionPrefs::Get(profile())
213 ->SetInstallParam(extension_id, install_param);
214 // Re-enable the extension if needed.
215 if (registry->enabled_extensions().Contains(extension_id)) {
216 content::WindowedNotificationObserver load_signal(
217 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
218 content::Source<Profile>(profile()));
219 // Reload the extension so that the
220 // NOTIFICATION_EXTENSION_LOADED_DEPRECATED
221 // observers may access |install_param|.
222 service->ReloadExtension(extension_id);
223 load_signal.Wait();
224 extension = service->GetExtensionById(extension_id, false);
225 CHECK(extension) << extension_id << " not found after reloading.";
229 // Toggling incognito or file access will reload the extension, so wait for
230 // the reload and grab the new extension instance. The default state is
231 // incognito disabled and file access enabled, so we don't wait in those
232 // cases.
234 content::WindowedNotificationObserver load_signal(
235 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
236 content::Source<Profile>(profile()));
237 CHECK(!extensions::util::IsIncognitoEnabled(extension_id, profile()))
238 << extension_id << " is enabled in incognito, but shouldn't be";
240 if (flags & kFlagEnableIncognito) {
241 extensions::util::SetIsIncognitoEnabled(extension_id, profile(), true);
242 load_signal.Wait();
243 extension = service->GetExtensionById(extension_id, false);
244 CHECK(extension) << extension_id << " not found after reloading.";
249 content::WindowedNotificationObserver load_signal(
250 extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
251 content::Source<Profile>(profile()));
252 CHECK(extensions::util::AllowFileAccess(extension_id, profile()));
253 if (!(flags & kFlagEnableFileAccess)) {
254 extensions::util::SetAllowFileAccess(extension_id, profile(), false);
255 load_signal.Wait();
256 extension = service->GetExtensionById(extension_id, false);
257 CHECK(extension) << extension_id << " not found after reloading.";
261 if (!observer_->WaitForExtensionViewsToLoad())
262 return NULL;
264 return extension;
267 const Extension* ExtensionBrowserTest::LoadExtensionAsComponentWithManifest(
268 const base::FilePath& path,
269 const base::FilePath::CharType* manifest_relative_path) {
270 ExtensionService* service = extensions::ExtensionSystem::Get(
271 profile())->extension_service();
272 ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
274 std::string manifest;
275 if (!base::ReadFileToString(path.Append(manifest_relative_path), &manifest)) {
276 return NULL;
279 service->component_loader()->set_ignore_whitelist_for_testing(true);
280 std::string extension_id = service->component_loader()->Add(manifest, path);
281 const Extension* extension =
282 registry->enabled_extensions().GetByID(extension_id);
283 if (!extension)
284 return NULL;
285 observer_->set_last_loaded_extension_id(extension->id());
286 return extension;
289 const Extension* ExtensionBrowserTest::LoadExtensionAsComponent(
290 const base::FilePath& path) {
291 return LoadExtensionAsComponentWithManifest(path,
292 extensions::kManifestFilename);
295 base::FilePath ExtensionBrowserTest::PackExtension(
296 const base::FilePath& dir_path) {
297 base::FilePath crx_path = temp_dir_.path().AppendASCII("temp.crx");
298 if (!base::DeleteFile(crx_path, false)) {
299 ADD_FAILURE() << "Failed to delete crx: " << crx_path.value();
300 return base::FilePath();
303 // Look for PEM files with the same name as the directory.
304 base::FilePath pem_path =
305 dir_path.ReplaceExtension(FILE_PATH_LITERAL(".pem"));
306 base::FilePath pem_path_out;
308 if (!base::PathExists(pem_path)) {
309 pem_path = base::FilePath();
310 pem_path_out = crx_path.DirName().AppendASCII("temp.pem");
311 if (!base::DeleteFile(pem_path_out, false)) {
312 ADD_FAILURE() << "Failed to delete pem: " << pem_path_out.value();
313 return base::FilePath();
317 return PackExtensionWithOptions(dir_path, crx_path, pem_path, pem_path_out);
320 base::FilePath ExtensionBrowserTest::PackExtensionWithOptions(
321 const base::FilePath& dir_path,
322 const base::FilePath& crx_path,
323 const base::FilePath& pem_path,
324 const base::FilePath& pem_out_path) {
325 if (!base::PathExists(dir_path)) {
326 ADD_FAILURE() << "Extension dir not found: " << dir_path.value();
327 return base::FilePath();
330 if (!base::PathExists(pem_path) && pem_out_path.empty()) {
331 ADD_FAILURE() << "Must specify a PEM file or PEM output path";
332 return base::FilePath();
335 scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
336 if (!creator->Run(dir_path,
337 crx_path,
338 pem_path,
339 pem_out_path,
340 ExtensionCreator::kOverwriteCRX)) {
341 ADD_FAILURE() << "ExtensionCreator::Run() failed: "
342 << creator->error_message();
343 return base::FilePath();
346 if (!base::PathExists(crx_path)) {
347 ADD_FAILURE() << crx_path.value() << " was not created.";
348 return base::FilePath();
350 return crx_path;
353 // This class is used to simulate an installation abort by the user.
354 class MockAbortExtensionInstallPrompt : public ExtensionInstallPrompt {
355 public:
356 MockAbortExtensionInstallPrompt() : ExtensionInstallPrompt(NULL) {
359 // Simulate a user abort on an extension installation.
360 void ConfirmInstall(Delegate* delegate,
361 const Extension* extension,
362 const ShowDialogCallback& show_dialog_callback) override {
363 delegate->InstallUIAbort(true);
364 base::MessageLoopForUI::current()->Quit();
367 void OnInstallSuccess(const Extension* extension, SkBitmap* icon) override {}
369 void OnInstallFailure(const extensions::CrxInstallError& error) override {}
372 class MockAutoConfirmExtensionInstallPrompt : public ExtensionInstallPrompt {
373 public:
374 explicit MockAutoConfirmExtensionInstallPrompt(
375 content::WebContents* web_contents)
376 : ExtensionInstallPrompt(web_contents) {}
378 // Proceed without confirmation prompt.
379 void ConfirmInstall(Delegate* delegate,
380 const Extension* extension,
381 const ShowDialogCallback& show_dialog_callback) override {
382 delegate->InstallUIProceed();
386 const Extension* ExtensionBrowserTest::UpdateExtensionWaitForIdle(
387 const std::string& id,
388 const base::FilePath& path,
389 int expected_change) {
390 return InstallOrUpdateExtension(id,
391 path,
392 INSTALL_UI_TYPE_NONE,
393 expected_change,
394 Manifest::INTERNAL,
395 browser(),
396 Extension::NO_FLAGS,
397 false,
398 false);
401 const Extension* ExtensionBrowserTest::InstallExtensionFromWebstore(
402 const base::FilePath& path,
403 int expected_change) {
404 return InstallOrUpdateExtension(std::string(),
405 path,
406 INSTALL_UI_TYPE_NONE,
407 expected_change,
408 Manifest::INTERNAL,
409 browser(),
410 Extension::FROM_WEBSTORE,
411 true,
412 false);
415 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
416 const std::string& id,
417 const base::FilePath& path,
418 InstallUIType ui_type,
419 int expected_change) {
420 return InstallOrUpdateExtension(id,
421 path,
422 ui_type,
423 expected_change,
424 Manifest::INTERNAL,
425 browser(),
426 Extension::NO_FLAGS,
427 true,
428 false);
431 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
432 const std::string& id,
433 const base::FilePath& path,
434 InstallUIType ui_type,
435 int expected_change,
436 Browser* browser,
437 Extension::InitFromValueFlags creation_flags) {
438 return InstallOrUpdateExtension(id,
439 path,
440 ui_type,
441 expected_change,
442 Manifest::INTERNAL,
443 browser,
444 creation_flags,
445 true,
446 false);
449 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
450 const std::string& id,
451 const base::FilePath& path,
452 InstallUIType ui_type,
453 int expected_change,
454 Manifest::Location install_source) {
455 return InstallOrUpdateExtension(id,
456 path,
457 ui_type,
458 expected_change,
459 install_source,
460 browser(),
461 Extension::NO_FLAGS,
462 true,
463 false);
466 const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
467 const std::string& id,
468 const base::FilePath& path,
469 InstallUIType ui_type,
470 int expected_change,
471 Manifest::Location install_source,
472 Browser* browser,
473 Extension::InitFromValueFlags creation_flags,
474 bool install_immediately,
475 bool is_ephemeral) {
476 ExtensionService* service =
477 extensions::ExtensionSystem::Get(profile())->extension_service();
478 ExtensionRegistry* registry = ExtensionRegistry::Get(profile());
479 service->set_show_extensions_prompts(false);
480 size_t num_before = registry->enabled_extensions().size();
483 scoped_ptr<ExtensionInstallPrompt> install_ui;
484 if (ui_type == INSTALL_UI_TYPE_CANCEL) {
485 install_ui.reset(new MockAbortExtensionInstallPrompt());
486 } else if (ui_type == INSTALL_UI_TYPE_NORMAL) {
487 install_ui.reset(new ExtensionInstallPrompt(
488 browser->tab_strip_model()->GetActiveWebContents()));
489 } else if (ui_type == INSTALL_UI_TYPE_AUTO_CONFIRM) {
490 install_ui.reset(new MockAutoConfirmExtensionInstallPrompt(
491 browser->tab_strip_model()->GetActiveWebContents()));
494 // TODO(tessamac): Update callers to always pass an unpacked extension
495 // and then always pack the extension here.
496 base::FilePath crx_path = path;
497 if (crx_path.Extension() != FILE_PATH_LITERAL(".crx")) {
498 crx_path = PackExtension(path);
500 if (crx_path.empty())
501 return NULL;
503 scoped_refptr<extensions::CrxInstaller> installer(
504 extensions::CrxInstaller::Create(service, install_ui.Pass()));
505 installer->set_expected_id(id);
506 installer->set_creation_flags(creation_flags);
507 installer->set_install_source(install_source);
508 installer->set_install_immediately(install_immediately);
509 installer->set_is_ephemeral(is_ephemeral);
510 if (!installer->is_gallery_install()) {
511 installer->set_off_store_install_allow_reason(
512 extensions::CrxInstaller::OffStoreInstallAllowedInTest);
515 observer_->Watch(
516 extensions::NOTIFICATION_CRX_INSTALLER_DONE,
517 content::Source<extensions::CrxInstaller>(installer.get()));
519 installer->InstallCrx(crx_path);
521 observer_->Wait();
524 size_t num_after = registry->enabled_extensions().size();
525 EXPECT_EQ(num_before + expected_change, num_after);
526 if (num_before + expected_change != num_after) {
527 VLOG(1) << "Num extensions before: " << base::IntToString(num_before)
528 << " num after: " << base::IntToString(num_after)
529 << " Installed extensions follow:";
531 for (const scoped_refptr<const Extension>& extension :
532 registry->enabled_extensions())
533 VLOG(1) << " " << extension->id();
535 VLOG(1) << "Errors follow:";
536 const std::vector<base::string16>* errors =
537 ExtensionErrorReporter::GetInstance()->GetErrors();
538 for (std::vector<base::string16>::const_iterator iter = errors->begin();
539 iter != errors->end(); ++iter)
540 VLOG(1) << *iter;
542 return NULL;
545 if (!observer_->WaitForExtensionViewsToLoad())
546 return NULL;
547 return service->GetExtensionById(last_loaded_extension_id(), false);
550 void ExtensionBrowserTest::ReloadExtension(const std::string extension_id) {
551 observer_->Watch(extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
552 content::NotificationService::AllSources());
554 ExtensionService* service =
555 extensions::ExtensionSystem::Get(profile())->extension_service();
556 service->ReloadExtension(extension_id);
558 observer_->Wait();
559 observer_->WaitForExtensionViewsToLoad();
562 void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) {
563 ExtensionService* service = extensions::ExtensionSystem::Get(
564 profile())->extension_service();
565 service->UnloadExtension(extension_id,
566 extensions::UnloadedExtensionInfo::REASON_DISABLE);
569 void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) {
570 ExtensionService* service = extensions::ExtensionSystem::Get(
571 profile())->extension_service();
572 service->UninstallExtension(extension_id,
573 extensions::UNINSTALL_REASON_FOR_TESTING,
574 base::Bind(&base::DoNothing),
575 NULL);
578 void ExtensionBrowserTest::DisableExtension(const std::string& extension_id) {
579 ExtensionService* service = extensions::ExtensionSystem::Get(
580 profile())->extension_service();
581 service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION);
584 void ExtensionBrowserTest::EnableExtension(const std::string& extension_id) {
585 ExtensionService* service = extensions::ExtensionSystem::Get(
586 profile())->extension_service();
587 service->EnableExtension(extension_id);
590 void ExtensionBrowserTest::OpenWindow(content::WebContents* contents,
591 const GURL& url,
592 bool newtab_process_should_equal_opener,
593 content::WebContents** newtab_result) {
594 content::WindowedNotificationObserver windowed_observer(
595 content::NOTIFICATION_LOAD_STOP,
596 content::NotificationService::AllSources());
597 ASSERT_TRUE(content::ExecuteScript(contents,
598 "window.open('" + url.spec() + "');"));
600 // The above window.open call is not user-initiated, so it will create
601 // a popup window instead of a new tab in current window.
602 // The stop notification will come from the new tab.
603 windowed_observer.Wait();
604 content::NavigationController* controller =
605 content::Source<content::NavigationController>(
606 windowed_observer.source()).ptr();
607 content::WebContents* newtab = controller->GetWebContents();
608 ASSERT_TRUE(newtab);
609 EXPECT_EQ(url, controller->GetLastCommittedEntry()->GetURL());
610 if (newtab_process_should_equal_opener)
611 EXPECT_EQ(contents->GetRenderProcessHost(), newtab->GetRenderProcessHost());
612 else
613 EXPECT_NE(contents->GetRenderProcessHost(), newtab->GetRenderProcessHost());
615 if (newtab_result)
616 *newtab_result = newtab;
619 void ExtensionBrowserTest::NavigateInRenderer(content::WebContents* contents,
620 const GURL& url) {
621 // Ensure any existing navigations complete before trying to navigate anew, to
622 // avoid triggering of the unload event for the wrong navigation.
623 content::WaitForLoadStop(contents);
624 bool result = false;
625 content::WindowedNotificationObserver windowed_observer(
626 content::NOTIFICATION_LOAD_STOP,
627 content::NotificationService::AllSources());
628 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
629 contents,
630 "window.addEventListener('unload', function() {"
631 " window.domAutomationController.send(true);"
632 "}, false);"
633 "window.location = '" + url.spec() + "';",
634 &result));
635 ASSERT_TRUE(result);
636 windowed_observer.Wait();
637 EXPECT_EQ(url, contents->GetController().GetLastCommittedEntry()->GetURL());
640 extensions::ExtensionHost* ExtensionBrowserTest::FindHostWithPath(
641 extensions::ProcessManager* manager,
642 const std::string& path,
643 int expected_hosts) {
644 extensions::ExtensionHost* result_host = nullptr;
645 int num_hosts = 0;
646 for (extensions::ExtensionHost* host : manager->background_hosts()) {
647 if (host->GetURL().path() == path) {
648 EXPECT_FALSE(result_host);
649 result_host = host;
651 num_hosts++;
653 EXPECT_EQ(expected_hosts, num_hosts);
654 return result_host;
657 std::string ExtensionBrowserTest::ExecuteScriptInBackgroundPage(
658 const std::string& extension_id,
659 const std::string& script) {
660 return extensions::browsertest_util::ExecuteScriptInBackgroundPage(
661 profile(), extension_id, script);
664 bool ExtensionBrowserTest::ExecuteScriptInBackgroundPageNoWait(
665 const std::string& extension_id,
666 const std::string& script) {
667 return extensions::browsertest_util::ExecuteScriptInBackgroundPageNoWait(
668 profile(), extension_id, script);