extension_browsertest.cc revision 116680a4aac90f2aa7413d9095a592090648e557
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.
4
5#include "chrome/browser/extensions/extension_browsertest.h"
6
7#include <vector>
8
9#include "base/command_line.h"
10#include "base/file_util.h"
11#include "base/files/file_path.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/chrome_notification_types.h"
18#include "chrome/browser/extensions/browsertest_util.h"
19#include "chrome/browser/extensions/component_loader.h"
20#include "chrome/browser/extensions/crx_installer.h"
21#include "chrome/browser/extensions/extension_creator.h"
22#include "chrome/browser/extensions/extension_error_reporter.h"
23#include "chrome/browser/extensions/extension_install_prompt.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/profiles/profile.h"
29#include "chrome/browser/profiles/profile_manager.h"
30#include "chrome/browser/ui/browser.h"
31#include "chrome/browser/ui/browser_window.h"
32#include "chrome/browser/ui/tabs/tab_strip_model.h"
33#include "chrome/common/chrome_paths.h"
34#include "chrome/common/chrome_switches.h"
35#include "chrome/common/chrome_version_info.h"
36#include "chrome/test/base/ui_test_utils.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 "extensions/browser/extension_host.h"
44#include "extensions/browser/extension_prefs.h"
45#include "extensions/browser/extension_system.h"
46#include "extensions/common/constants.h"
47#include "extensions/common/extension_set.h"
48#include "sync/api/string_ordinal.h"
49
50#if defined(OS_CHROMEOS)
51#include "chromeos/chromeos_switches.h"
52#endif
53
54using extensions::Extension;
55using extensions::ExtensionCreator;
56using extensions::FeatureSwitch;
57using extensions::Manifest;
58
59ExtensionBrowserTest::ExtensionBrowserTest()
60    : loaded_(false),
61      installed_(false),
62#if defined(OS_CHROMEOS)
63      set_chromeos_user_(true),
64#endif
65      // Default channel is STABLE but override with UNKNOWN so that unlaunched
66      // or incomplete APIs can write tests.
67      current_channel_(chrome::VersionInfo::CHANNEL_UNKNOWN),
68      override_prompt_for_external_extensions_(
69          FeatureSwitch::prompt_for_external_extensions(),
70          false),
71      profile_(NULL) {
72  EXPECT_TRUE(temp_dir_.CreateUniqueTempDir());
73}
74
75ExtensionBrowserTest::~ExtensionBrowserTest() {
76}
77
78Profile* ExtensionBrowserTest::profile() {
79  if (!profile_) {
80    if (browser())
81      profile_ = browser()->profile();
82    else
83      profile_ = ProfileManager::GetActiveUserProfile();
84  }
85  return profile_;
86}
87
88// static
89const Extension* ExtensionBrowserTest::GetExtensionByPath(
90    const extensions::ExtensionSet* extensions, const base::FilePath& path) {
91  base::FilePath extension_path = base::MakeAbsoluteFilePath(path);
92  EXPECT_TRUE(!extension_path.empty());
93  for (extensions::ExtensionSet::const_iterator iter = extensions->begin();
94       iter != extensions->end(); ++iter) {
95    if ((*iter)->path() == extension_path) {
96      return iter->get();
97    }
98  }
99  return NULL;
100}
101
102void ExtensionBrowserTest::SetUp() {
103  test_extension_cache_.reset(new extensions::ExtensionCacheFake());
104  InProcessBrowserTest::SetUp();
105}
106
107void ExtensionBrowserTest::SetUpCommandLine(CommandLine* command_line) {
108  PathService::Get(chrome::DIR_TEST_DATA, &test_data_dir_);
109  test_data_dir_ = test_data_dir_.AppendASCII("extensions");
110  observer_.reset(new ExtensionTestNotificationObserver(browser()));
111
112#if defined(OS_CHROMEOS)
113  if (set_chromeos_user_) {
114    // This makes sure that we create the Default profile first, with no
115    // ExtensionService and then the real profile with one, as we do when
116    // running on chromeos.
117    command_line->AppendSwitchASCII(chromeos::switches::kLoginUser,
118                                    "TestUser@gmail.com");
119    command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "user");
120  }
121#endif
122}
123
124void ExtensionBrowserTest::SetUpOnMainThread() {
125  InProcessBrowserTest::SetUpOnMainThread();
126  observer_.reset(new ExtensionTestNotificationObserver(browser()));
127}
128
129const Extension* ExtensionBrowserTest::LoadExtension(
130    const base::FilePath& path) {
131  return LoadExtensionWithFlags(path, kFlagEnableFileAccess);
132}
133
134const Extension* ExtensionBrowserTest::LoadExtensionIncognito(
135    const base::FilePath& path) {
136  return LoadExtensionWithFlags(path,
137                                kFlagEnableFileAccess | kFlagEnableIncognito);
138}
139
140const Extension* ExtensionBrowserTest::LoadExtensionWithFlags(
141    const base::FilePath& path, int flags) {
142  return LoadExtensionWithInstallParam(path, flags, std::string());
143}
144
145const extensions::Extension*
146ExtensionBrowserTest::LoadExtensionWithInstallParam(
147    const base::FilePath& path,
148    int flags,
149    const std::string& install_param) {
150  ExtensionService* service = extensions::ExtensionSystem::Get(
151      profile())->extension_service();
152  {
153    observer_->Watch(chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
154                     content::NotificationService::AllSources());
155
156    scoped_refptr<extensions::UnpackedInstaller> installer(
157        extensions::UnpackedInstaller::Create(service));
158    installer->set_prompt_for_plugins(false);
159    installer->set_require_modern_manifest_version(
160        (flags & kFlagAllowOldManifestVersions) == 0);
161    installer->Load(path);
162
163    observer_->Wait();
164  }
165
166  // Find the loaded extension by its path. See crbug.com/59531 for why
167  // we cannot just use last_loaded_extension_id().
168  const Extension* extension = GetExtensionByPath(service->extensions(), path);
169  if (!extension)
170    return NULL;
171
172  if (!(flags & kFlagIgnoreManifestWarnings)) {
173    const std::vector<extensions::InstallWarning>& install_warnings =
174        extension->install_warnings();
175    if (!install_warnings.empty()) {
176      std::string install_warnings_message = base::StringPrintf(
177          "Unexpected warnings when loading test extension %s:\n",
178          path.AsUTF8Unsafe().c_str());
179
180      for (std::vector<extensions::InstallWarning>::const_iterator it =
181          install_warnings.begin(); it != install_warnings.end(); ++it) {
182        install_warnings_message += "  " + it->message + "\n";
183      }
184
185      EXPECT_EQ(0u, extension->install_warnings().size())
186          << install_warnings_message;
187      return NULL;
188    }
189  }
190
191  const std::string extension_id = extension->id();
192
193  if (!install_param.empty()) {
194    extensions::ExtensionPrefs::Get(profile())
195        ->SetInstallParam(extension_id, install_param);
196    // Re-enable the extension if needed.
197    if (service->extensions()->Contains(extension_id)) {
198      content::WindowedNotificationObserver load_signal(
199          chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
200          content::Source<Profile>(profile()));
201      // Reload the extension so that the
202      // NOTIFICATION_EXTENSION_LOADED_DEPRECATED
203      // observers may access |install_param|.
204      service->ReloadExtension(extension_id);
205      load_signal.Wait();
206      extension = service->GetExtensionById(extension_id, false);
207      CHECK(extension) << extension_id << " not found after reloading.";
208    }
209  }
210
211  // Toggling incognito or file access will reload the extension, so wait for
212  // the reload and grab the new extension instance. The default state is
213  // incognito disabled and file access enabled, so we don't wait in those
214  // cases.
215  {
216    content::WindowedNotificationObserver load_signal(
217        chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
218        content::Source<Profile>(profile()));
219    CHECK(!extensions::util::IsIncognitoEnabled(extension_id, profile()));
220
221    if (flags & kFlagEnableIncognito) {
222      extensions::util::SetIsIncognitoEnabled(extension_id, profile(), true);
223      load_signal.Wait();
224      extension = service->GetExtensionById(extension_id, false);
225      CHECK(extension) << extension_id << " not found after reloading.";
226    }
227  }
228
229  {
230    content::WindowedNotificationObserver load_signal(
231        chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
232        content::Source<Profile>(profile()));
233    CHECK(extensions::util::AllowFileAccess(extension_id, profile()));
234    if (!(flags & kFlagEnableFileAccess)) {
235      extensions::util::SetAllowFileAccess(extension_id, profile(), false);
236      load_signal.Wait();
237      extension = service->GetExtensionById(extension_id, false);
238      CHECK(extension) << extension_id << " not found after reloading.";
239    }
240  }
241
242  if (!observer_->WaitForExtensionViewsToLoad())
243    return NULL;
244
245  return extension;
246}
247
248const Extension* ExtensionBrowserTest::LoadExtensionAsComponentWithManifest(
249    const base::FilePath& path,
250    const base::FilePath::CharType* manifest_relative_path) {
251  ExtensionService* service = extensions::ExtensionSystem::Get(
252      profile())->extension_service();
253
254  std::string manifest;
255  if (!base::ReadFileToString(path.Append(manifest_relative_path), &manifest)) {
256    return NULL;
257  }
258
259  std::string extension_id = service->component_loader()->Add(manifest, path);
260  const Extension* extension = service->extensions()->GetByID(extension_id);
261  if (!extension)
262    return NULL;
263  observer_->set_last_loaded_extension_id(extension->id());
264  return extension;
265}
266
267const Extension* ExtensionBrowserTest::LoadExtensionAsComponent(
268    const base::FilePath& path) {
269  return LoadExtensionAsComponentWithManifest(path,
270                                              extensions::kManifestFilename);
271}
272
273base::FilePath ExtensionBrowserTest::PackExtension(
274    const base::FilePath& dir_path) {
275  base::FilePath crx_path = temp_dir_.path().AppendASCII("temp.crx");
276  if (!base::DeleteFile(crx_path, false)) {
277    ADD_FAILURE() << "Failed to delete crx: " << crx_path.value();
278    return base::FilePath();
279  }
280
281  // Look for PEM files with the same name as the directory.
282  base::FilePath pem_path =
283      dir_path.ReplaceExtension(FILE_PATH_LITERAL(".pem"));
284  base::FilePath pem_path_out;
285
286  if (!base::PathExists(pem_path)) {
287    pem_path = base::FilePath();
288    pem_path_out = crx_path.DirName().AppendASCII("temp.pem");
289    if (!base::DeleteFile(pem_path_out, false)) {
290      ADD_FAILURE() << "Failed to delete pem: " << pem_path_out.value();
291      return base::FilePath();
292    }
293  }
294
295  return PackExtensionWithOptions(dir_path, crx_path, pem_path, pem_path_out);
296}
297
298base::FilePath ExtensionBrowserTest::PackExtensionWithOptions(
299    const base::FilePath& dir_path,
300    const base::FilePath& crx_path,
301    const base::FilePath& pem_path,
302    const base::FilePath& pem_out_path) {
303  if (!base::PathExists(dir_path)) {
304    ADD_FAILURE() << "Extension dir not found: " << dir_path.value();
305    return base::FilePath();
306  }
307
308  if (!base::PathExists(pem_path) && pem_out_path.empty()) {
309    ADD_FAILURE() << "Must specify a PEM file or PEM output path";
310    return base::FilePath();
311  }
312
313  scoped_ptr<ExtensionCreator> creator(new ExtensionCreator());
314  if (!creator->Run(dir_path,
315                    crx_path,
316                    pem_path,
317                    pem_out_path,
318                    ExtensionCreator::kOverwriteCRX)) {
319    ADD_FAILURE() << "ExtensionCreator::Run() failed: "
320                  << creator->error_message();
321    return base::FilePath();
322  }
323
324  if (!base::PathExists(crx_path)) {
325    ADD_FAILURE() << crx_path.value() << " was not created.";
326    return base::FilePath();
327  }
328  return crx_path;
329}
330
331// This class is used to simulate an installation abort by the user.
332class MockAbortExtensionInstallPrompt : public ExtensionInstallPrompt {
333 public:
334  MockAbortExtensionInstallPrompt() : ExtensionInstallPrompt(NULL) {
335  }
336
337  // Simulate a user abort on an extension installation.
338  virtual void ConfirmInstall(
339      Delegate* delegate,
340      const Extension* extension,
341      const ShowDialogCallback& show_dialog_callback) OVERRIDE {
342    delegate->InstallUIAbort(true);
343    base::MessageLoopForUI::current()->Quit();
344  }
345
346  virtual void OnInstallSuccess(const Extension* extension,
347                                SkBitmap* icon) OVERRIDE {}
348
349  virtual void OnInstallFailure(
350      const extensions::CrxInstallerError& error) OVERRIDE {}
351};
352
353class MockAutoConfirmExtensionInstallPrompt : public ExtensionInstallPrompt {
354 public:
355  explicit MockAutoConfirmExtensionInstallPrompt(
356      content::WebContents* web_contents)
357    : ExtensionInstallPrompt(web_contents) {}
358
359  // Proceed without confirmation prompt.
360  virtual void ConfirmInstall(
361      Delegate* delegate,
362      const Extension* extension,
363      const ShowDialogCallback& show_dialog_callback) OVERRIDE {
364    delegate->InstallUIProceed();
365  }
366};
367
368const Extension* ExtensionBrowserTest::UpdateExtensionWaitForIdle(
369    const std::string& id,
370    const base::FilePath& path,
371    int expected_change) {
372  return InstallOrUpdateExtension(id,
373                                  path,
374                                  INSTALL_UI_TYPE_NONE,
375                                  expected_change,
376                                  Manifest::INTERNAL,
377                                  browser(),
378                                  Extension::NO_FLAGS,
379                                  false,
380                                  false);
381}
382
383const Extension* ExtensionBrowserTest::InstallExtensionFromWebstore(
384    const base::FilePath& path,
385    int expected_change) {
386  return InstallOrUpdateExtension(std::string(),
387                                  path,
388                                  INSTALL_UI_TYPE_NONE,
389                                  expected_change,
390                                  Manifest::INTERNAL,
391                                  browser(),
392                                  Extension::FROM_WEBSTORE,
393                                  true,
394                                  false);
395}
396
397const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
398    const std::string& id,
399    const base::FilePath& path,
400    InstallUIType ui_type,
401    int expected_change) {
402  return InstallOrUpdateExtension(id,
403                                  path,
404                                  ui_type,
405                                  expected_change,
406                                  Manifest::INTERNAL,
407                                  browser(),
408                                  Extension::NO_FLAGS,
409                                  true,
410                                  false);
411}
412
413const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
414    const std::string& id,
415    const base::FilePath& path,
416    InstallUIType ui_type,
417    int expected_change,
418    Browser* browser,
419    Extension::InitFromValueFlags creation_flags) {
420  return InstallOrUpdateExtension(id,
421                                  path,
422                                  ui_type,
423                                  expected_change,
424                                  Manifest::INTERNAL,
425                                  browser,
426                                  creation_flags,
427                                  true,
428                                  false);
429}
430
431const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
432    const std::string& id,
433    const base::FilePath& path,
434    InstallUIType ui_type,
435    int expected_change,
436    Manifest::Location install_source) {
437  return InstallOrUpdateExtension(id,
438                                  path,
439                                  ui_type,
440                                  expected_change,
441                                  install_source,
442                                  browser(),
443                                  Extension::NO_FLAGS,
444                                  true,
445                                  false);
446}
447
448const Extension* ExtensionBrowserTest::InstallOrUpdateExtension(
449    const std::string& id,
450    const base::FilePath& path,
451    InstallUIType ui_type,
452    int expected_change,
453    Manifest::Location install_source,
454    Browser* browser,
455    Extension::InitFromValueFlags creation_flags,
456    bool install_immediately,
457    bool is_ephemeral) {
458  ExtensionService* service =
459      extensions::ExtensionSystem::Get(profile())->extension_service();
460  service->set_show_extensions_prompts(false);
461  size_t num_before = service->extensions()->size();
462
463  {
464    scoped_ptr<ExtensionInstallPrompt> install_ui;
465    if (ui_type == INSTALL_UI_TYPE_CANCEL) {
466      install_ui.reset(new MockAbortExtensionInstallPrompt());
467    } else if (ui_type == INSTALL_UI_TYPE_NORMAL) {
468      install_ui.reset(new ExtensionInstallPrompt(
469          browser->tab_strip_model()->GetActiveWebContents()));
470    } else if (ui_type == INSTALL_UI_TYPE_AUTO_CONFIRM) {
471      install_ui.reset(new MockAutoConfirmExtensionInstallPrompt(
472          browser->tab_strip_model()->GetActiveWebContents()));
473    }
474
475    // TODO(tessamac): Update callers to always pass an unpacked extension
476    //                 and then always pack the extension here.
477    base::FilePath crx_path = path;
478    if (crx_path.Extension() != FILE_PATH_LITERAL(".crx")) {
479      crx_path = PackExtension(path);
480    }
481    if (crx_path.empty())
482      return NULL;
483
484    scoped_refptr<extensions::CrxInstaller> installer(
485        extensions::CrxInstaller::Create(service, install_ui.Pass()));
486    installer->set_expected_id(id);
487    installer->set_creation_flags(creation_flags);
488    installer->set_install_source(install_source);
489    installer->set_install_immediately(install_immediately);
490    installer->set_is_ephemeral(is_ephemeral);
491    if (!installer->is_gallery_install()) {
492      installer->set_off_store_install_allow_reason(
493          extensions::CrxInstaller::OffStoreInstallAllowedInTest);
494    }
495
496    observer_->Watch(
497        chrome::NOTIFICATION_CRX_INSTALLER_DONE,
498        content::Source<extensions::CrxInstaller>(installer.get()));
499
500    installer->InstallCrx(crx_path);
501
502    observer_->Wait();
503  }
504
505  size_t num_after = service->extensions()->size();
506  EXPECT_EQ(num_before + expected_change, num_after);
507  if (num_before + expected_change != num_after) {
508    VLOG(1) << "Num extensions before: " << base::IntToString(num_before)
509            << " num after: " << base::IntToString(num_after)
510            << " Installed extensions follow:";
511
512    for (extensions::ExtensionSet::const_iterator it =
513             service->extensions()->begin();
514         it != service->extensions()->end(); ++it)
515      VLOG(1) << "  " << (*it)->id();
516
517    VLOG(1) << "Errors follow:";
518    const std::vector<base::string16>* errors =
519        ExtensionErrorReporter::GetInstance()->GetErrors();
520    for (std::vector<base::string16>::const_iterator iter = errors->begin();
521         iter != errors->end(); ++iter)
522      VLOG(1) << *iter;
523
524    return NULL;
525  }
526
527  if (!observer_->WaitForExtensionViewsToLoad())
528    return NULL;
529  return service->GetExtensionById(last_loaded_extension_id(), false);
530}
531
532void ExtensionBrowserTest::ReloadExtension(const std::string extension_id) {
533  observer_->Watch(chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED,
534                   content::NotificationService::AllSources());
535
536  ExtensionService* service =
537      extensions::ExtensionSystem::Get(profile())->extension_service();
538  service->ReloadExtension(extension_id);
539
540  observer_->Wait();
541  observer_->WaitForExtensionViewsToLoad();
542}
543
544void ExtensionBrowserTest::UnloadExtension(const std::string& extension_id) {
545  ExtensionService* service = extensions::ExtensionSystem::Get(
546      profile())->extension_service();
547  service->UnloadExtension(extension_id,
548                           extensions::UnloadedExtensionInfo::REASON_DISABLE);
549}
550
551void ExtensionBrowserTest::UninstallExtension(const std::string& extension_id) {
552  ExtensionService* service = extensions::ExtensionSystem::Get(
553      profile())->extension_service();
554  service->UninstallExtension(
555      extension_id, ExtensionService::UNINSTALL_REASON_FOR_TESTING, NULL);
556}
557
558void ExtensionBrowserTest::DisableExtension(const std::string& extension_id) {
559  ExtensionService* service = extensions::ExtensionSystem::Get(
560      profile())->extension_service();
561  service->DisableExtension(extension_id, Extension::DISABLE_USER_ACTION);
562}
563
564void ExtensionBrowserTest::EnableExtension(const std::string& extension_id) {
565  ExtensionService* service = extensions::ExtensionSystem::Get(
566      profile())->extension_service();
567  service->EnableExtension(extension_id);
568}
569
570void ExtensionBrowserTest::OpenWindow(content::WebContents* contents,
571                                      const GURL& url,
572                                      bool newtab_process_should_equal_opener,
573                                      content::WebContents** newtab_result) {
574  content::WindowedNotificationObserver windowed_observer(
575      content::NOTIFICATION_LOAD_STOP,
576      content::NotificationService::AllSources());
577  ASSERT_TRUE(content::ExecuteScript(contents,
578                                     "window.open('" + url.spec() + "');"));
579
580  // The above window.open call is not user-initiated, so it will create
581  // a popup window instead of a new tab in current window.
582  // The stop notification will come from the new tab.
583  windowed_observer.Wait();
584  content::NavigationController* controller =
585      content::Source<content::NavigationController>(
586          windowed_observer.source()).ptr();
587  content::WebContents* newtab = controller->GetWebContents();
588  ASSERT_TRUE(newtab);
589  EXPECT_EQ(url, controller->GetLastCommittedEntry()->GetURL());
590  if (newtab_process_should_equal_opener)
591    EXPECT_EQ(contents->GetRenderProcessHost(), newtab->GetRenderProcessHost());
592  else
593    EXPECT_NE(contents->GetRenderProcessHost(), newtab->GetRenderProcessHost());
594
595  if (newtab_result)
596    *newtab_result = newtab;
597}
598
599void ExtensionBrowserTest::NavigateInRenderer(content::WebContents* contents,
600                                              const GURL& url) {
601  bool result = false;
602  content::WindowedNotificationObserver windowed_observer(
603      content::NOTIFICATION_LOAD_STOP,
604      content::NotificationService::AllSources());
605  ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
606      contents,
607      "window.addEventListener('unload', function() {"
608      "    window.domAutomationController.send(true);"
609      "}, false);"
610      "window.location = '" + url.spec() + "';",
611      &result));
612  ASSERT_TRUE(result);
613  windowed_observer.Wait();
614  EXPECT_EQ(url, contents->GetController().GetLastCommittedEntry()->GetURL());
615}
616
617extensions::ExtensionHost* ExtensionBrowserTest::FindHostWithPath(
618    extensions::ProcessManager* manager,
619    const std::string& path,
620    int expected_hosts) {
621  extensions::ExtensionHost* host = NULL;
622  int num_hosts = 0;
623  extensions::ProcessManager::ExtensionHostSet background_hosts =
624      manager->background_hosts();
625  for (extensions::ProcessManager::const_iterator iter =
626           background_hosts.begin();
627       iter != background_hosts.end();
628       ++iter) {
629    if ((*iter)->GetURL().path() == path) {
630      EXPECT_FALSE(host);
631      host = *iter;
632    }
633    num_hosts++;
634  }
635  EXPECT_EQ(expected_hosts, num_hosts);
636  return host;
637}
638
639std::string ExtensionBrowserTest::ExecuteScriptInBackgroundPage(
640    const std::string& extension_id,
641    const std::string& script) {
642  return extensions::browsertest_util::ExecuteScriptInBackgroundPage(
643      profile(), extension_id, script);
644}
645
646bool ExtensionBrowserTest::ExecuteScriptInBackgroundPageNoWait(
647    const std::string& extension_id,
648    const std::string& script) {
649  return extensions::browsertest_util::ExecuteScriptInBackgroundPageNoWait(
650      profile(), extension_id, script);
651}
652