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 <map>
6 
7 #include "base/strings/stringprintf.h"
8 #include "build/build_config.h"
9 #include "chrome/browser/extensions/extension_apitest.h"
10 #include "chrome/browser/extensions/extension_service.h"
11 #include "chrome/browser/extensions/launch_util.h"
12 #include "chrome/browser/profiles/profile.h"
13 #include "chrome/browser/ui/browser.h"
14 #include "chrome/browser/ui/browser_commands.h"
15 #include "chrome/browser/ui/browser_dialogs.h"
16 #include "chrome/browser/ui/browser_finder.h"
17 #include "chrome/browser/ui/browser_list.h"
18 #include "chrome/browser/ui/tabs/tab_strip_model.h"
19 #include "chrome/browser/web_applications/components/app_registrar.h"
20 #include "chrome/browser/web_applications/components/app_shortcut_manager.h"
21 #include "chrome/browser/web_applications/components/web_app_helpers.h"
22 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
23 #include "chrome/browser/web_applications/test/test_web_app_ui_manager.h"
24 #include "chrome/browser/web_applications/test/web_app_test.h"
25 #include "chrome/common/chrome_features.h"
26 #include "chrome/common/chrome_switches.h"
27 #include "chrome/common/extensions/extension_constants.h"
28 #include "extensions/browser/api/management/management_api.h"
29 #include "extensions/browser/extension_dialog_auto_confirm.h"
30 #include "extensions/browser/extension_registry.h"
31 #include "extensions/browser/extension_system.h"
32 #include "extensions/browser/test_management_policy.h"
33 #include "extensions/common/manifest.h"
34 #include "extensions/test/extension_test_message_listener.h"
35 #include "extensions/test/result_catcher.h"
36 #include "extensions/test/test_extension_dir.h"
37 #include "net/dns/mock_host_resolver.h"
38 
39 using extensions::Extension;
40 using extensions::Manifest;
41 using web_app::ProviderType;
42 
43 namespace {
44 
45 // Find a browser other than |browser|.
FindOtherBrowser(Browser * browser)46 Browser* FindOtherBrowser(Browser* browser) {
47   Browser* found = NULL;
48   for (auto* b : *BrowserList::GetInstance()) {
49     if (b == browser)
50       continue;
51     found = b;
52   }
53   return found;
54 }
55 
56 }  // namespace
57 
58 class ExtensionManagementApiTest : public extensions::ExtensionApiTest {
59  public:
LoadExtensions()60   virtual void LoadExtensions() {
61     base::FilePath basedir = test_data_dir_.AppendASCII("management");
62 
63     // Load 5 enabled items.
64     LoadNamedExtension(basedir, "enabled_extension");
65     LoadNamedExtension(basedir, "enabled_app");
66     LoadNamedExtension(basedir, "description");
67     LoadNamedExtension(basedir, "permissions");
68     LoadNamedExtension(basedir, "short_name");
69 
70     // Load 2 disabled items.
71     LoadNamedExtension(basedir, "disabled_extension");
72     DisableExtension(extension_ids_["disabled_extension"]);
73     LoadNamedExtension(basedir, "disabled_app");
74     DisableExtension(extension_ids_["disabled_app"]);
75   }
76 
77   // Load an app, and wait for a message that it has been launched. This should
78   // be sent by the launched app, to ensure the page is fully loaded.
LoadAndWaitForLaunch(const std::string & app_path,std::string * out_app_id)79   void LoadAndWaitForLaunch(const std::string& app_path,
80                             std::string* out_app_id) {
81     ExtensionTestMessageListener launched_app("launched app", false);
82     ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII(app_path)));
83 
84     if (out_app_id)
85       *out_app_id = last_loaded_extension_id();
86 
87     ASSERT_TRUE(launched_app.WaitUntilSatisfied());
88   }
89 
90  protected:
LoadNamedExtension(const base::FilePath & path,const std::string & name)91   void LoadNamedExtension(const base::FilePath& path,
92                           const std::string& name) {
93     const Extension* extension = LoadExtension(path.AppendASCII(name));
94     ASSERT_TRUE(extension);
95     extension_ids_[name] = extension->id();
96   }
97 
InstallNamedExtension(const base::FilePath & path,const std::string & name,Manifest::Location install_source)98   void InstallNamedExtension(const base::FilePath& path,
99                              const std::string& name,
100                              Manifest::Location install_source) {
101     const Extension* extension = InstallExtension(path.AppendASCII(name), 1,
102                                                   install_source);
103     ASSERT_TRUE(extension);
104     extension_ids_[name] = extension->id();
105   }
106 
107   // Maps installed extension names to their IDs.
108   std::map<std::string, std::string> extension_ids_;
109 };
110 
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,Basics)111 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, Basics) {
112   LoadExtensions();
113 
114   base::FilePath basedir = test_data_dir_.AppendASCII("management");
115   InstallNamedExtension(basedir, "internal_extension", Manifest::INTERNAL);
116   InstallNamedExtension(basedir, "external_extension",
117                         Manifest::EXTERNAL_PREF);
118   InstallNamedExtension(basedir, "admin_extension",
119                         Manifest::EXTERNAL_POLICY_DOWNLOAD);
120   InstallNamedExtension(basedir, "version_name", Manifest::INTERNAL);
121 
122   ASSERT_TRUE(RunExtensionSubtest("management/test", "basics.html"));
123 }
124 
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,NoPermission)125 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, NoPermission) {
126   LoadExtensions();
127   ASSERT_TRUE(RunExtensionSubtest("management/no_permission", "test.html"));
128 }
129 
130 // Disabled: http://crbug.com/174411
131 #if defined(OS_WIN)
132 #define MAYBE_Uninstall DISABLED_Uninstall
133 #else
134 #define MAYBE_Uninstall Uninstall
135 #endif
136 
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,MAYBE_Uninstall)137 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, MAYBE_Uninstall) {
138   LoadExtensions();
139   // Confirmation dialog will be shown for uninstallations except for self.
140   extensions::ScopedTestDialogAutoConfirm auto_confirm(
141       extensions::ScopedTestDialogAutoConfirm::ACCEPT);
142   ASSERT_TRUE(RunExtensionSubtest("management/test", "uninstall.html"));
143 }
144 
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,CreateAppShortcut)145 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, CreateAppShortcut) {
146   LoadExtensions();
147   base::FilePath basedir = test_data_dir_.AppendASCII("management");
148   LoadNamedExtension(basedir, "packaged_app");
149 
150   extensions::ManagementCreateAppShortcutFunction::SetAutoConfirmForTest(true);
151   ASSERT_TRUE(RunExtensionSubtest("management/test",
152                                   "createAppShortcut.html"));
153 }
154 
155 class GenerateAppManagementApiTest
156     : public ExtensionManagementApiTest,
157       public ::testing::WithParamInterface<ProviderType> {
158  public:
SetUp()159   void SetUp() override {
160     if (GetParam() == ProviderType::kWebApps) {
161       scoped_feature_list_.InitWithFeatures(
162           {features::kDesktopPWAsWithoutExtensions}, {});
163     } else {
164       DCHECK_EQ(GetParam(), ProviderType::kBookmarkApps);
165       scoped_feature_list_.InitWithFeatures(
166           {}, {features::kDesktopPWAsWithoutExtensions});
167     }
168 
169     ExtensionManagementApiTest::SetUp();
170   }
171 
172  private:
173   base::test::ScopedFeatureList scoped_feature_list_;
174 };
175 
IN_PROC_BROWSER_TEST_P(GenerateAppManagementApiTest,GenerateAppForLink)176 IN_PROC_BROWSER_TEST_P(GenerateAppManagementApiTest, GenerateAppForLink) {
177   ASSERT_TRUE(RunExtensionSubtest("management/test",
178                                   "generateAppForLink.html"));
179 }
180 
181 INSTANTIATE_TEST_SUITE_P(All,
182                          GenerateAppManagementApiTest,
183                          ::testing::Values(ProviderType::kBookmarkApps,
184                                            ProviderType::kWebApps),
185                          web_app::ProviderTypeParamToString);
186 
187 class InstallReplacementWebAppApiTest : public ExtensionManagementApiTest {
188  public:
InstallReplacementWebAppApiTest()189   InstallReplacementWebAppApiTest()
190       : https_test_server_(net::EmbeddedTestServer::TYPE_HTTPS) {}
191   ~InstallReplacementWebAppApiTest() override = default;
192 
193  protected:
194   static const char kManifest[];
195   static const char kAppManifest[];
196 
SetUpOnMainThread()197   void SetUpOnMainThread() override {
198     ExtensionManagementApiTest::SetUpOnMainThread();
199     https_test_server_.ServeFilesFromDirectory(test_data_dir_);
200     ASSERT_TRUE(https_test_server_.Start());
201 
202     web_app::WebAppProviderBase::GetProviderBase(profile())
203         ->shortcut_manager()
204         .SuppressShortcutsForTesting();
205   }
206 
RunTest(const char * manifest,const char * web_app_path,const char * background_script,bool from_webstore)207   void RunTest(const char* manifest,
208                const char* web_app_path,
209                const char* background_script,
210                bool from_webstore) {
211     extensions::TestExtensionDir extension_dir;
212     extension_dir.WriteManifest(base::StringPrintf(
213         manifest, https_test_server_.GetURL(web_app_path).spec().c_str()));
214     extension_dir.WriteFile(FILE_PATH_LITERAL("background.js"),
215                             background_script);
216     extensions::ResultCatcher catcher;
217     if (from_webstore) {
218       // |expected_change| is the expected change in the number of installed
219       // extensions.
220       ASSERT_TRUE(InstallExtensionFromWebstore(extension_dir.UnpackedPath(),
221                                                1 /* expected_change */));
222     } else {
223       ASSERT_TRUE(LoadExtension(extension_dir.UnpackedPath()));
224     }
225 
226     ASSERT_TRUE(catcher.GetNextResult()) << catcher.message();
227   }
228 
RunInstallableWebAppTest(const char * manifest,const char * web_app_url,const char * web_app_start_url)229   void RunInstallableWebAppTest(const char* manifest,
230                                 const char* web_app_url,
231                                 const char* web_app_start_url) {
232     static constexpr char kInstallReplacementWebApp[] =
233         R"(chrome.test.runWithUserGesture(function() {
234              chrome.management.installReplacementWebApp(function() {
235                chrome.test.assertNoLastError();
236                chrome.test.notifyPass();
237              });
238            });)";
239 
240     chrome::SetAutoAcceptPWAInstallConfirmationForTesting(true);
241     const GURL start_url = https_test_server_.GetURL(web_app_start_url);
242     web_app::AppId web_app_id = web_app::GenerateAppIdFromURL(start_url);
243 
244     auto* provider =
245         web_app::WebAppProviderBase::GetProviderBase(browser()->profile());
246     EXPECT_FALSE(provider->registrar().IsLocallyInstalled(start_url));
247     EXPECT_EQ(0, static_cast<int>(
248                      provider->ui_manager().GetNumWindowsForApp(web_app_id)));
249 
250     RunTest(manifest, web_app_url, kInstallReplacementWebApp,
251             true /* from_webstore */);
252     EXPECT_TRUE(provider->registrar().IsLocallyInstalled(start_url));
253     EXPECT_EQ(1, static_cast<int>(
254                      provider->ui_manager().GetNumWindowsForApp(web_app_id)));
255 
256     // Call API again. It should launch the app.
257     RunTest(manifest, web_app_url, kInstallReplacementWebApp,
258             true /* from_webstore */);
259     EXPECT_TRUE(provider->registrar().IsLocallyInstalled(start_url));
260     EXPECT_EQ(2, static_cast<int>(
261                      provider->ui_manager().GetNumWindowsForApp(web_app_id)));
262 
263     chrome::SetAutoAcceptPWAInstallConfirmationForTesting(false);
264   }
265 
266   net::EmbeddedTestServer https_test_server_;
267 };
268 
269 const char InstallReplacementWebAppApiTest::kManifest[] =
270     R"({
271           "name": "Management API Test",
272           "version": "0.1",
273           "manifest_version": 2,
274           "background": { "scripts": ["background.js"] },
275           "replacement_web_app": "%s"
276         })";
277 
278 const char InstallReplacementWebAppApiTest::kAppManifest[] =
279     R"({
280           "name": "Management API Test",
281           "version": "0.1",
282           "manifest_version": 2,
283           "app": {
284             "background": { "scripts": ["background.js"] }
285           },
286           "replacement_web_app": "%s"
287         })";
288 
IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest,NotWebstore)289 IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest, NotWebstore) {
290   static constexpr char kBackground[] = R"(
291   chrome.management.installReplacementWebApp(function() {
292     chrome.test.assertLastError(
293         'Only extensions from the web store can install replacement web apps.');
294     chrome.test.notifyPass();
295   });)";
296 
297   RunTest(kManifest,
298           "/management/install_replacement_web_app/good_web_app/index.html",
299           kBackground, false /* from_webstore */);
300 }
301 
IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest,NoGesture)302 IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest, NoGesture) {
303   static constexpr char kBackground[] = R"(
304   chrome.management.installReplacementWebApp(function() {
305     chrome.test.assertLastError(
306         'chrome.management.installReplacementWebApp requires a user gesture.');
307     chrome.test.notifyPass();
308   });)";
309 
310   RunTest(kManifest,
311           "/management/install_replacement_web_app/good_web_app/index.html",
312           kBackground, true /* from_webstore */);
313 }
314 
IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest,NotInstallableWebApp)315 IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest, NotInstallableWebApp) {
316   static constexpr char kBackground[] =
317       R"(chrome.test.runWithUserGesture(function() {
318            chrome.management.installReplacementWebApp(function() {
319              chrome.test.assertLastError(
320                  'Web app is not a valid installable web app.');
321              chrome.test.notifyPass();
322            });
323          });)";
324 
325   RunTest(kManifest,
326           "/management/install_replacement_web_app/bad_web_app/index.html",
327           kBackground, true /* from_webstore */);
328 }
329 
IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest,InstallableWebApp)330 IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest, InstallableWebApp) {
331   static constexpr char kGoodWebAppURL[] =
332       "/management/install_replacement_web_app/good_web_app/index.html";
333 
334   RunInstallableWebAppTest(kManifest, kGoodWebAppURL, kGoodWebAppURL);
335 }
336 
337 // Check that web app still installs and launches correctly when start_url does
338 // not match replacement_web_app_url.
IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest,InstallableWebAppWithStartUrl)339 IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest,
340                        InstallableWebAppWithStartUrl) {
341   static constexpr char kGoodWebAppUrl[] =
342       "/management/install_replacement_web_app/good_web_app_with_start_url/"
343       "index.html";
344   static constexpr char kGoodWebAppStartUrl[] =
345       "/management/install_replacement_web_app/good_web_app_with_start_url/"
346       "pwa_start_url.html";
347 
348   RunInstallableWebAppTest(kManifest, kGoodWebAppUrl, kGoodWebAppStartUrl);
349 }
350 
IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest,InstallableWebAppInPlatformApp)351 IN_PROC_BROWSER_TEST_F(InstallReplacementWebAppApiTest,
352                        InstallableWebAppInPlatformApp) {
353   static constexpr char kGoodWebAppURL[] =
354       "/management/install_replacement_web_app/good_web_app/index.html";
355 
356   RunInstallableWebAppTest(kAppManifest, kGoodWebAppURL, kGoodWebAppURL);
357 }
358 
359 // Fails often on Windows dbg bots. http://crbug.com/177163
360 #if defined(OS_WIN)
361 #define MAYBE_ManagementPolicyAllowed DISABLED_ManagementPolicyAllowed
362 #else
363 #define MAYBE_ManagementPolicyAllowed ManagementPolicyAllowed
364 #endif  // defined(OS_WIN)
365 // Tests actions on extensions when no management policy is in place.
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,MAYBE_ManagementPolicyAllowed)366 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,
367                        MAYBE_ManagementPolicyAllowed) {
368   LoadExtensions();
369   extensions::ScopedTestDialogAutoConfirm auto_confirm(
370       extensions::ScopedTestDialogAutoConfirm::ACCEPT);
371   extensions::ExtensionRegistry* registry =
372       extensions::ExtensionRegistry::Get(browser()->profile());
373   EXPECT_TRUE(registry->enabled_extensions().GetByID(
374       extension_ids_["enabled_extension"]));
375 
376   // Ensure that all actions are allowed.
377   extensions::ExtensionSystem::Get(
378       browser()->profile())->management_policy()->UnregisterAllProviders();
379 
380   ASSERT_TRUE(RunExtensionSubtest("management/management_policy",
381                                   "allowed.html"));
382   // The last thing the test does is uninstall the "enabled_extension".
383   EXPECT_FALSE(
384       registry->GetExtensionById(extension_ids_["enabled_extension"],
385                                  extensions::ExtensionRegistry::EVERYTHING));
386 }
387 
388 // Fails often on Windows dbg bots. http://crbug.com/177163
389 #if defined(OS_WIN)
390 #define MAYBE_ManagementPolicyProhibited DISABLED_ManagementPolicyProhibited
391 #else
392 #define MAYBE_ManagementPolicyProhibited ManagementPolicyProhibited
393 #endif  // defined(OS_WIN)
394 // Tests actions on extensions when management policy prohibits those actions.
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,MAYBE_ManagementPolicyProhibited)395 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,
396                        MAYBE_ManagementPolicyProhibited) {
397   LoadExtensions();
398   extensions::ExtensionRegistry* registry =
399       extensions::ExtensionRegistry::Get(browser()->profile());
400   EXPECT_TRUE(registry->enabled_extensions().GetByID(
401       extension_ids_["enabled_extension"]));
402 
403   // Prohibit status changes.
404   extensions::ManagementPolicy* policy = extensions::ExtensionSystem::Get(
405       browser()->profile())->management_policy();
406   policy->UnregisterAllProviders();
407   extensions::TestManagementPolicyProvider provider(
408       extensions::TestManagementPolicyProvider::PROHIBIT_MODIFY_STATUS |
409       extensions::TestManagementPolicyProvider::MUST_REMAIN_ENABLED |
410       extensions::TestManagementPolicyProvider::MUST_REMAIN_INSTALLED);
411   policy->RegisterProvider(&provider);
412   ASSERT_TRUE(RunExtensionSubtest("management/management_policy",
413                                   "prohibited.html"));
414 }
415 
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,LaunchPanelApp)416 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, LaunchPanelApp) {
417   // Load an extension that calls launchApp() on any app that gets
418   // installed.
419   ExtensionTestMessageListener launcher_loaded("launcher loaded", false);
420   ASSERT_TRUE(LoadExtension(
421       test_data_dir_.AppendASCII("management/launch_on_install")));
422   ASSERT_TRUE(launcher_loaded.WaitUntilSatisfied());
423 
424   // Load an app with app.launch.container = "panel".
425   std::string app_id;
426   LoadAndWaitForLaunch("management/launch_app_panel", &app_id);
427   ASSERT_FALSE(HasFatalFailure());  // Stop the test if any ASSERT failed.
428 
429   // Find the app's browser.  Check that it is a popup.
430   ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile()));
431   Browser* app_browser = FindOtherBrowser(browser());
432   ASSERT_TRUE(app_browser->is_type_app());
433 
434   // Close the app panel.
435   CloseBrowserSynchronously(app_browser);
436 
437   extensions::ExtensionRegistry* registry =
438       extensions::ExtensionRegistry::Get(browser()->profile());
439   // Unload the extension.
440   UninstallExtension(app_id);
441   ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
442   ASSERT_FALSE(registry->GetExtensionById(
443       app_id, extensions::ExtensionRegistry::EVERYTHING));
444 
445   // Set a pref indicating that the user wants to launch in a regular tab.
446   // This should be ignored, because panel apps always load in a popup.
447   extensions::SetLaunchType(browser()->profile(), app_id,
448                             extensions::LAUNCH_TYPE_REGULAR);
449 
450   // Load the extension again.
451   std::string app_id_new;
452   LoadAndWaitForLaunch("management/launch_app_panel", &app_id_new);
453   ASSERT_FALSE(HasFatalFailure());
454 
455   // If the ID changed, then the pref will not apply to the app.
456   ASSERT_EQ(app_id, app_id_new);
457 
458   // Find the app's browser.  Apps that should load in a panel ignore
459   // prefs, so we should still see the launch in a popup.
460   ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile()));
461   app_browser = FindOtherBrowser(browser());
462   ASSERT_TRUE(app_browser->is_type_app());
463 }
464 
465 // Disabled: crbug.com/230165, crbug.com/915339, crbug.com/979399
466 #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
467     defined(OS_CHROMEOS)
468 #define MAYBE_LaunchTabApp DISABLED_LaunchTabApp
469 #else
470 #define MAYBE_LaunchTabApp LaunchTabApp
471 #endif
472 
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,MAYBE_LaunchTabApp)473 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, MAYBE_LaunchTabApp) {
474   // Load an extension that calls launchApp() on any app that gets
475   // installed.
476   ExtensionTestMessageListener launcher_loaded("launcher loaded", false);
477   ASSERT_TRUE(LoadExtension(
478       test_data_dir_.AppendASCII("management/launch_on_install")));
479   ASSERT_TRUE(launcher_loaded.WaitUntilSatisfied());
480 
481   // Code below assumes that the test starts with a single browser window
482   // hosting one tab.
483   ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
484   ASSERT_EQ(1, browser()->tab_strip_model()->count());
485 
486   // Load an app with app.launch.container = "tab".
487   std::string app_id;
488   LoadAndWaitForLaunch("management/launch_app_tab", &app_id);
489   ASSERT_FALSE(HasFatalFailure());
490 
491   // Check that the app opened in a new tab of the existing browser.
492   ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
493   ASSERT_EQ(2, browser()->tab_strip_model()->count());
494 
495   extensions::ExtensionRegistry* registry =
496       extensions::ExtensionRegistry::Get(browser()->profile());
497   // Unload the extension.
498   UninstallExtension(app_id);
499   ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile()));
500   ASSERT_FALSE(registry->GetExtensionById(
501       app_id, extensions::ExtensionRegistry::EVERYTHING));
502 
503   // Set a pref indicating that the user wants to launch in a window.
504   extensions::SetLaunchType(browser()->profile(), app_id,
505                             extensions::LAUNCH_TYPE_WINDOW);
506 
507   std::string app_id_new;
508   LoadAndWaitForLaunch("management/launch_app_tab", &app_id_new);
509   ASSERT_FALSE(HasFatalFailure());
510 
511   // If the ID changed, then the pref will not apply to the app.
512   ASSERT_EQ(app_id, app_id_new);
513 
514   // Find the app's browser.  Opening in a new window will create
515   // a new browser.
516   ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile()));
517   Browser* app_browser = FindOtherBrowser(browser());
518   ASSERT_TRUE(app_browser->is_type_app());
519 }
520 
521 // Flaky on MacOS: crbug.com/915339
522 #if defined(OS_MACOSX)
523 #define MAYBE_LaunchType DISABLED_LaunchType
524 #else
525 #define MAYBE_LaunchType LaunchType
526 #endif
IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest,MAYBE_LaunchType)527 IN_PROC_BROWSER_TEST_F(ExtensionManagementApiTest, MAYBE_LaunchType) {
528   LoadExtensions();
529   base::FilePath basedir = test_data_dir_.AppendASCII("management");
530   LoadNamedExtension(basedir, "packaged_app");
531 
532   ASSERT_TRUE(RunExtensionSubtest("management/test", "launchType.html"));
533 }
534