| // Copyright 2019 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <codecvt> |
| #include <string> |
| |
| #include "base/barrier_callback.h" |
| #include "base/containers/contains.h" |
| #include "base/feature_list.h" |
| #include "base/files/file_util.h" |
| #include "base/functional/callback.h" |
| #include "base/strings/strcat.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/test/bind.h" |
| #include "base/test/metrics/histogram_tester.h" |
| #include "base/test/metrics/user_action_tester.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/test/test_future.h" |
| #include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/app/chrome_command_ids.h" |
| #include "chrome/browser/apps/app_service/app_launch_params.h" |
| #include "chrome/browser/apps/app_service/app_service_proxy.h" |
| #include "chrome/browser/apps/app_service/app_service_proxy_factory.h" |
| #include "chrome/browser/apps/app_service/browser_app_launcher.h" |
| #include "chrome/browser/banners/app_banner_manager_desktop.h" |
| #include "chrome/browser/browser_features.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/devtools/protocol/browser_handler.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/scoped_disable_client_side_decorations_for_test.h" |
| #include "chrome/browser/sessions/tab_restore_service_factory.h" |
| #include "chrome/browser/shell_integration.h" |
| #include "chrome/browser/themes/custom_theme_supplier.h" |
| #include "chrome/browser/themes/theme_properties.h" |
| #include "chrome/browser/themes/theme_service.h" |
| #include "chrome/browser/themes/theme_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/browser_list.h" |
| #include "chrome/browser/ui/browser_tabstrip.h" |
| #include "chrome/browser/ui/browser_window.h" |
| #include "chrome/browser/ui/exclusive_access/exclusive_access_test.h" |
| #include "chrome/browser/ui/page_info/page_info_dialog.h" |
| #include "chrome/browser/ui/tabs/tab_strip_model.h" |
| #include "chrome/browser/ui/toolbar/app_menu_model.h" |
| #include "chrome/browser/ui/web_applications/app_browser_controller.h" |
| #include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h" |
| #include "chrome/browser/ui/web_applications/web_app_controller_browsertest.h" |
| #include "chrome/browser/ui/web_applications/web_app_launch_utils.h" |
| #include "chrome/browser/ui/web_applications/web_app_menu_model.h" |
| #include "chrome/browser/ui/web_applications/web_app_ui_utils.h" |
| #include "chrome/browser/ui/window_sizer/window_sizer.h" |
| #include "chrome/browser/web_applications/commands/run_on_os_login_command.h" |
| #include "chrome/browser/web_applications/external_install_options.h" |
| #include "chrome/browser/web_applications/mojom/user_display_mode.mojom.h" |
| #include "chrome/browser/web_applications/os_integration/web_app_shortcut.h" |
| #include "chrome/browser/web_applications/test/os_integration_test_override_impl.h" |
| #include "chrome/browser/web_applications/test/web_app_install_test_utils.h" |
| #include "chrome/browser/web_applications/test/web_app_test_observers.h" |
| #include "chrome/browser/web_applications/test/web_app_test_utils.h" |
| #include "chrome/browser/web_applications/web_app.h" |
| #include "chrome/browser/web_applications/web_app_command_manager.h" |
| #include "chrome/browser/web_applications/web_app_command_scheduler.h" |
| #include "chrome/browser/web_applications/web_app_constants.h" |
| #include "chrome/browser/web_applications/web_app_helpers.h" |
| #include "chrome/browser/web_applications/web_app_install_finalizer.h" |
| #include "chrome/browser/web_applications/web_app_install_info.h" |
| #include "chrome/browser/web_applications/web_app_provider.h" |
| #include "chrome/browser/web_applications/web_app_registrar.h" |
| #include "chrome/browser/web_applications/web_app_registry_update.h" |
| #include "chrome/browser/web_applications/web_app_sync_bridge.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/common/webui_url_constants.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "components/services/app_service/public/cpp/app_launch_util.h" |
| #include "components/sessions/core/tab_restore_service.h" |
| #include "components/webapps/browser/features.h" |
| #include "components/webapps/browser/installable/installable_metrics.h" |
| #include "components/webapps/browser/uninstall_result_code.h" |
| #include "content/public/common/content_features.h" |
| #include "content/public/test/background_color_change_waiter.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/test_utils.h" |
| #include "extensions/common/constants.h" |
| #include "net/base/filename_util.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/blink/public/common/features.h" |
| #include "third_party/skia/include/core/SkColor.h" |
| #include "ui/base/clipboard/clipboard.h" |
| #include "ui/base/clipboard/clipboard_buffer.h" |
| #include "ui/base/window_open_disposition.h" |
| #include "ui/display/screen.h" |
| #include "ui/gfx/color_utils.h" |
| #include "ui/gfx/geometry/rect.h" |
| #include "ui/gfx/geometry/size.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "chrome/browser/ash/system_web_apps/color_helpers.h" |
| #include "chrome/browser/ash/system_web_apps/test_support/test_system_web_app_installation.h" |
| #include "chrome/browser/ui/ash/shelf/chrome_shelf_controller.h" |
| #include "chromeos/constants/chromeos_features.h" |
| #endif |
| |
| #if BUILDFLAG(IS_MAC) |
| #include "ui/base/test/scoped_fake_nswindow_fullscreen.h" |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) |
| #include "base/test/test_reg_util_win.h" |
| #include "base/win/windows_version.h" |
| #include "chrome/browser/web_applications/os_integration/web_app_handler_registration_utils_win.h" |
| #include "chrome/browser/web_applications/os_integration/web_app_shortcuts_menu_win.h" |
| #include "chrome/browser/win/jumplist_updater.h" |
| #include "chrome/installer/util/shell_util.h" |
| #endif |
| |
| namespace { |
| |
| constexpr const char kExampleURL[] = "http://example.org/"; |
| constexpr const char16_t kExampleURL16[] = u"http://example.org/"; |
| constexpr const char kExampleManifestURL[] = "http://example.org/manifest"; |
| |
| constexpr char kLaunchWebAppDisplayModeHistogram[] = "Launch.WebAppDisplayMode"; |
| |
| // Opens |url| in a new popup window with the dimensions |popup_size|. |
| Browser* OpenPopupAndWait(Browser* browser, |
| const GURL& url, |
| const gfx::Size& popup_size) { |
| content::WebContents* const web_contents = |
| browser->tab_strip_model()->GetActiveWebContents(); |
| |
| ui_test_utils::BrowserChangeObserver browser_change_observer( |
| nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); |
| std::string open_window_script = base::StringPrintf( |
| "window.open('%s', '_blank', 'toolbar=none,width=%i,height=%i')", |
| url.spec().c_str(), popup_size.width(), popup_size.height()); |
| |
| EXPECT_TRUE(content::ExecJs(web_contents, open_window_script)); |
| |
| // The navigation should happen in a new window. |
| Browser* popup_browser = browser_change_observer.Wait(); |
| EXPECT_NE(browser, popup_browser); |
| |
| content::WebContents* popup_contents = |
| popup_browser->tab_strip_model()->GetActiveWebContents(); |
| EXPECT_TRUE(content::WaitForLoadStop(popup_contents)); |
| EXPECT_EQ(popup_contents->GetLastCommittedURL(), url); |
| |
| return popup_browser; |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| std::vector<std::wstring> GetFileExtensionsForProgId( |
| const std::wstring& file_handler_prog_id) { |
| const std::wstring prog_id_path = |
| base::StrCat({ShellUtil::kRegClasses, L"\\", file_handler_prog_id}); |
| |
| // Get list of handled file extensions from value FileExtensions at |
| // HKEY_CURRENT_USER\Software\Classes\<file_handler_prog_id>. |
| base::win::RegKey file_extensions_key(HKEY_CURRENT_USER, prog_id_path.c_str(), |
| KEY_QUERY_VALUE); |
| std::wstring handled_file_extensions; |
| EXPECT_EQ(file_extensions_key.ReadValue(L"FileExtensions", |
| &handled_file_extensions), |
| ERROR_SUCCESS); |
| return base::SplitString(handled_file_extensions, std::wstring(L";"), |
| base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); |
| } |
| |
| #endif // BUILDFLAG(IS_WIN) |
| |
| } // namespace |
| |
| namespace web_app { |
| |
| using ::base::BucketsAre; |
| |
| class WebAppBrowserTest : public WebAppControllerBrowserTest { |
| public: |
| GURL GetSecureAppURL() { |
| return https_server()->GetURL("app.com", "/ssl/google.html"); |
| } |
| |
| GURL GetURLForPath(const std::string& path) { |
| return https_server()->GetURL("app.com", path); |
| } |
| |
| bool HasMinimalUiButtons(DisplayMode display_mode, |
| absl::optional<DisplayMode> display_override_mode, |
| bool open_as_window) { |
| static int index = 0; |
| |
| base::HistogramTester tester; |
| const GURL app_url = https_server()->GetURL( |
| base::StringPrintf("/web_apps/basic.html?index=%d", index++)); |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app_info->start_url = app_url; |
| web_app_info->scope = app_url; |
| web_app_info->display_mode = display_mode; |
| web_app_info->user_display_mode = open_as_window |
| ? mojom::UserDisplayMode::kStandalone |
| : mojom::UserDisplayMode::kBrowser; |
| if (display_override_mode) |
| web_app_info->display_override.push_back(*display_override_mode); |
| |
| AppId app_id = InstallWebApp(std::move(web_app_info)); |
| Browser* app_browser = LaunchWebAppBrowser(app_id); |
| DCHECK(app_browser->is_type_app()); |
| DCHECK(app_browser->app_controller()); |
| tester.ExpectUniqueSample( |
| kLaunchWebAppDisplayModeHistogram, |
| display_override_mode ? *display_override_mode : display_mode, 1); |
| |
| content::WebContents* const web_contents = |
| app_browser->tab_strip_model()->GetActiveWebContents(); |
| EXPECT_TRUE(WaitForLoadStop(web_contents)); |
| EXPECT_EQ(app_url, web_contents->GetVisibleURL()); |
| |
| const bool result = app_browser->app_controller()->HasMinimalUiButtons(); |
| EXPECT_EQ( |
| result, |
| EvalJs(web_contents, |
| "window.matchMedia('(display-mode: minimal-ui)').matches")); |
| CloseAndWait(app_browser); |
| |
| return result; |
| } |
| }; |
| |
| // A dedicated test fixture for Borderless, which requires a command |
| // line switch to enable manifest parsing. |
| class WebAppBrowserTest_Borderless : public WebAppBrowserTest { |
| public: |
| WebAppBrowserTest_Borderless() = default; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_{ |
| blink::features::kWebAppBorderless}; |
| }; |
| |
| // A dedicated test fixture for tabbed display override, which requires a |
| // command line switch to enable manifest parsing. |
| class WebAppBrowserTest_Tabbed : public WebAppBrowserTest { |
| public: |
| WebAppBrowserTest_Tabbed() = default; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_{ |
| features::kDesktopPWAsTabStrip}; |
| }; |
| |
| // A dedicated test fixture for detailed install dialog, which requires a |
| // command line switch to enable manifest parsing. |
| class WebAppBrowserTest_DetailedInstallDialog : public WebAppBrowserTest { |
| public: |
| WebAppBrowserTest_DetailedInstallDialog() = default; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_{ |
| webapps::features::kDesktopPWAsDetailedInstallDialog}; |
| }; |
| |
| // TODO(crbug.com/1257751): Stabilize the test. |
| #if BUILDFLAG(IS_POSIX) |
| #define DISABLE_POSIX(TEST) DISABLED_##TEST |
| #else |
| #define DISABLE_POSIX(TEST) TEST |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) |
| using WebAppBrowserTest_ShortcutMenu = WebAppBrowserTest; |
| #endif |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ThemeColor) { |
| { |
| const SkColor theme_color = SkColorSetA(SK_ColorBLUE, 0xF0); |
| blink::mojom::Manifest manifest; |
| manifest.start_url = GURL(kExampleURL); |
| manifest.scope = GURL(kExampleURL); |
| manifest.has_theme_color = true; |
| manifest.theme_color = theme_color; |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app::UpdateWebAppInfoFromManifest(manifest, GURL(kExampleManifestURL), |
| web_app_info.get()); |
| |
| AppId app_id = InstallWebApp(std::move(web_app_info)); |
| Browser* app_browser = LaunchWebAppBrowser(app_id); |
| |
| EXPECT_EQ(GetAppIdFromApplicationName(app_browser->app_name()), app_id); |
| EXPECT_EQ(SkColorSetA(theme_color, SK_AlphaOPAQUE), |
| app_browser->app_controller()->GetThemeColor()); |
| } |
| { |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app_info->start_url = GURL("http://example.org/2"); |
| web_app_info->scope = GURL("http://example.org/"); |
| web_app_info->theme_color = absl::optional<SkColor>(); |
| AppId app_id = InstallWebApp(std::move(web_app_info)); |
| Browser* app_browser = LaunchWebAppBrowser(app_id); |
| |
| EXPECT_EQ(GetAppIdFromApplicationName(app_browser->app_name()), app_id); |
| EXPECT_EQ(absl::nullopt, app_browser->app_controller()->GetThemeColor()); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, BackgroundColor) { |
| blink::mojom::Manifest manifest; |
| manifest.start_url = GURL(kExampleURL); |
| manifest.scope = GURL(kExampleURL); |
| manifest.has_background_color = true; |
| manifest.background_color = SkColorSetA(SK_ColorBLUE, 0xF0); |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app::UpdateWebAppInfoFromManifest(manifest, GURL(kExampleManifestURL), |
| web_app_info.get()); |
| AppId app_id = InstallWebApp(std::move(web_app_info)); |
| |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| EXPECT_EQ(provider->registrar_unsafe().GetAppBackgroundColor(app_id), |
| SK_ColorBLUE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ShortcutBackgroundColor) { |
| const GURL app_url = https_server()->GetURL("/banners/background-color.html"); |
| const AppId app_id = InstallWebAppFromPage(browser(), app_url); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| |
| EXPECT_EQ(provider->registrar_unsafe().GetAppBackgroundColor(app_id), |
| SK_ColorBLUE); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ManifestWithColor) { |
| const GURL app_url = |
| https_server()->GetURL("/banners/no-sw-with-colors.html"); |
| const AppId app_id = InstallWebAppFromPage(browser(), app_url); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| |
| EXPECT_EQ(provider->registrar_unsafe().GetAppBackgroundColor(app_id), |
| SK_ColorYELLOW); |
| EXPECT_EQ(provider->registrar_unsafe().GetAppThemeColor(app_id), |
| SK_ColorGREEN); |
| } |
| |
| // Also see BackgroundColorChangeSystemWebAppBrowserTest.BackgroundColorChange |
| // below. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, BackgroundColorChange) { |
| const GURL app_url = GetSecureAppURL(); |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app_info->start_url = app_url; |
| web_app_info->scope = app_url.GetWithoutFilename(); |
| web_app_info->theme_color = SK_ColorWHITE; |
| web_app_info->dark_mode_theme_color = SK_ColorBLACK; |
| web_app_info->background_color = SK_ColorWHITE; |
| web_app_info->dark_mode_background_color = SK_ColorBLACK; |
| |
| const AppId app_id = InstallWebApp(std::move(web_app_info)); |
| |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| content::WebContents* const web_contents = |
| app_browser->tab_strip_model()->GetActiveWebContents(); |
| |
| // Wait for original background color to load. |
| { |
| content::BackgroundColorChangeWaiter waiter(web_contents); |
| waiter.Wait(); |
| EXPECT_EQ(app_browser->app_controller()->GetBackgroundColor().value(), |
| SK_ColorWHITE); |
| } |
| content::AwaitDocumentOnLoadCompleted(web_contents); |
| |
| // Changing background color should update the toolbar color. |
| { |
| content::BackgroundColorChangeWaiter waiter(web_contents); |
| EXPECT_TRUE(content::ExecJs( |
| web_contents, "document.body.style.backgroundColor = 'cyan';")); |
| waiter.Wait(); |
| EXPECT_EQ(app_browser->app_controller()->GetBackgroundColor().value(), |
| SK_ColorCYAN); |
| SkColor download_shelf_color; |
| app_browser->app_controller()->GetThemeSupplier()->GetColor( |
| ThemeProperties::COLOR_TOOLBAR, &download_shelf_color); |
| EXPECT_EQ(download_shelf_color, SK_ColorCYAN); |
| } |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| class ColorSystemWebAppBrowserTest : public WebAppBrowserTest { |
| public: |
| ColorSystemWebAppBrowserTest() { |
| system_web_app_installation_ = |
| ash::TestSystemWebAppInstallation::SetUpAppWithColors( |
| /*theme_color=*/SK_ColorWHITE, |
| /*dark_mode_theme_color=*/SK_ColorBLACK, |
| /*background_color=*/SK_ColorWHITE, |
| /*dark_mode_background_color=*/SK_ColorBLACK); |
| } |
| |
| // Installs the web app under test, blocking until installation is complete, |
| // and returning the `AppId` for the installed web app. |
| AppId WaitForSwaInstall() { |
| system_web_app_installation_->WaitForAppInstall(); |
| return system_web_app_installation_->GetAppId(); |
| } |
| |
| protected: |
| std::unique_ptr<ash::TestSystemWebAppInstallation> |
| system_web_app_installation_; |
| }; |
| |
| class BackgroundColorChangeSystemWebAppBrowserTest |
| : public ColorSystemWebAppBrowserTest, |
| public testing::WithParamInterface< |
| /*prefer_manifest_background_color=*/bool> { |
| public: |
| BackgroundColorChangeSystemWebAppBrowserTest() { |
| static_cast<ash::UnittestingSystemAppDelegate*>( |
| system_web_app_installation_->GetDelegate()) |
| ->SetPreferManifestBackgroundColor(PreferManifestBackgroundColor()); |
| } |
| |
| // Returns whether the web app under test prefers manifest background colors |
| // over web contents background colors. |
| bool PreferManifestBackgroundColor() const { return GetParam(); } |
| }; |
| |
| class DynamicColorSystemWebAppBrowserTest |
| : public ColorSystemWebAppBrowserTest, |
| public testing::WithParamInterface</*use_system_theme_color=*/bool> { |
| public: |
| DynamicColorSystemWebAppBrowserTest() { |
| auto* delegate = static_cast<ash::UnittestingSystemAppDelegate*>( |
| system_web_app_installation_->GetDelegate()); |
| |
| delegate->SetUseSystemThemeColor(GetParam()); |
| } |
| |
| // Returns whether the web app under test wants to use a system sourced theme |
| // color. |
| bool UseSystemThemeColor() const { return GetParam(); } |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_{ |
| chromeos::features::kJelly}; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(All, |
| BackgroundColorChangeSystemWebAppBrowserTest, |
| /*prefer_manifest_background_color=*/testing::Bool(), |
| [](const testing::TestParamInfo< |
| /*prefer_manifest_background_color=*/bool>& info) { |
| return info.param ? "PreferManifestBackgroundColor" |
| : "WebContentsBackgroundColor"; |
| }); |
| |
| // Also see WebAppBrowserTest.BackgroundColorChange above. |
| IN_PROC_BROWSER_TEST_P(BackgroundColorChangeSystemWebAppBrowserTest, |
| BackgroundColorChange) { |
| const AppId app_id = WaitForSwaInstall(); |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| content::WebContents* const web_contents = |
| app_browser->tab_strip_model()->GetActiveWebContents(); |
| |
| const bool is_dark_mode_state = |
| ui::NativeTheme::GetInstanceForNativeUi()->ShouldUseDarkColors(); |
| // Wait for original background color to load. |
| { |
| content::BackgroundColorChangeWaiter waiter(web_contents); |
| waiter.Wait(); |
| EXPECT_EQ(app_browser->app_controller()->GetBackgroundColor().value(), |
| is_dark_mode_state ? SK_ColorBLACK : SK_ColorWHITE); |
| } |
| content::AwaitDocumentOnLoadCompleted(web_contents); |
| |
| // Changing background color should update the toolbar color unless a system |
| // web app prefers manifest background colors over web contents background |
| // colors. |
| { |
| content::BackgroundColorChangeWaiter waiter(web_contents); |
| EXPECT_TRUE(content::ExecJs( |
| web_contents, "document.body.style.backgroundColor = 'cyan';")); |
| waiter.Wait(); |
| EXPECT_EQ(app_browser->app_controller()->GetBackgroundColor().value(), |
| PreferManifestBackgroundColor() |
| ? (is_dark_mode_state ? SK_ColorBLACK : SK_ColorWHITE) |
| : SK_ColorCYAN); |
| SkColor download_shelf_color; |
| app_browser->app_controller()->GetThemeSupplier()->GetColor( |
| ThemeProperties::COLOR_TOOLBAR, &download_shelf_color); |
| EXPECT_EQ(download_shelf_color, |
| PreferManifestBackgroundColor() |
| ? (is_dark_mode_state ? SK_ColorBLACK : SK_ColorWHITE) |
| : SK_ColorCYAN); |
| } |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(All, |
| DynamicColorSystemWebAppBrowserTest, |
| /*use_system_theme_color=*/::testing::Bool(), |
| [](const testing::TestParamInfo< |
| /*use_system_theme_color=*/bool>& info) { |
| return info.param ? "WithUseSystemThemeColor" |
| : "WithoutUseSystemThemeColor"; |
| }); |
| |
| IN_PROC_BROWSER_TEST_P(DynamicColorSystemWebAppBrowserTest, Colors) { |
| const AppId app_id = WaitForSwaInstall(); |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| auto* app_controller = app_browser->app_controller(); |
| auto theme_color = app_controller->GetThemeColor().value(); |
| auto bg_color = app_controller->GetBackgroundColor().value(); |
| if (UseSystemThemeColor()) { |
| // Ensure app controller is pulling the color from the OS. |
| EXPECT_EQ(theme_color, ash::GetSystemThemeColor()); |
| EXPECT_EQ(bg_color, ash::GetSystemBackgroundColor()); |
| } else { |
| // If SWA has opted out, theme and bg color should default to white or black |
| // depending on launch context. |
| EXPECT_TRUE(theme_color == SK_ColorWHITE || theme_color == SK_ColorBLACK); |
| EXPECT_TRUE(bg_color == SK_ColorWHITE || bg_color == SK_ColorBLACK); |
| } |
| } |
| |
| #endif // BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| // This tests that we don't crash when launching a PWA window with an |
| // autogenerated user theme set. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, AutoGeneratedUserThemeCrash) { |
| ThemeServiceFactory::GetForProfile(browser()->profile()) |
| ->BuildAutogeneratedThemeFromColor(SK_ColorBLUE); |
| |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app_info->start_url = GURL(kExampleURL); |
| AppId app_id = InstallWebApp(std::move(web_app_info)); |
| |
| LaunchWebAppBrowser(app_id); |
| } |
| |
| // Check the 'Open in Chrome' menu button for web app windows. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, OpenInChrome) { |
| const GURL app_url(kExampleURL); |
| const AppId app_id = InstallPWA(app_url); |
| |
| { |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| |
| EXPECT_EQ(1, app_browser->tab_strip_model()->count()); |
| EXPECT_EQ(1, browser()->tab_strip_model()->count()); |
| ASSERT_EQ(2u, chrome::GetBrowserCount(browser()->profile())); |
| |
| chrome::ExecuteCommand(app_browser, IDC_OPEN_IN_CHROME); |
| |
| // The browser frame is closed next event loop so it's still safe to access |
| // here. |
| EXPECT_EQ(0, app_browser->tab_strip_model()->count()); |
| |
| EXPECT_EQ(2, browser()->tab_strip_model()->count()); |
| EXPECT_EQ(1, browser()->tab_strip_model()->active_index()); |
| EXPECT_EQ( |
| app_url, |
| browser()->tab_strip_model()->GetActiveWebContents()->GetVisibleURL()); |
| } |
| |
| // Wait until the browser actually gets closed. This invalidates |
| // |app_browser|. |
| content::RunAllPendingInMessageLoop(); |
| ASSERT_EQ(1u, chrome::GetBrowserCount(browser()->profile())); |
| } |
| |
| // Check the 'App info' menu button for web app windows. |
| #if BUILDFLAG(IS_LINUX) |
| // Disabled on Linux because the test only completes unless unrelated |
| // events are received to wake up the message loop. |
| #define MAYBE_AppInfoOpensPageInfo DISABLED_AppInfoOpensPageInfo |
| #else |
| #define MAYBE_AppInfoOpensPageInfo AppInfoOpensPageInfo |
| #endif |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, MAYBE_AppInfoOpensPageInfo) { |
| const GURL app_url(kExampleURL); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| |
| base::RunLoop run_loop_dialog_created; |
| GetPageInfoDialogCreatedCallbackForTesting() = |
| run_loop_dialog_created.QuitClosure(); |
| chrome::ExecuteCommand(app_browser, IDC_WEB_APP_MENU_APP_INFO); |
| // Wait for dialog to be created, timeout will trigger the test to fail. |
| run_loop_dialog_created.Run(); |
| |
| // The test closure should have run. But clear the global in case it hasn't. |
| EXPECT_FALSE(GetPageInfoDialogCreatedCallbackForTesting()); |
| GetPageInfoDialogCreatedCallbackForTesting().Reset(); |
| } |
| |
| // Check that last launch time is set after launch. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, AppLastLaunchTime) { |
| const GURL app_url(kExampleURL); |
| const AppId app_id = InstallPWA(app_url); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| |
| // last_launch_time is not set before launch |
| EXPECT_TRUE( |
| provider->registrar_unsafe().GetAppLastLaunchTime(app_id).is_null()); |
| |
| auto before_launch = base::Time::Now(); |
| LaunchWebAppBrowser(app_id); |
| |
| EXPECT_TRUE(provider->registrar_unsafe().GetAppLastLaunchTime(app_id) >= |
| before_launch); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, DISABLE_POSIX(WithMinimalUiButtons)) { |
| EXPECT_TRUE(HasMinimalUiButtons(DisplayMode::kBrowser, absl::nullopt, |
| /*open_as_window=*/true)); |
| EXPECT_TRUE(HasMinimalUiButtons(DisplayMode::kMinimalUi, absl::nullopt, |
| /*open_as_window=*/true)); |
| |
| EXPECT_TRUE(HasMinimalUiButtons(DisplayMode::kBrowser, absl::nullopt, |
| /*open_as_window=*/false)); |
| EXPECT_TRUE(HasMinimalUiButtons(DisplayMode::kMinimalUi, absl::nullopt, |
| /*open_as_window=*/false)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, WithoutMinimalUiButtons) { |
| EXPECT_FALSE(HasMinimalUiButtons(DisplayMode::kStandalone, absl::nullopt, |
| /*open_as_window=*/true)); |
| EXPECT_FALSE(HasMinimalUiButtons(DisplayMode::kFullscreen, absl::nullopt, |
| /*open_as_window=*/true)); |
| |
| EXPECT_FALSE(HasMinimalUiButtons(DisplayMode::kStandalone, absl::nullopt, |
| /*open_as_window=*/false)); |
| EXPECT_FALSE(HasMinimalUiButtons(DisplayMode::kFullscreen, absl::nullopt, |
| /*open_as_window=*/false)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, DISABLE_POSIX(DisplayOverride)) { |
| GURL test_url = https_server()->GetURL( |
| "/banners/" |
| "manifest_test_page.html?manifest=manifest_display_override.json"); |
| NavigateToURLAndWait(browser(), test_url); |
| |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| |
| std::vector<DisplayMode> app_display_mode_override = |
| provider->registrar_unsafe().GetAppDisplayModeOverride(app_id); |
| |
| ASSERT_EQ(2u, app_display_mode_override.size()); |
| EXPECT_EQ(DisplayMode::kMinimalUi, app_display_mode_override[0]); |
| EXPECT_EQ(DisplayMode::kStandalone, app_display_mode_override[1]); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| WithMinimalUiButtons_DisplayOverride) { |
| EXPECT_TRUE(HasMinimalUiButtons(DisplayMode::kStandalone, |
| DisplayMode::kBrowser, |
| /*open_as_window=*/true)); |
| EXPECT_TRUE(HasMinimalUiButtons(DisplayMode::kStandalone, |
| DisplayMode::kMinimalUi, |
| /*open_as_window=*/true)); |
| |
| EXPECT_TRUE(HasMinimalUiButtons(DisplayMode::kStandalone, |
| DisplayMode::kBrowser, |
| /*open_as_window=*/false)); |
| EXPECT_TRUE(HasMinimalUiButtons(DisplayMode::kStandalone, |
| DisplayMode::kMinimalUi, |
| /*open_as_window=*/false)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| WithoutMinimalUiButtons_DisplayOverride) { |
| EXPECT_FALSE(HasMinimalUiButtons(DisplayMode::kMinimalUi, |
| DisplayMode::kStandalone, |
| /*open_as_window=*/true)); |
| EXPECT_FALSE(HasMinimalUiButtons(DisplayMode::kMinimalUi, |
| DisplayMode::kFullscreen, |
| /*open_as_window=*/true)); |
| |
| EXPECT_FALSE(HasMinimalUiButtons(DisplayMode::kMinimalUi, |
| DisplayMode::kStandalone, |
| /*open_as_window=*/false)); |
| EXPECT_FALSE(HasMinimalUiButtons(DisplayMode::kMinimalUi, |
| DisplayMode::kFullscreen, |
| /*open_as_window=*/false)); |
| } |
| |
| // Tests that desktop PWAs open out-of-scope links with a custom toolbar. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, DesktopPWAsOpenLinksInApp) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| NavigateToURLAndWait(app_browser, app_url); |
| ASSERT_TRUE(app_browser->app_controller()); |
| NavigateAndCheckForToolbar(app_browser, GURL(kExampleURL), true); |
| } |
| |
| // Tests that desktop PWAs open links in a new tab at the end of the tabstrip of |
| // the last active browser. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, DesktopPWAsOpenLinksInNewTab) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| NavigateToURLAndWait(app_browser, app_url); |
| ASSERT_TRUE(app_browser->app_controller()); |
| |
| EXPECT_EQ(chrome::GetTotalBrowserCount(), 2u); |
| Browser* browser2 = CreateBrowser(app_browser->profile()); |
| EXPECT_EQ(chrome::GetTotalBrowserCount(), 3u); |
| |
| TabStripModel* model2 = browser2->tab_strip_model(); |
| chrome::AddTabAt(browser2, GURL(), -1, true); |
| EXPECT_EQ(model2->count(), 2); |
| model2->SelectPreviousTab(); |
| EXPECT_EQ(model2->active_index(), 0); |
| |
| NavigateParams param(app_browser, GURL("http://www.google.com/"), |
| ui::PAGE_TRANSITION_LINK); |
| param.window_action = NavigateParams::SHOW_WINDOW; |
| param.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; |
| |
| ui_test_utils::NavigateToURL(¶m); |
| |
| EXPECT_EQ(chrome::GetTotalBrowserCount(), 3u); |
| EXPECT_EQ(model2->count(), 3); |
| EXPECT_EQ(param.browser, browser2); |
| EXPECT_EQ(model2->active_index(), 2); |
| EXPECT_EQ(param.navigated_or_inserted_contents, |
| model2->GetActiveWebContents()); |
| } |
| |
| // Tests that desktop PWAs are opened at the correct size. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, PWASizeIsCorrectlyRestored) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| |
| EXPECT_TRUE(AppBrowserController::IsWebApp(app_browser)); |
| NavigateToURLAndWait(app_browser, app_url); |
| |
| const gfx::Rect bounds = gfx::Rect(50, 50, 550, 500); |
| app_browser->window()->SetBounds(bounds); |
| CloseAndWait(app_browser); |
| |
| Browser* const new_browser = LaunchWebAppBrowser(app_id); |
| EXPECT_EQ(new_browser->window()->GetBounds(), bounds); |
| } |
| |
| // Tests that using window.open to create a popup window out of scope results in |
| // a correctly sized window. |
| // TODO(crbug.com/1234260): Stabilize the test. |
| #if BUILDFLAG(IS_LINUX) |
| #define MAYBE_OffScopePWAPopupsHaveCorrectSize \ |
| DISABLED_OffScopePWAPopupsHaveCorrectSize |
| #else |
| #define MAYBE_OffScopePWAPopupsHaveCorrectSize OffScopePWAPopupsHaveCorrectSize |
| #endif |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| MAYBE_OffScopePWAPopupsHaveCorrectSize) { |
| // TODO(crbug.com/1240482): the test expectations fail if the window gets CSD |
| // and becomes smaller because of that. Investigate this and remove the line |
| // below if possible. |
| ui::ScopedDisableClientSideDecorationsForTest scoped_disabled_csd; |
| |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| |
| EXPECT_TRUE(AppBrowserController::IsWebApp(app_browser)); |
| |
| const GURL offscope_url = |
| https_server()->GetURL("offscope.site.test", "/simple.html"); |
| const gfx::Size size(500, 500); |
| |
| Browser* const popup_browser = |
| OpenPopupAndWait(app_browser, offscope_url, size); |
| |
| // The navigation should have happened in a new window. |
| EXPECT_NE(popup_browser, app_browser); |
| |
| // The popup browser should be a PWA. |
| EXPECT_TRUE(AppBrowserController::IsWebApp(popup_browser)); |
| |
| // Toolbar should be shown, as the popup is out of scope. |
| EXPECT_TRUE(popup_browser->app_controller()->ShouldShowCustomTabBar()); |
| |
| // Skip animating the toolbar visibility. |
| popup_browser->app_controller()->UpdateCustomTabBarVisibility(false); |
| |
| // The popup window should be the size we specified. |
| EXPECT_EQ(size, popup_browser->window()->GetContentsSize()); |
| } |
| |
| // Tests that using window.open to create a popup window in scope results in |
| // a correctly sized window. |
| // TODO(crbug.com/1234260): Stabilize the test. |
| #if BUILDFLAG(IS_LINUX) |
| #define MAYBE_InScopePWAPopupsHaveCorrectSize \ |
| DISABLED_InScopePWAPopupsHaveCorrectSize |
| #else |
| #define MAYBE_InScopePWAPopupsHaveCorrectSize InScopePWAPopupsHaveCorrectSize |
| #endif |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| MAYBE_InScopePWAPopupsHaveCorrectSize) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| |
| EXPECT_TRUE(AppBrowserController::IsWebApp(app_browser)); |
| |
| const gfx::Size size(500, 500); |
| Browser* const popup_browser = OpenPopupAndWait(app_browser, app_url, size); |
| |
| // The navigation should have happened in a new window. |
| EXPECT_NE(popup_browser, app_browser); |
| |
| // The popup browser should be a PWA. |
| EXPECT_TRUE(AppBrowserController::IsWebApp(popup_browser)); |
| |
| // Toolbar should not be shown, as the popup is in scope. |
| EXPECT_FALSE(popup_browser->app_controller()->ShouldShowCustomTabBar()); |
| |
| // Skip animating the toolbar visibility. |
| popup_browser->app_controller()->UpdateCustomTabBarVisibility(false); |
| |
| // The popup window should be the size we specified. |
| EXPECT_EQ(size, popup_browser->window()->GetContentsSize()); |
| } |
| |
| // Test navigating to an out of scope url on the same origin causes the url |
| // to be shown to the user. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| LocationBarIsVisibleOffScopeOnSameOrigin) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| |
| // Toolbar should not be visible in the app. |
| ASSERT_FALSE(app_browser->app_controller()->ShouldShowCustomTabBar()); |
| |
| // The installed PWA's scope is app.com:{PORT}/ssl, |
| // so app.com:{PORT}/accessibility_fail.html is out of scope. |
| const GURL out_of_scope = GetURLForPath("/accessibility_fail.html"); |
| NavigateToURLAndWait(app_browser, out_of_scope); |
| |
| // Location should be visible off scope. |
| ASSERT_TRUE(app_browser->app_controller()->ShouldShowCustomTabBar()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, UpgradeWithoutCustomTabBar) { |
| const GURL secure_app_url = |
| https_server()->GetURL("app.site.test", "/empty.html"); |
| GURL::Replacements rep; |
| rep.SetSchemeStr(url::kHttpScheme); |
| const GURL app_url = secure_app_url.ReplaceComponents(rep); |
| |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| NavigateToURLAndWait(app_browser, secure_app_url); |
| |
| EXPECT_FALSE(app_browser->app_controller()->ShouldShowCustomTabBar()); |
| |
| const GURL off_origin_url = |
| https_server()->GetURL("example.org", "/empty.html"); |
| NavigateToURLAndWait(app_browser, off_origin_url); |
| EXPECT_EQ(app_browser->app_controller()->ShouldShowCustomTabBar(), true); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, OverscrollEnabled) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| |
| // Overscroll is only enabled on Aura platforms currently. |
| #if defined(USE_AURA) |
| EXPECT_TRUE(app_browser->CanOverscrollContent()); |
| #else |
| EXPECT_FALSE(app_browser->CanOverscrollContent()); |
| #endif |
| } |
| |
| // Check the 'Copy URL' menu button for Web App windows. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, CopyURL) { |
| const GURL app_url(kExampleURL); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| |
| content::BrowserTestClipboardScope test_clipboard_scope; |
| chrome::ExecuteCommand(app_browser, IDC_COPY_URL); |
| |
| ui::Clipboard* const clipboard = ui::Clipboard::GetForCurrentThread(); |
| std::u16string result; |
| clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste, /* data_dst = */ nullptr, |
| &result); |
| EXPECT_EQ(result, kExampleURL16); |
| } |
| |
| // Tests that the command for popping a tab out to a PWA window is disabled in |
| // incognito. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, PopOutDisabledInIncognito) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| |
| Browser* const incognito_browser = OpenURLOffTheRecord(profile(), app_url); |
| auto app_menu_model = |
| std::make_unique<AppMenuModel>(nullptr, incognito_browser); |
| app_menu_model->Init(); |
| ui::MenuModel* model = app_menu_model.get(); |
| size_t index = 0; |
| ASSERT_TRUE(app_menu_model->GetModelAndIndexForCommandId( |
| IDC_OPEN_IN_PWA_WINDOW, &model, &index)); |
| EXPECT_FALSE(model->IsEnabledAt(index)); |
| } |
| |
| // Tests that web app menus don't crash when no tabs are selected. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, NoTabSelectedMenuCrash) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| |
| app_browser->tab_strip_model()->CloseAllTabs(); |
| auto app_menu_model = std::make_unique<WebAppMenuModel>( |
| /*provider=*/nullptr, app_browser); |
| app_menu_model->Init(); |
| } |
| |
| // Tests that PWA menus have an uninstall option. |
| // TODO(crbug.com/1271118): Flaky on mac arm64. |
| #if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64) |
| #define MAYBE_UninstallMenuOption DISABLED_UninstallMenuOption |
| #else |
| #define MAYBE_UninstallMenuOption UninstallMenuOption |
| #endif |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, MAYBE_UninstallMenuOption) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| |
| auto app_menu_model = std::make_unique<WebAppMenuModel>( |
| /*provider=*/nullptr, app_browser); |
| app_menu_model->Init(); |
| ui::MenuModel* model = app_menu_model.get(); |
| size_t index = 0; |
| const bool found = app_menu_model->GetModelAndIndexForCommandId( |
| WebAppMenuModel::kUninstallAppCommandId, &model, &index); |
| #if BUILDFLAG(IS_CHROMEOS) |
| EXPECT_FALSE(found); |
| #else |
| EXPECT_TRUE(found); |
| EXPECT_TRUE(model->IsEnabledAt(index)); |
| |
| base::HistogramTester tester; |
| app_menu_model->ExecuteCommand(WebAppMenuModel::kUninstallAppCommandId, |
| /*event_flags=*/0); |
| tester.ExpectUniqueSample("WrenchMenu.MenuAction", MENU_ACTION_UNINSTALL_APP, |
| 1); |
| #endif // BUILDFLAG(IS_CHROMEOS) |
| } |
| |
| // Tests that both installing a PWA and creating a shortcut app are disabled for |
| // incognito windows. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ShortcutMenuOptionsInIncognito) { |
| Browser* const incognito_browser = CreateIncognitoBrowser(profile()); |
| EXPECT_EQ(webapps::AppBannerManagerDesktop::FromWebContents( |
| incognito_browser->tab_strip_model()->GetActiveWebContents()), |
| nullptr); |
| NavigateToURLAndWait(incognito_browser, GetInstallableAppURL()); |
| |
| // Wait sufficient time for an installability check to occur. |
| EXPECT_TRUE( |
| NavigateAndAwaitInstallabilityCheck(browser(), GetInstallableAppURL())); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, incognito_browser), |
| kDisabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, incognito_browser), |
| kNotPresent); |
| } |
| |
| // Tests that both installing a PWA and creating a shortcut app are disabled for |
| // an error page. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ShortcutMenuOptionsForErrorPage) { |
| EXPECT_FALSE(NavigateAndAwaitInstallabilityCheck( |
| browser(), https_server()->GetURL("/invalid_path.html"))); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, browser()), kDisabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, browser()), kNotPresent); |
| } |
| |
| // Tests that both installing a PWA and creating a shortcut app are available |
| // for an installable PWA. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| ShortcutMenuOptionsForInstallablePWA) { |
| EXPECT_TRUE( |
| NavigateAndAwaitInstallabilityCheck(browser(), GetInstallableAppURL())); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, browser()), kEnabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, browser()), kEnabled); |
| } |
| |
| // Tests that both installing a PWA and creating a shortcut app are disabled |
| // when page crashes. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ShortcutMenuOptionsForCrashedTab) { |
| EXPECT_TRUE( |
| NavigateAndAwaitInstallabilityCheck(browser(), GetInstallableAppURL())); |
| content::WebContents* tab_contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| |
| { |
| content::ScopedAllowRendererCrashes scoped_allow_renderer_crashes; |
| content::RenderFrameDeletedObserver crash_observer( |
| tab_contents->GetPrimaryMainFrame()); |
| tab_contents->GetPrimaryMainFrame()->GetProcess()->Shutdown(1); |
| crash_observer.WaitUntilDeleted(); |
| } |
| ASSERT_TRUE(tab_contents->IsCrashed()); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, browser()), kDisabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, browser()), kDisabled); |
| } |
| |
| // Tests that an installed PWA is not used when out of scope by one path level. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| DISABLE_POSIX(MenuOptionsOutsideInstalledPwaScope)) { |
| NavigateToURLAndWait( |
| browser(), |
| https_server()->GetURL("/banners/scope_is_start_url/index.html")); |
| test::InstallPwaForCurrentUrl(browser()); |
| |
| // Open a page that is one directory up from the installed PWA. |
| Browser* const new_browser = NavigateInNewWindowAndAwaitInstallabilityCheck( |
| https_server()->GetURL("/banners/no_manifest_test_page.html")); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, new_browser), kEnabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, new_browser), kNotPresent); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, new_browser), |
| kNotPresent); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| DISABLE_POSIX(InstallInstallableSite)) { |
| base::Time before_install_time = base::Time::Now(); |
| base::UserActionTester user_action_tester; |
| NavigateToURLAndWait(browser(), GetInstallableAppURL()); |
| |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| EXPECT_EQ(provider->registrar_unsafe().GetAppShortName(app_id), |
| GetInstallableAppName()); |
| |
| // Installed PWAs should launch in their own window. |
| EXPECT_EQ(provider->registrar_unsafe().GetAppUserDisplayMode(app_id), |
| web_app::mojom::UserDisplayMode::kStandalone); |
| |
| // Installed PWAs should have install time set. |
| EXPECT_TRUE(provider->registrar_unsafe().GetAppInstallTime(app_id) >= |
| before_install_time); |
| |
| EXPECT_EQ(1, user_action_tester.GetActionCount("InstallWebAppFromMenu")); |
| EXPECT_EQ(0, user_action_tester.GetActionCount("CreateShortcut")); |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| // Apps on Chrome OS should not be pinned after install. |
| EXPECT_FALSE(ChromeShelfController::instance()->IsAppPinned(app_id)); |
| #endif |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| DISABLE_POSIX(CanInstallOverBrowserTabPwa)) { |
| NavigateToURLAndWait(browser(), GetInstallableAppURL()); |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| |
| // Change display mode to open in tab. |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| provider->sync_bridge_unsafe().SetAppUserDisplayMode( |
| app_id, web_app::mojom::UserDisplayMode::kBrowser, |
| /*is_user_action=*/false); |
| |
| Browser* const new_browser = |
| NavigateInNewWindowAndAwaitInstallabilityCheck(GetInstallableAppURL()); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, new_browser), kEnabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, new_browser), kEnabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, new_browser), |
| kNotPresent); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| DISABLE_POSIX(CannotInstallOverWindowPwa)) { |
| NavigateToURLAndWait(browser(), GetInstallableAppURL()); |
| test::InstallPwaForCurrentUrl(browser()); |
| |
| // Avoid any interference if active browser was changed by PWA install. |
| Browser* const new_browser = |
| NavigateInNewWindowAndAwaitInstallabilityCheck(GetInstallableAppURL()); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, new_browser), kEnabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, new_browser), kNotPresent); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, new_browser), |
| kEnabled); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, NoOpenInAppForBrowserTabPwa) { |
| GURL app_url = https_server()->GetURL( |
| "/web_apps/get_manifest.html?display_browser.json"); |
| AppId app_id = InstallWebAppFromPage(browser(), app_url); |
| |
| // Change display mode to open in tab. |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| provider->sync_bridge_unsafe().SetAppUserDisplayMode( |
| app_id, web_app::mojom::UserDisplayMode::kBrowser, |
| /*is_user_action=*/false); |
| |
| NavigateToURLAndWait(browser(), app_url); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, browser()), kEnabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, browser()), kNotPresent); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, browser()), |
| kNotPresent); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, CanInstallWithPolicyPwa) { |
| ExternalInstallOptions options = CreateInstallOptions(GetInstallableAppURL()); |
| options.install_source = ExternalInstallSource::kExternalPolicy; |
| ExternallyManagedAppManagerInstall(profile(), options); |
| |
| // Avoid any interference if active browser was changed by PWA install. |
| Browser* const new_browser = |
| NavigateInNewWindowAndAwaitInstallabilityCheck(GetInstallableAppURL()); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_CREATE_SHORTCUT, new_browser), kEnabled); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, new_browser), kNotPresent); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, new_browser), |
| kEnabled); |
| } |
| |
| // TODO(crbug.com/1415857): Flaky on ChromeOS. |
| #if BUILDFLAG(IS_CHROMEOS) |
| #define MAYBE_OpenDetailedInstallDialogOnlyOnce \ |
| DISABLED_OpenDetailedInstallDialogOnlyOnce |
| #else |
| #define MAYBE_OpenDetailedInstallDialogOnlyOnce \ |
| OpenDetailedInstallDialogOnlyOnce |
| #endif |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_DetailedInstallDialog, |
| MAYBE_OpenDetailedInstallDialogOnlyOnce) { |
| base::UserActionTester user_action_tester; |
| NavigateToURLAndWait( |
| browser(), |
| https_server()->GetURL( |
| "/banners/" |
| "manifest_test_page.html?manifest=manifest_with_screenshots.json")); |
| |
| WebAppTestInstallObserver observer(profile()); |
| // The IDC_INSTALL_PWA is executed twice, but the dialog |
| // must be shown only once. |
| ASSERT_TRUE(chrome::ExecuteCommand(browser(), IDC_INSTALL_PWA)); |
| ASSERT_TRUE(chrome::ExecuteCommand(browser(), IDC_INSTALL_PWA)); |
| |
| EXPECT_EQ(1u, provider().command_manager().GetCommandCountForTesting()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, WindowsOffsetForMultiWindowPWA) { |
| const GURL app_url(kExampleURL); |
| const AppId app_id = InstallPWA(app_url); |
| |
| Browser* first_browser = LaunchWebAppBrowserAndWait(app_id); |
| // We should have the original (tabbed) browser for this BrowserTest, plus a |
| // new one for the PWA. |
| EXPECT_NE(nullptr, first_browser); |
| EXPECT_EQ(BrowserList::GetInstance()->size(), 2u); |
| |
| // Make the window small so that we don't hit the edge when creating a new |
| // one that is offset. |
| first_browser->window()->SetBounds(gfx::Rect(0, 0, 50, 50)); |
| |
| Browser* second_browser = LaunchWebAppBrowserAndWait(app_id); |
| EXPECT_NE(nullptr, second_browser); |
| EXPECT_EQ(BrowserList::GetInstance()->size(), 3u); |
| |
| auto bounds1 = first_browser->window()->GetRestoredBounds(); |
| auto bounds2 = second_browser->window()->GetRestoredBounds(); |
| EXPECT_EQ(bounds1.x() + WindowSizer::kWindowTilePixels, bounds2.x()); |
| EXPECT_EQ(bounds1.y() + WindowSizer::kWindowTilePixels, bounds2.y()); |
| |
| // On Chrome OS and Mac we aggressively move the entire window on screen if it |
| // would otherwise be partially off-screen. On other platforms we merely make |
| // sure at least some of the window is visible, but don't force the entire |
| // window on screen. As such, only run these checks on Mac and Chrome OS. |
| #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) |
| const gfx::Rect work_area = |
| display::Screen::GetScreen() |
| ->GetDisplayMatching(first_browser->window()->GetRestoredBounds()) |
| .work_area(); |
| |
| // Resize the second window larger so that subsequent new windows will hit the |
| // edge of the screen when offset. |
| second_browser->window()->SetBounds(work_area); |
| |
| // Open a windows until they start stacking. |
| bool hit_the_bottom_right = false; |
| gfx::Rect previous_bounds = second_browser->window()->GetRestoredBounds(); |
| for (int i = 0; i < 10; i++) { |
| Browser* next_browser = LaunchWebAppBrowserAndWait(app_id); |
| if (previous_bounds == next_browser->window()->GetRestoredBounds()) { |
| hit_the_bottom_right = true; |
| break; |
| } |
| previous_bounds = next_browser->window()->GetRestoredBounds(); |
| } |
| |
| EXPECT_TRUE(hit_the_bottom_right); |
| #endif |
| } |
| |
| class WebAppBrowserTest_ExternalPrefMigration |
| : public WebAppBrowserTest, |
| public testing::WithParamInterface<test::ExternalPrefMigrationTestCases> { |
| public: |
| WebAppBrowserTest_ExternalPrefMigration() { |
| std::vector<base::test::FeatureRef> enabled_features; |
| std::vector<base::test::FeatureRef> disabled_features; |
| |
| switch (GetParam()) { |
| case test::ExternalPrefMigrationTestCases::kDisableMigrationReadPref: |
| disabled_features.push_back(features::kMigrateExternalPrefsToWebAppDB); |
| disabled_features.push_back( |
| features::kUseWebAppDBInsteadOfExternalPrefs); |
| break; |
| case test::ExternalPrefMigrationTestCases::kDisableMigrationReadDB: |
| disabled_features.push_back(features::kMigrateExternalPrefsToWebAppDB); |
| enabled_features.push_back( |
| features::kUseWebAppDBInsteadOfExternalPrefs); |
| break; |
| case test::ExternalPrefMigrationTestCases::kEnableMigrationReadPref: |
| enabled_features.push_back(features::kMigrateExternalPrefsToWebAppDB); |
| disabled_features.push_back( |
| features::kUseWebAppDBInsteadOfExternalPrefs); |
| break; |
| case test::ExternalPrefMigrationTestCases::kEnableMigrationReadDB: |
| enabled_features.push_back(features::kMigrateExternalPrefsToWebAppDB); |
| enabled_features.push_back( |
| features::kUseWebAppDBInsteadOfExternalPrefs); |
| break; |
| } |
| scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); |
| } |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(WebAppBrowserTest_ExternalPrefMigration, |
| CannotUninstallPolicyWebAppAfterUserInstall) { |
| GURL install_url = GetInstallableAppURL(); |
| ExternalInstallOptions options = CreateInstallOptions(install_url); |
| options.install_source = ExternalInstallSource::kExternalPolicy; |
| ExternallyManagedAppManagerInstall(profile(), options); |
| |
| auto* provider = WebAppProvider::GetForTest(browser()->profile()); |
| AppId app_id = |
| provider->registrar_unsafe().LookupExternalAppId(install_url).value(); |
| |
| EXPECT_FALSE(provider->install_finalizer().CanUserUninstallWebApp(app_id)); |
| |
| InstallWebAppFromPage(browser(), install_url); |
| |
| // Performing a user install on the page should not override the "policy" |
| // install source. |
| EXPECT_FALSE(provider->install_finalizer().CanUserUninstallWebApp(app_id)); |
| const WebApp& web_app = *provider->registrar_unsafe().GetAppById(app_id); |
| EXPECT_TRUE(web_app.IsSynced()); |
| EXPECT_TRUE(web_app.IsPolicyInstalledApp()); |
| } |
| |
| // Tests that the command for OpenActiveTabInPwaWindow is available for secure |
| // pages in an app's scope. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ReparentWebAppForSecureActiveTab) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| |
| NavigateToURLAndWait(browser(), app_url); |
| content::WebContents* tab_contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| ASSERT_EQ(tab_contents->GetLastCommittedURL(), app_url); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, browser()), |
| kEnabled); |
| } |
| |
| #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| DISABLE_POSIX(ShortcutIconCorrectColor)) { |
| os_hooks_suppress_.reset(); |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| |
| std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> |
| registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); |
| |
| NavigateToURLAndWait( |
| browser(), |
| https_server()->GetURL( |
| "/banners/manifest_test_page.html?manifest=manifest_one_icon.json")); |
| |
| // Wait for OS hooks and installation to complete and the app to launch. |
| base::RunLoop run_loop_install; |
| WebAppInstallManagerObserverAdapter observer(profile()); |
| observer.SetWebAppInstalledWithOsHooksDelegate(base::BindLambdaForTesting( |
| [&](const AppId& installed_app_id) { run_loop_install.Quit(); })); |
| content::CreateAndLoadWebContentsObserver app_loaded_observer; |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| run_loop_install.Run(); |
| app_loaded_observer.Wait(); |
| |
| base::FilePath shortcut_path; |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| std::vector<SkColor> expected_pixel_colors = {SkColorSetRGB(92, 92, 92)}; |
| absl::optional<SkColor> icon_pixel_color = absl::nullopt; |
| #if BUILDFLAG(IS_MAC) |
| icon_pixel_color = registration->test_override->GetShortcutIconTopLeftColor( |
| profile(), registration->test_override->chrome_apps_folder(), app_id, |
| provider->registrar_unsafe().GetAppShortName(app_id)); |
| #elif BUILDFLAG(IS_WIN) |
| icon_pixel_color = registration->test_override->GetShortcutIconTopLeftColor( |
| profile(), registration->test_override->application_menu(), app_id, |
| provider->registrar_unsafe().GetAppShortName(app_id)); |
| expected_pixel_colors.push_back(SkColorSetRGB(91, 91, 91)); |
| expected_pixel_colors.push_back(SkColorSetRGB(90, 90, 90)); |
| #endif |
| EXPECT_TRUE(icon_pixel_color.has_value()); |
| EXPECT_THAT(expected_pixel_colors, |
| testing::Contains(icon_pixel_color.value())) |
| << "Actual color (RGB) is: " |
| << color_utils::SkColorToRgbString(icon_pixel_color.value()); |
| |
| base::RunLoop run_loop_uninstall; |
| provider->install_finalizer().UninstallWebApp( |
| app_id, webapps::WebappUninstallSource::kAppMenu, |
| base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { |
| EXPECT_EQ(code, webapps::UninstallResultCode::kSuccess); |
| run_loop_uninstall.Quit(); |
| })); |
| run_loop_uninstall.Run(); |
| } |
| #endif |
| |
| #if BUILDFLAG(IS_WIN) |
| |
| struct ShortcutsMenuItem { |
| public: |
| ShortcutsMenuItem() : command_line(base::CommandLine::NO_PROGRAM) {} |
| |
| // The string to be displayed in a shortcut menu item. |
| std::u16string title; |
| |
| // Used for storing and appending command-line arguments. |
| base::CommandLine command_line; |
| |
| // The absolute path to an icon to be displayed in a shortcut menu item. |
| base::FilePath icon_path; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_ShortcutMenu, ShortcutsMenuSuccess) { |
| os_hooks_suppress_.reset(); |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| |
| std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> |
| registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); |
| NavigateToURLAndWait( |
| browser(), |
| https_server()->GetURL( |
| "/banners/" |
| "manifest_test_page.html?manifest=manifest_with_shortcuts.json")); |
| |
| std::vector<ShortcutsMenuItem> shortcuts_menu_items; |
| |
| auto SaveJumpList = base::BindLambdaForTesting( |
| [&](std::wstring, |
| const std::vector<scoped_refptr<ShellLinkItem>>& link_items) -> bool { |
| for (auto& shell_item : link_items) { |
| ShortcutsMenuItem item; |
| item.title = shell_item->title(); |
| item.icon_path = shell_item->icon_path(); |
| item.command_line = *shell_item->GetCommandLine(); |
| shortcuts_menu_items.push_back(item); |
| } |
| return true; |
| }); |
| |
| SetUpdateJumpListForTesting(SaveJumpList); |
| |
| // Wait for OS hooks and installation to complete and the app to launch. |
| base::HistogramTester tester; |
| base::RunLoop run_loop_install; |
| WebAppInstallManagerObserverAdapter observer(profile()); |
| observer.SetWebAppInstalledWithOsHooksDelegate( |
| base::BindLambdaForTesting([&](const AppId& installed_app_id) { |
| EXPECT_THAT( |
| tester.GetAllSamples("WebApp.ShortcutsMenuRegistration.Result"), |
| BucketsAre(base::Bucket(true, 1))); |
| run_loop_install.Quit(); |
| })); |
| content::CreateAndLoadWebContentsObserver app_loaded_observer; |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| run_loop_install.Run(); |
| app_loaded_observer.Wait(); |
| |
| EXPECT_EQ(2U, shortcuts_menu_items.size()); |
| EXPECT_EQ(u"shortcut1", shortcuts_menu_items[0].title); |
| EXPECT_EQ(u"shortcut2", shortcuts_menu_items[1].title); |
| EXPECT_TRUE(base::PathExists(shortcuts_menu_items[0].icon_path)); |
| EXPECT_TRUE(base::PathExists(shortcuts_menu_items[1].icon_path)); |
| EXPECT_EQ(app_id, shortcuts_menu_items[0].command_line.GetSwitchValueASCII( |
| switches::kAppId)); |
| EXPECT_EQ(app_id, shortcuts_menu_items[1].command_line.GetSwitchValueASCII( |
| switches::kAppId)); |
| EXPECT_NE( |
| std::string::npos, |
| shortcuts_menu_items[0] |
| .command_line |
| .GetSwitchValueASCII(switches::kAppLaunchUrlForShortcutsMenuItem) |
| .find("/banners/launch_url1")); |
| EXPECT_NE( |
| std::string::npos, |
| shortcuts_menu_items[1] |
| .command_line |
| .GetSwitchValueASCII(switches::kAppLaunchUrlForShortcutsMenuItem) |
| .find("/banners/launch_url2")); |
| |
| base::RunLoop run_loop_uninstall; |
| WebAppProvider::GetForTest(profile())->install_finalizer().UninstallWebApp( |
| app_id, webapps::WebappUninstallSource::kAppMenu, |
| base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { |
| EXPECT_EQ(code, webapps::UninstallResultCode::kSuccess); |
| EXPECT_THAT( |
| tester.GetAllSamples("WebApp.ShortcutsMenuUnregistered.Result"), |
| BucketsAre(base::Bucket(true, 1))); |
| run_loop_uninstall.Quit(); |
| })); |
| run_loop_uninstall.Run(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_ShortcutMenu, |
| ShortcutsMenuRegistrationWithNoShortcuts) { |
| os_hooks_suppress_.reset(); |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| |
| std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> |
| registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); |
| NavigateToURLAndWait( |
| browser(), |
| https_server()->GetURL("/banners/" |
| "manifest_test_page.html?manifest=manifest.json")); |
| |
| std::vector<ShortcutsMenuItem> shortcuts_menu_items; |
| |
| auto SaveJumpList = base::BindLambdaForTesting( |
| [&](std::wstring, |
| const std::vector<scoped_refptr<ShellLinkItem>>& link_items) -> bool { |
| for (auto& shell_item : link_items) { |
| ShortcutsMenuItem item; |
| item.title = shell_item->title(); |
| item.icon_path = shell_item->icon_path(); |
| item.command_line = *shell_item->GetCommandLine(); |
| shortcuts_menu_items.push_back(item); |
| } |
| return true; |
| }); |
| |
| SetUpdateJumpListForTesting(SaveJumpList); |
| |
| // Wait for OS hooks and installation to complete and the app to launch. |
| base::HistogramTester tester; |
| base::RunLoop run_loop_install; |
| WebAppInstallManagerObserverAdapter observer(profile()); |
| observer.SetWebAppInstalledWithOsHooksDelegate( |
| base::BindLambdaForTesting([&](const AppId& installed_app_id) { |
| // Verify that since the shortcuts menu items are not registered, |
| // none of the buckets are filled. |
| EXPECT_THAT( |
| tester.GetAllSamples("WebApp.ShortcutsMenuUnregistered.Result"), |
| BucketsAre(base::Bucket(true, 0), base::Bucket(false, 0))); |
| run_loop_install.Quit(); |
| })); |
| content::CreateAndLoadWebContentsObserver app_loaded_observer; |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| run_loop_install.Run(); |
| app_loaded_observer.Wait(); |
| |
| // No shortcuts should be read. |
| EXPECT_TRUE(shortcuts_menu_items.empty()); |
| |
| base::RunLoop run_loop_uninstall; |
| WebAppProvider::GetForTest(profile())->install_finalizer().UninstallWebApp( |
| app_id, webapps::WebappUninstallSource::kAppMenu, |
| base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { |
| EXPECT_EQ(code, webapps::UninstallResultCode::kSuccess); |
| EXPECT_THAT( |
| tester.GetAllSamples("WebApp.ShortcutsMenuUnregistered.Result"), |
| BucketsAre(base::Bucket(true, 1))); |
| run_loop_uninstall.Quit(); |
| })); |
| run_loop_uninstall.Run(); |
| } |
| |
| #endif |
| |
| #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX) |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, WebAppCreateAndDeleteShortcut) { |
| os_hooks_suppress_.reset(); |
| |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| |
| std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> |
| registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); |
| |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| |
| NavigateToURLAndWait(browser(), GetInstallableAppURL()); |
| |
| // Wait for OS hooks and installation to complete and the app to launch. |
| base::RunLoop run_loop_install; |
| WebAppInstallManagerObserverAdapter observer(profile()); |
| observer.SetWebAppInstalledWithOsHooksDelegate(base::BindLambdaForTesting( |
| [&](const AppId& installed_app_id) { run_loop_install.Quit(); })); |
| content::CreateAndLoadWebContentsObserver app_loaded_observer; |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| run_loop_install.Run(); |
| app_loaded_observer.Wait(); |
| |
| EXPECT_TRUE(provider->registrar_unsafe().IsInstalled(app_id)); |
| EXPECT_EQ(provider->registrar_unsafe().GetAppShortName(app_id), |
| GetInstallableAppName()); |
| |
| EXPECT_TRUE(registration->test_override->IsShortcutCreated( |
| profile(), app_id, provider->registrar_unsafe().GetAppShortName(app_id))); |
| |
| // Unistall the web app |
| base::RunLoop run_loop_uninstall; |
| provider->install_finalizer().UninstallWebApp( |
| app_id, webapps::WebappUninstallSource::kAppMenu, |
| base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { |
| EXPECT_EQ(code, webapps::UninstallResultCode::kSuccess); |
| run_loop_uninstall.Quit(); |
| })); |
| run_loop_uninstall.Run(); |
| |
| #if BUILDFLAG(IS_WIN) |
| base::FilePath desktop_shortcut_path = |
| registration->test_override->GetShortcutPath( |
| profile(), registration->test_override->desktop(), app_id, |
| provider->registrar_unsafe().GetAppShortName(app_id)); |
| base::FilePath app_menu_shortcut_path = |
| registration->test_override->GetShortcutPath( |
| profile(), registration->test_override->application_menu(), app_id, |
| provider->registrar_unsafe().GetAppShortName(app_id)); |
| EXPECT_FALSE(base::PathExists(desktop_shortcut_path)); |
| EXPECT_FALSE(base::PathExists(app_menu_shortcut_path)); |
| #elif BUILDFLAG(IS_MAC) |
| base::FilePath app_shortcut_path = |
| registration->test_override->GetShortcutPath( |
| profile(), registration->test_override->chrome_apps_folder(), app_id, |
| provider->registrar_unsafe().GetAppShortName(app_id)); |
| EXPECT_FALSE(base::PathExists(app_shortcut_path)); |
| #elif BUILDFLAG(IS_LINUX) |
| base::FilePath desktop_shortcut_path = |
| registration->test_override->GetShortcutPath( |
| profile(), registration->test_override->desktop(), app_id, |
| provider->registrar_unsafe().GetAppShortName(app_id)); |
| EXPECT_FALSE(base::PathExists(desktop_shortcut_path)); |
| #endif |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, RunOnOsLoginMetrics) { |
| os_hooks_suppress_.reset(); |
| GURL pwa_url("https://test-app.com"); |
| |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| |
| std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> |
| registration = OsIntegrationTestOverrideImpl::OverrideForTesting(); |
| |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| const AppId& app_id = InstallPWA(pwa_url); |
| |
| ASSERT_TRUE(provider->registrar_unsafe().IsInstalled(app_id)); |
| |
| base::HistogramTester tester; |
| base::RunLoop run_loop; |
| provider->scheduler().SetRunOnOsLoginMode( |
| app_id, RunOnOsLoginMode::kWindowed, base::BindLambdaForTesting([&]() { |
| EXPECT_THAT( |
| tester.GetAllSamples("WebApp.RunOnOsLogin.Registration.Result"), |
| BucketsAre(base::Bucket(true, 1))); |
| run_loop.Quit(); |
| })); |
| run_loop.Run(); |
| EXPECT_TRUE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( |
| profile(), app_id, provider->registrar_unsafe().GetAppShortName(app_id))); |
| |
| test::UninstallAllWebApps(profile()); |
| EXPECT_FALSE(OsIntegrationTestOverrideImpl::Get()->IsRunOnOsLoginEnabled( |
| profile(), app_id, provider->registrar_unsafe().GetAppShortName(app_id))); |
| EXPECT_THAT(tester.GetAllSamples("WebApp.RunOnOsLogin.Unregistration.Result"), |
| BucketsAre(base::Bucket(true, 1))); |
| } |
| #endif |
| |
| // Tests that reparenting the last browser tab doesn't close the browser window. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ReparentLastBrowserTab) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| NavigateToURLAndWait(browser(), app_url); |
| |
| Browser* const app_browser = ReparentWebAppForActiveTab(browser()); |
| ASSERT_EQ(app_browser->app_controller()->app_id(), app_id); |
| |
| ASSERT_TRUE(IsBrowserOpen(browser())); |
| EXPECT_EQ(browser()->tab_strip_model()->count(), 1); |
| } |
| |
| class WebAppBrowserTestUpdateShortcutResult |
| : public WebAppBrowserTest, |
| public ::testing::WithParamInterface<OsIntegrationSubManagersState> { |
| public: |
| WebAppBrowserTestUpdateShortcutResult() { |
| if (GetParam() == OsIntegrationSubManagersState::kSaveStateToDB) { |
| scoped_feature_list_.InitWithFeaturesAndParameters( |
| {{features::kOsIntegrationSubManagers, {{"stage", "write_config"}}}}, |
| /*disabled_features=*/{}); |
| } else { |
| scoped_feature_list_.InitWithFeatures( |
| {}, {features::kOsIntegrationSubManagers}); |
| } |
| } |
| |
| ~WebAppBrowserTestUpdateShortcutResult() override = default; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_P(WebAppBrowserTestUpdateShortcutResult, UpdateShortcut) { |
| os_hooks_suppress_.reset(); |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> |
| blocking_registration = |
| OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); |
| |
| NavigateToURLAndWait(browser(), GetInstallableAppURL()); |
| |
| WebAppProvider* provider = WebAppProvider::GetForTest(profile()); |
| |
| base::test::TestFuture<const AppId&, webapps::InstallResultCode> |
| install_future; |
| provider->scheduler().FetchManifestAndInstall( |
| webapps::WebappInstallSource::OMNIBOX_INSTALL_ICON, |
| browser()->tab_strip_model()->GetActiveWebContents()->GetWeakPtr(), |
| /*bypass_service_worker_check=*/false, |
| base::BindOnce(test::TestAcceptDialogCallback), |
| install_future.GetCallback(), |
| /*use_fallback=*/false); |
| |
| const AppId& app_id = install_future.Get<0>(); |
| EXPECT_EQ(provider->registrar_unsafe().GetAppShortName(app_id), |
| GetInstallableAppName()); |
| |
| { |
| ScopedRegistryUpdate update(&provider->sync_bridge_unsafe()); |
| update->UpdateApp(app_id)->SetName("test_app_2"); |
| } |
| |
| base::HistogramTester tester; |
| base::test::TestFuture<Result> result; |
| |
| auto synchronize_barrier = base::BarrierCallback<Result>( |
| /*num_callbacks=*/2, |
| base::BindOnce( |
| [&](base::OnceCallback<void(Result)> result_callback, |
| std::vector<Result> final_results) { |
| DCHECK_EQ(2u, final_results.size()); |
| Result final_result = Result::kOk; |
| if (final_results[0] == Result::kError || |
| final_results[1] == Result::kError) { |
| final_result = Result::kError; |
| } |
| std::move(result_callback).Run(final_result); |
| }, |
| result.GetCallback())); |
| |
| provider->os_integration_manager().UpdateShortcuts( |
| app_id, "Manifest test app", synchronize_barrier); |
| provider->os_integration_manager().Synchronize( |
| app_id, base::BindOnce(synchronize_barrier, Result::kOk)); |
| ASSERT_TRUE(result.Wait()); |
| EXPECT_THAT(result.Get(), testing::Eq(Result::kOk)); |
| |
| bool can_create_shortcuts = provider->os_integration_manager() |
| .shortcut_manager_for_testing() |
| .CanCreateShortcuts(); |
| if (can_create_shortcuts) { |
| EXPECT_THAT(tester.GetAllSamples("WebApp.Shortcuts.Update.Result"), |
| BucketsAre(base::Bucket(true, 1))); |
| } else { |
| EXPECT_THAT(tester.GetAllSamples("WebApp.Shortcuts.Update.Result"), |
| testing::IsEmpty()); |
| } |
| |
| base::test::TestFuture<std::unique_ptr<ShortcutInfo>> shortcut_future; |
| provider->os_integration_manager().GetShortcutInfoForApp( |
| app_id, shortcut_future.GetCallback()); |
| auto shortcut_info = shortcut_future.Take(); |
| EXPECT_NE(shortcut_info, nullptr); |
| EXPECT_EQ(shortcut_info->title, u"test_app_2"); |
| |
| test::UninstallAllWebApps(profile()); |
| EXPECT_FALSE(provider->registrar_unsafe().IsInstalled(app_id)); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| WebAppBrowserTestUpdateShortcutResult, |
| ::testing::Values(OsIntegrationSubManagersState::kSaveStateToDB, |
| OsIntegrationSubManagersState::kDisabled), |
| test::GetOsIntegrationSubManagersTestName); |
| |
| // Tests that reparenting a display: browser app tab results in a minimal-ui |
| // app window. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, ReparentDisplayBrowserApp) { |
| const GURL app_url = GetSecureAppURL(); |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app_info->start_url = app_url; |
| web_app_info->scope = app_url.GetWithoutFilename(); |
| web_app_info->display_mode = DisplayMode::kBrowser; |
| web_app_info->user_display_mode = mojom::UserDisplayMode::kStandalone; |
| web_app_info->title = u"A Shortcut App"; |
| const AppId app_id = InstallWebApp(std::move(web_app_info)); |
| |
| base::HistogramTester tester; |
| NavigateToURLAndWait(browser(), app_url); |
| content::WebContents* tab_contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| ASSERT_EQ(tab_contents->GetLastCommittedURL(), app_url); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_OPEN_IN_PWA_WINDOW, browser()), |
| kEnabled); |
| EXPECT_TRUE(chrome::ExecuteCommand(browser(), IDC_OPEN_IN_PWA_WINDOW)); |
| |
| Browser* const app_browser = BrowserList::GetInstance()->GetLastActive(); |
| ASSERT_EQ(app_browser->app_controller()->app_id(), app_id); |
| EXPECT_TRUE(app_browser->app_controller()->HasMinimalUiButtons()); |
| |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| EXPECT_EQ(provider->registrar_unsafe().GetAppUserDisplayMode(app_id), |
| mojom::UserDisplayMode::kStandalone); |
| EXPECT_EQ(provider->registrar_unsafe().GetAppEffectiveDisplayMode(app_id), |
| DisplayMode::kMinimalUi); |
| EXPECT_FALSE( |
| provider->registrar_unsafe().GetAppLastLaunchTime(app_id).is_null()); |
| tester.ExpectUniqueSample("WebApp.LaunchContainer", |
| apps::LaunchContainer::kLaunchContainerWindow, 1); |
| tester.ExpectUniqueSample("WebApp.LaunchSource", |
| apps::LaunchSource::kFromReparenting, 1); |
| } |
| |
| // Tests that the manifest name of the current installable site is used in the |
| // installation menu text. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, InstallToShelfContainsAppName) { |
| EXPECT_TRUE( |
| NavigateAndAwaitInstallabilityCheck(browser(), GetInstallableAppURL())); |
| |
| auto app_menu_model = std::make_unique<AppMenuModel>(nullptr, browser()); |
| app_menu_model->Init(); |
| ui::MenuModel* model = app_menu_model.get(); |
| size_t index = 0; |
| EXPECT_TRUE(app_menu_model->GetModelAndIndexForCommandId(IDC_INSTALL_PWA, |
| &model, &index)); |
| EXPECT_EQ(app_menu_model.get(), model); |
| EXPECT_EQ(model->GetLabelAt(index), u"Install Manifest test app…"); |
| } |
| |
| // Check that no assertions are hit when showing a permission request bubble. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, PermissionBubble) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| |
| content::RenderFrameHost* const render_frame_host = |
| app_browser->tab_strip_model() |
| ->GetActiveWebContents() |
| ->GetPrimaryMainFrame(); |
| EXPECT_TRUE(content::ExecJs( |
| render_frame_host, |
| "navigator.geolocation.getCurrentPosition(function(){});")); |
| } |
| |
| using WebAppBrowserTest_PrefixInTitle = WebAppBrowserTest; |
| |
| // Ensure that web app windows don't duplicate the app name in the title, when |
| // the page's title already starts with the app name. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_PrefixInTitle, PrefixExistsInTitle) { |
| const GURL app_url = |
| https_server()->GetURL("app.com", "/web_apps/title_appname_prefix.html"); |
| const std::u16string app_title = u"A Web App"; |
| |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app_info->start_url = app_url; |
| web_app_info->scope = app_url.GetWithoutFilename(); |
| web_app_info->title = app_title; |
| const AppId app_id = InstallWebApp(std::move(web_app_info)); |
| |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| content::WebContents* const web_contents = |
| app_browser->tab_strip_model()->GetActiveWebContents(); |
| EXPECT_TRUE(content::WaitForLoadStop(web_contents)); |
| |
| // The window title should not repeat "A Web App". |
| EXPECT_EQ(u"A Web App - funny cat video", |
| app_browser->GetWindowTitleForCurrentTab(false)); |
| } |
| |
| // Ensure that web app windows with blank titles don't display the URL as a |
| // default window title. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_PrefixInTitle, |
| WebAppWindowTitleForEmptyAndSimpleWebContentTitles) { |
| // Ensure web app windows show the expected title when the contents have an |
| // empty or simple title. |
| const GURL app_url = https_server()->GetURL("app.site.test", "/empty.html"); |
| const std::u16string app_title = u"A Web App"; |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app_info->start_url = app_url; |
| web_app_info->scope = app_url.GetWithoutFilename(); |
| web_app_info->title = app_title; |
| const AppId app_id = InstallWebApp(std::move(web_app_info)); |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| content::WebContents* const web_contents = |
| app_browser->tab_strip_model()->GetActiveWebContents(); |
| EXPECT_TRUE(content::WaitForLoadStop(web_contents)); |
| EXPECT_EQ(app_title, app_browser->GetWindowTitleForCurrentTab(false)); |
| NavigateToURLAndWait(app_browser, |
| https_server()->GetURL("app.site.test", "/simple.html")); |
| EXPECT_EQ(u"A Web App - OK", app_browser->GetWindowTitleForCurrentTab(false)); |
| } |
| |
| // Ensure that web app windows display the app title instead of the page |
| // title when off scope. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_PrefixInTitle, |
| OffScopeUrlsDisplayAppTitle) { |
| const GURL app_url = GetSecureAppURL(); |
| const std::u16string app_title = u"A Web App"; |
| |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app_info->start_url = app_url; |
| web_app_info->scope = app_url.GetWithoutFilename(); |
| web_app_info->title = app_title; |
| const AppId app_id = InstallWebApp(std::move(web_app_info)); |
| |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| content::WebContents* const web_contents = |
| app_browser->tab_strip_model()->GetActiveWebContents(); |
| EXPECT_TRUE(content::WaitForLoadStop(web_contents)); |
| |
| // When we are within scope, show the page title. |
| EXPECT_EQ(u"A Web App - Google", |
| app_browser->GetWindowTitleForCurrentTab(false)); |
| NavigateToURLAndWait(app_browser, |
| https_server()->GetURL("app.site.test", "/simple.html")); |
| |
| // When we are off scope, show the app title. |
| EXPECT_EQ(app_title, app_browser->GetWindowTitleForCurrentTab(false)); |
| } |
| |
| // Ensure that web app windows display the app title instead of the page |
| // title when using http. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, InScopeHttpUrlsDisplayAppTitle) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| const GURL app_url = |
| embedded_test_server()->GetURL("app.site.test", "/simple.html"); |
| const std::u16string app_title = u"A Web App"; |
| |
| auto web_app_info = std::make_unique<WebAppInstallInfo>(); |
| web_app_info->start_url = app_url; |
| web_app_info->title = app_title; |
| const AppId app_id = InstallWebApp(std::move(web_app_info)); |
| |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| content::WebContents* const web_contents = |
| app_browser->tab_strip_model()->GetActiveWebContents(); |
| EXPECT_TRUE(content::WaitForLoadStop(web_contents)); |
| |
| // The page title is "OK" but the page is being served over HTTP, so the app |
| // title should be used instead. |
| EXPECT_EQ(app_title, app_browser->GetWindowTitleForCurrentTab(false)); |
| } |
| |
| class WebAppBrowserTest_HideOrigin : public WebAppBrowserTest { |
| public: |
| WebAppBrowserTest_HideOrigin() = default; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_{ |
| features::kHideWebAppOriginText}; |
| }; |
| |
| // WebApps should not have origin text with this feature on. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_HideOrigin, OriginTextRemoved) { |
| const GURL app_url = GetInstallableAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| EXPECT_FALSE(app_browser->app_controller()->HasTitlebarAppOriginText()); |
| } |
| |
| // Check that a subframe on a regular web page can navigate to a URL that |
| // redirects to a web app. https://crbug.com/721949. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, SubframeRedirectsToWebApp) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| |
| // Set up a web app which covers app.com URLs. |
| GURL app_url = embedded_test_server()->GetURL("app.com", "/title1.html"); |
| const AppId app_id = InstallPWA(app_url); |
| |
| // Navigate a regular tab to a page with a subframe. |
| const GURL url = embedded_test_server()->GetURL("foo.com", "/iframe.html"); |
| content::WebContents* const tab = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| NavigateToURLAndWait(browser(), url); |
| |
| // Navigate the subframe to a URL that redirects to a URL in the web app's |
| // web extent. |
| const GURL redirect_url = embedded_test_server()->GetURL( |
| "bar.com", "/server-redirect?" + app_url.spec()); |
| EXPECT_TRUE(NavigateIframeToURL(tab, "test", redirect_url)); |
| |
| // Ensure that the frame navigated successfully and that it has correct |
| // content. |
| content::RenderFrameHost* const subframe = |
| content::ChildFrameAt(tab->GetPrimaryMainFrame(), 0); |
| EXPECT_EQ(app_url, subframe->GetLastCommittedURL()); |
| EXPECT_EQ( |
| "This page has no title.", |
| EvalJs(subframe, "document.body.innerText.trim();").ExtractString()); |
| } |
| |
| #if BUILDFLAG(IS_MAC) |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, NewAppWindow) { |
| BrowserList* const browser_list = BrowserList::GetInstance(); |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| Browser* const app_browser = LaunchWebAppBrowserAndWait(app_id); |
| |
| EXPECT_EQ(browser_list->size(), 2U); |
| |
| ui_test_utils::BrowserChangeObserver browser_change_observer( |
| nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded); |
| EXPECT_TRUE(chrome::ExecuteCommand(app_browser, IDC_NEW_WINDOW)); |
| Browser* const new_browser = browser_change_observer.Wait(); |
| |
| EXPECT_EQ(new_browser, browser_list->GetLastActive()); |
| EXPECT_EQ(browser_list->size(), 3U); |
| EXPECT_NE(new_browser, browser()); |
| EXPECT_NE(new_browser, app_browser); |
| EXPECT_TRUE(new_browser->is_type_app()); |
| EXPECT_EQ(new_browser->app_controller()->app_id(), app_id); |
| |
| WebAppProvider::GetForTest(profile()) |
| ->sync_bridge_unsafe() |
| .SetAppUserDisplayMode(app_id, web_app::mojom::UserDisplayMode::kBrowser, |
| /*is_user_action=*/false); |
| EXPECT_EQ(browser()->tab_strip_model()->count(), 1); |
| |
| ui_test_utils::AllBrowserTabAddedWaiter tab_waiter; |
| EXPECT_TRUE(chrome::ExecuteCommand(app_browser, IDC_NEW_WINDOW)); |
| content::WebContents* new_tab = tab_waiter.Wait(); |
| |
| ASSERT_TRUE(new_tab); |
| EXPECT_EQ(browser_list->GetLastActive(), browser()); |
| EXPECT_EQ(browser()->tab_strip_model()->count(), 2); |
| EXPECT_EQ(new_tab, browser()->tab_strip_model()->GetActiveWebContents()); |
| EXPECT_EQ(new_tab->GetVisibleURL(), app_url); |
| } |
| |
| #endif |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, PopupLocationBar) { |
| #if BUILDFLAG(IS_MAC) |
| ui::test::ScopedFakeNSWindowFullscreen fake_fullscreen; |
| #endif |
| const GURL app_url = GetSecureAppURL(); |
| const GURL in_scope = |
| https_server()->GetURL("app.com", "/ssl/page_with_subresource.html"); |
| const AppId app_id = InstallPWA(app_url); |
| |
| Browser* const popup_browser = web_app::CreateWebApplicationWindow( |
| profile(), app_id, WindowOpenDisposition::NEW_POPUP, /*restore_id=*/0); |
| |
| EXPECT_TRUE( |
| popup_browser->CanSupportWindowFeature(Browser::FEATURE_LOCATIONBAR)); |
| EXPECT_TRUE( |
| popup_browser->SupportsWindowFeature(Browser::FEATURE_LOCATIONBAR)); |
| |
| FullscreenNotificationObserver waiter(popup_browser); |
| chrome::ToggleFullscreenMode(popup_browser); |
| waiter.Wait(); |
| |
| EXPECT_TRUE( |
| popup_browser->CanSupportWindowFeature(Browser::FEATURE_LOCATIONBAR)); |
| } |
| |
| // Make sure chrome://web-app-internals page loads fine. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, WebAppInternalsPage) { |
| // Loads with no web app. |
| NavigateToURLAndWait(browser(), GURL("chrome://web-app-internals")); |
| |
| const GURL app_url = GetSecureAppURL(); |
| InstallPWA(app_url); |
| // Loads with one web app. |
| NavigateToURLAndWait(browser(), GURL("chrome://web-app-internals")); |
| |
| // Install a non-promotable web app. |
| NavigateToURLAndWait( |
| browser(), https_server()->GetURL("/banners/no_manifest_test_page.html")); |
| chrome::SetAutoAcceptWebAppDialogForTesting(/*auto_accept=*/true, |
| /*auto_open_in_window=*/false); |
| WebAppTestInstallObserver observer(profile()); |
| observer.BeginListening(); |
| CHECK(chrome::ExecuteCommand(browser(), IDC_CREATE_SHORTCUT)); |
| observer.Wait(); |
| chrome::SetAutoAcceptWebAppDialogForTesting(false, false); |
| // Loads with two apps. |
| NavigateToURLAndWait(browser(), GURL("chrome://web-app-internals")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, BrowserDisplayNotInstallable) { |
| GURL url = https_server()->GetURL( |
| "/banners/" |
| "manifest_test_page.html?manifest=manifest_display_browser.json"); |
| NavigateAndAwaitInstallabilityCheck(browser(), url); |
| |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, browser()), kNotPresent); |
| |
| // Install using Create Shortcut. |
| chrome::SetAutoAcceptWebAppDialogForTesting(/*auto_accept=*/true, |
| /*auto_open_in_window=*/false); |
| WebAppTestInstallObserver observer(profile()); |
| observer.BeginListening(); |
| CHECK(chrome::ExecuteCommand(browser(), IDC_CREATE_SHORTCUT)); |
| observer.Wait(); |
| chrome::SetAutoAcceptWebAppDialogForTesting(false, false); |
| |
| // Navigate to this site again and install should still be disabled. |
| Browser* new_browser = NavigateInNewWindowAndAwaitInstallabilityCheck(url); |
| EXPECT_EQ(GetAppMenuCommandState(IDC_INSTALL_PWA, new_browser), kNotPresent); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, |
| DISABLE_POSIX(WindowControlsOverlay)) { |
| GURL test_url = https_server()->GetURL( |
| "/banners/" |
| "manifest_test_page.html?manifest=manifest_window_controls_overlay.json"); |
| NavigateToURLAndWait(browser(), test_url); |
| |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| |
| std::vector<DisplayMode> app_display_mode_override = |
| provider->registrar_unsafe().GetAppDisplayModeOverride(app_id); |
| |
| ASSERT_EQ(1u, app_display_mode_override.size()); |
| EXPECT_EQ(DisplayMode::kWindowControlsOverlay, app_display_mode_override[0]); |
| |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| EXPECT_EQ(true, |
| app_browser->app_controller()->AppUsesWindowControlsOverlay()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_Borderless, |
| DISABLE_POSIX(Borderless)) { |
| GURL test_url = https_server()->GetURL( |
| "/banners/" |
| "manifest_test_page.html?manifest=manifest_borderless.json"); |
| NavigateToURLAndWait(browser(), test_url); |
| |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| |
| std::vector<DisplayMode> app_display_mode_override = |
| provider->registrar_unsafe().GetAppDisplayModeOverride(app_id); |
| |
| ASSERT_EQ(1u, app_display_mode_override.size()); |
| EXPECT_EQ(DisplayMode::kBorderless, app_display_mode_override[0]); |
| |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| app_browser->app_controller()->SetIsolatedWebAppTrueForTesting(); |
| |
| EXPECT_TRUE(app_browser->app_controller()->AppUsesBorderlessMode()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_Tabbed, |
| DISABLE_POSIX(TabbedDisplayOverride)) { |
| GURL test_url = https_server()->GetURL( |
| "/banners/" |
| "manifest_test_page.html?manifest=manifest_tabbed_display_override.json"); |
| NavigateToURLAndWait(browser(), test_url); |
| |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| |
| std::vector<DisplayMode> app_display_mode_override = |
| provider->registrar_unsafe().GetAppDisplayModeOverride(app_id); |
| |
| ASSERT_EQ(1u, app_display_mode_override.size()); |
| EXPECT_EQ(DisplayMode::kTabbed, app_display_mode_override[0]); |
| EXPECT_EQ(true, |
| provider->registrar_unsafe().IsTabbedWindowModeEnabled(app_id)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, DISABLE_POSIX(RemoveStatusBar)) { |
| NavigateToURLAndWait(browser(), GetInstallableAppURL()); |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| Browser* const app_browser = LaunchWebAppBrowser(app_id); |
| EXPECT_EQ(nullptr, app_browser->GetStatusBubbleForTesting()); |
| } |
| |
| class WebAppBrowserTest_NoDestroyProfile : public WebAppBrowserTest { |
| public: |
| WebAppBrowserTest_NoDestroyProfile() { |
| // This test only makes sense when DestroyProfileOnBrowserClose is |
| // disabled. |
| feature_list_.InitAndDisableFeature( |
| features::kDestroyProfileOnBrowserClose); |
| } |
| |
| private: |
| base::test::ScopedFeatureList feature_list_; |
| }; |
| |
| // Check that no web app is launched during shutdown. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_NoDestroyProfile, Shutdown) { |
| Profile* profile = browser()->profile(); |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| apps::AppLaunchParams params( |
| app_id, apps::LaunchContainer::kLaunchContainerWindow, |
| WindowOpenDisposition::NEW_WINDOW, apps::LaunchSource::kFromTest); |
| |
| BrowserHandler handler(nullptr, std::string()); |
| handler.Close(); |
| ui_test_utils::WaitForBrowserToClose(); |
| |
| content::WebContents* const web_contents = |
| apps::AppServiceProxyFactory::GetForProfile(profile) |
| ->BrowserAppLauncher() |
| ->LaunchAppWithParamsForTesting(std::move(params)); |
| EXPECT_EQ(web_contents, nullptr); |
| } |
| |
| using WebAppBrowserTest_ManifestId = WebAppBrowserTest; |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_ManifestId, |
| DISABLE_POSIX(NoManifestId)) { |
| NavigateToURLAndWait(browser(), GetInstallableAppURL()); |
| |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| auto* app = provider->registrar_unsafe().GetAppById(app_id); |
| |
| EXPECT_EQ(web_app::GenerateAppId( |
| /*manifest_id=*/absl::nullopt, |
| provider->registrar_unsafe().GetAppStartUrl(app_id)), |
| app_id); |
| EXPECT_EQ(app->start_url().spec().substr( |
| app->start_url().DeprecatedGetOriginAsURL().spec().size()), |
| app->manifest_id()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_ManifestId, ManifestIdSpecified) { |
| NavigateAndAwaitInstallabilityCheck( |
| browser(), |
| https_server()->GetURL( |
| "/banners/manifest_test_page.html?manifest=manifest_with_id.json")); |
| |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| auto* app = provider->registrar_unsafe().GetAppById(app_id); |
| |
| EXPECT_EQ(web_app::GenerateAppId(app->manifest_id(), app->start_url()), |
| app_id); |
| EXPECT_NE( |
| web_app::GenerateAppId(/*manifest_id=*/absl::nullopt, app->start_url()), |
| app_id); |
| } |
| |
| #if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) |
| class WebAppBrowserTest_FileHandler : public WebAppBrowserTest { |
| public: |
| WebAppBrowserTest_FileHandler() {} |
| |
| #if BUILDFLAG(IS_WIN) |
| protected: |
| void SetUp() override { |
| // Don't pollute Windows registry of machine running tests. |
| registry_override_manager_.OverrideRegistry(HKEY_CURRENT_USER); |
| WebAppBrowserTest::SetUp(); |
| } |
| |
| registry_util::RegistryOverrideManager registry_override_manager_; |
| #endif // BUILDFLAG(IS_WIN) |
| }; |
| |
| // TODO(crbug.com/1320285): Flaky on Mac. |
| #if BUILDFLAG(IS_MAC) |
| #define MAYBE_RegKeysFileExtension DISABLED_RegKeysFileExtension |
| #else |
| #define MAYBE_RegKeysFileExtension RegKeysFileExtension |
| #endif |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_FileHandler, |
| MAYBE_RegKeysFileExtension) { |
| os_hooks_suppress_.reset(); |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| base::HistogramTester tester; |
| |
| std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> |
| registration = |
| OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); |
| std::vector<std::string> expected_extensions{"bar", "baz", "foo", "foobar"}; |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL app_url(embedded_test_server()->GetURL( |
| "/banners/" |
| "manifest_test_page.html?manifest=manifest_with_file_handlers.json")); |
| |
| NavigateToURLAndWait(browser(), app_url); |
| |
| // Wait for OS hooks and installation to complete. |
| chrome::SetAutoAcceptWebAppDialogForTesting(true, true); |
| base::RunLoop run_loop_install; |
| WebAppInstallManagerObserverAdapter observer(profile()); |
| observer.SetWebAppInstalledWithOsHooksDelegate( |
| base::BindLambdaForTesting([&](const AppId& installed_app_id) { |
| EXPECT_THAT( |
| tester.GetAllSamples("WebApp.FileHandlersRegistration.Result"), |
| BucketsAre(base::Bucket(true, 1))); |
| run_loop_install.Quit(); |
| })); |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| run_loop_install.Run(); |
| content::RunAllTasksUntilIdle(); |
| chrome::SetAutoAcceptWebAppDialogForTesting(false, false); |
| |
| #if BUILDFLAG(IS_WIN) |
| const std::wstring prog_id = |
| GetProgIdForApp(browser()->profile()->GetPath(), app_id); |
| const std::vector<std::wstring> file_handler_prog_ids = |
| ShellUtil::GetFileHandlerProgIdsForAppId(prog_id); |
| base::flat_map<std::wstring, std::wstring> reg_key_prog_id_map; |
| |
| std::vector<std::wstring> file_ext_reg_keys; |
| base::win::RegKey key; |
| for (const auto& file_handler_prog_id : file_handler_prog_ids) { |
| const std::vector<std::wstring> file_extensions = |
| GetFileExtensionsForProgId(file_handler_prog_id); |
| for (const auto& file_extension : file_extensions) { |
| const std::string extension = base::WideToUTF8(file_extension.substr(1)); |
| EXPECT_TRUE(base::Contains(expected_extensions, extension)) |
| << "Missing file extension: " << extension; |
| const std::wstring reg_key = |
| L"Software\\Classes\\" + file_extension + L"\\OpenWithProgids"; |
| reg_key_prog_id_map[reg_key] = file_handler_prog_id; |
| ASSERT_EQ(ERROR_SUCCESS, |
| key.Open(HKEY_CURRENT_USER, reg_key.data(), KEY_READ)); |
| EXPECT_TRUE(key.HasValue(file_handler_prog_id.data())); |
| } |
| } |
| #elif BUILDFLAG(IS_MAC) |
| for (auto extension : expected_extensions) { |
| const base::FilePath test_file_path = |
| registration->test_override->chrome_apps_folder().AppendASCII( |
| "test." + extension); |
| const base::File test_file(test_file_path, base::File::FLAG_CREATE_ALWAYS | |
| base::File::FLAG_WRITE); |
| const GURL test_file_url = net::FilePathToFileURL(test_file_path); |
| EXPECT_EQ(u"Manifest with file handlers", |
| shell_integration::GetApplicationNameForScheme(test_file_url)) |
| << "The default app to open the file is wrong. " |
| << "File extension: " + extension; |
| } |
| ASSERT_TRUE(registration->test_override->DeleteChromeAppsDir()); |
| #endif |
| |
| // Unistall the web app |
| NavigateToURLAndWait(browser(), GURL(chrome::kChromeUIAppsURL)); |
| base::RunLoop run_loop_uninstall; |
| WebAppProvider::GetForTest(profile())->install_finalizer().UninstallWebApp( |
| app_id, webapps::WebappUninstallSource::kAppsPage, |
| base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { |
| EXPECT_THAT( |
| tester.GetAllSamples("WebApp.FileHandlersUnregistration.Result"), |
| BucketsAre(base::Bucket(true, 1))); |
| EXPECT_EQ(code, webapps::UninstallResultCode::kSuccess); |
| run_loop_uninstall.Quit(); |
| })); |
| run_loop_uninstall.Run(); |
| |
| #if BUILDFLAG(IS_WIN) |
| // Check file associations after the web app is uninstalled. |
| // Check that HKCU/Software Classes/<filext>/ doesn't have the ProgId. |
| for (const auto& reg_key_prog_id : reg_key_prog_id_map) { |
| ASSERT_EQ(ERROR_SUCCESS, key.Open(HKEY_CURRENT_USER, |
| reg_key_prog_id.first.data(), KEY_READ)); |
| EXPECT_FALSE(key.HasValue(reg_key_prog_id.second.data())); |
| } |
| #endif |
| } |
| |
| // TODO(crbug.com/1270961): Disabled because it is flaky on Mac. |
| #if BUILDFLAG(IS_MAC) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_VERSION_11_0 |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_FileHandler, |
| UserDenyFileHandlingPermission) { |
| os_hooks_suppress_.reset(); |
| base::ScopedAllowBlockingForTesting allow_blocking; |
| |
| std::unique_ptr<OsIntegrationTestOverrideImpl::BlockingRegistration> |
| registration = |
| OsIntegrationTestOverrideImpl::OverrideForTesting(base::GetHomeDir()); |
| std::vector<std::string> expected_extensions{"bar", "baz", "foo", "foobar"}; |
| |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL app_url(embedded_test_server()->GetURL( |
| "/banners/" |
| "manifest_test_page.html?manifest=manifest_with_file_handlers.json")); |
| |
| NavigateToURLAndWait(browser(), app_url); |
| |
| // Wait for OS hooks and installation to complete. |
| chrome::SetAutoAcceptWebAppDialogForTesting(true, true); |
| base::RunLoop run_loop_install; |
| WebAppInstallManagerObserverAdapter observer(profile()); |
| observer.SetWebAppInstalledWithOsHooksDelegate(base::BindLambdaForTesting( |
| [&](const AppId& installed_app_id) { run_loop_install.Quit(); })); |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| run_loop_install.Run(); |
| content::RunAllTasksUntilIdle(); |
| chrome::SetAutoAcceptWebAppDialogForTesting(false, false); |
| |
| // Simulate the user permanently denying file handling permission. Regression |
| // test for crbug.com/1269387 |
| base::RunLoop run_loop_remove_file_handlers; |
| PersistFileHandlersUserChoice(browser()->profile(), app_id, /*allowed=*/false, |
| run_loop_remove_file_handlers.QuitClosure()); |
| run_loop_remove_file_handlers.Run(); |
| |
| for (auto extension : expected_extensions) { |
| const base::FilePath test_file_path = |
| registration->test_override->chrome_apps_folder().AppendASCII( |
| "test." + extension); |
| const base::File test_file(test_file_path, base::File::FLAG_CREATE_ALWAYS | |
| base::File::FLAG_WRITE); |
| const GURL test_file_url = net::FilePathToFileURL(test_file_path); |
| while (u"Manifest with file handlers" == |
| shell_integration::GetApplicationNameForScheme(test_file_url)) { |
| base::RunLoop delay_loop; |
| base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( |
| FROM_HERE, delay_loop.QuitClosure(), base::Milliseconds(100)); |
| delay_loop.Run(); |
| } |
| } |
| ASSERT_TRUE(registration->test_override->DeleteChromeAppsDir()); |
| |
| // Unistall the web app |
| NavigateToURLAndWait(browser(), GURL(chrome::kChromeUIAppsURL)); |
| base::RunLoop run_loop_uninstall; |
| WebAppProvider::GetForTest(profile())->install_finalizer().UninstallWebApp( |
| app_id, webapps::WebappUninstallSource::kAppsPage, |
| base::BindLambdaForTesting([&](webapps::UninstallResultCode code) { |
| EXPECT_EQ(code, webapps::UninstallResultCode::kSuccess); |
| run_loop_uninstall.Quit(); |
| })); |
| run_loop_uninstall.Run(); |
| } |
| #endif // BUILDFLAG(IS_MAC) |
| #endif // BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN) |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, PRE_UninstallIncompleteUninstall) { |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| |
| NavigateToURLAndWait(browser(), GetInstallableAppURL()); |
| |
| // Wait for OS hooks and installation to complete and the app to launch. |
| base::RunLoop run_loop_install; |
| WebAppInstallManagerObserverAdapter observer(profile()); |
| observer.SetWebAppInstalledWithOsHooksDelegate(base::BindLambdaForTesting( |
| [&](const AppId& installed_app_id) { run_loop_install.Quit(); })); |
| const AppId app_id = test::InstallPwaForCurrentUrl(browser()); |
| run_loop_install.Run(); |
| |
| EXPECT_TRUE(provider->registrar_unsafe().IsInstalled(app_id)); |
| EXPECT_EQ(provider->registrar_unsafe().GetAppShortName(app_id), |
| GetInstallableAppName()); |
| // This does NOT uninstall the web app, it just flags it for uninstall on |
| // startup. |
| { |
| ScopedRegistryUpdate update(&provider->sync_bridge_unsafe()); |
| WebApp* web_app = update->UpdateApp(app_id); |
| ASSERT_TRUE(web_app); |
| web_app->SetIsUninstalling(true); |
| } |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest, UninstallIncompleteUninstall) { |
| auto* provider = WebAppProvider::GetForTest(profile()); |
| // The uninstall-on-startup code schedules tasks to uninstall flagged apps on |
| // startup. For this test, either: |
| // 1) The webapp was uninstalled during test startup, when it is waiting for |
| // the WebAppProvider to be ready, or |
| // 2) It hasn't been uninstalled yet. |
| // The test body here handles both cases, and ensures that the app has been |
| // uninstalled. |
| std::set<AppId> apps; |
| for (const auto& web_app : |
| provider->registrar_unsafe().GetAppsIncludingStubs()) { |
| EXPECT_TRUE(web_app.is_uninstalling()); |
| apps.insert(web_app.app_id()); |
| } |
| EXPECT_TRUE(apps.size() == 0 || apps.size() == 1); |
| if (apps.size() != 0) { |
| WebAppTestUninstallObserver observer(profile()); |
| observer.BeginListeningAndWait(apps); |
| } |
| // TODO(dmurph): Remove AppSet, it's too hard to use. |
| int app_count = 0; |
| const web_app::WebAppRegistrar::AppSet& app_set = |
| provider->registrar_unsafe().GetAppsIncludingStubs(); |
| for (auto it = app_set.begin(); it != app_set.end(); ++it) { |
| ++app_count; |
| } |
| EXPECT_EQ(app_count, 0); |
| } |
| |
| // Verifies the behavior of the App/site settings link in the page info bubble. |
| class WebAppBrowserTest_PageInfoManagementLink : public WebAppBrowserTest { |
| public: |
| bool ShowingAppManagementLink(Browser* browser) { |
| int unused_id, unused_id2; |
| return GetLabelIdsForAppManagementLinkInPageInfo( |
| browser->tab_strip_model()->GetActiveWebContents(), &unused_id, |
| &unused_id2); |
| } |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_PageInfoManagementLink, Reparenting) { |
| const GURL app_url = GetSecureAppURL(); |
| InstallPWA(app_url); |
| |
| NavigateToURLAndWait(browser(), app_url); |
| content::WebContents* tab_contents = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| ASSERT_EQ(tab_contents->GetLastCommittedURL(), app_url); |
| |
| // After a normal (e.g. typed) navigation, should not show the app settings |
| // link. |
| EXPECT_FALSE(ShowingAppManagementLink(browser())); |
| // Reparent into app browser window. |
| Browser* const app_browser = ReparentWebAppForActiveTab(browser()); |
| // The leftover tab in the tabbed browser window should not be appy. |
| EXPECT_FALSE(ShowingAppManagementLink(browser())); |
| // After reparenting into an app browser, should show the app settings link. |
| EXPECT_TRUE(ShowingAppManagementLink(app_browser)); |
| |
| // Move back into tabbed browser: should keep showing the app settings link. |
| Browser* tabbed_browser = chrome::OpenInChrome(app_browser); |
| EXPECT_TRUE(ShowingAppManagementLink(tabbed_browser)); |
| } |
| |
| // Verifies behavior when an app window is opened by navigating with |
| // `open_pwa_window_if_possible` set to true. |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_PageInfoManagementLink, |
| OpenAppWindowIfPossible) { |
| const GURL app_url = GetSecureAppURL(); |
| InstallPWA(app_url); |
| |
| NavigateParams params(browser(), app_url, ui::PAGE_TRANSITION_LINK); |
| params.window_action = NavigateParams::SHOW_WINDOW; |
| params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; |
| params.open_pwa_window_if_possible = true; |
| ui_test_utils::NavigateToURL(¶ms); |
| |
| EXPECT_NE(browser(), params.browser); |
| EXPECT_FALSE(params.browser->is_type_normal()); |
| EXPECT_TRUE(params.browser->is_type_app()); |
| EXPECT_TRUE(params.browser->is_trusted_source()); |
| |
| EXPECT_TRUE(ShowingAppManagementLink(params.browser)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(WebAppBrowserTest_PageInfoManagementLink, LaunchAsTab) { |
| const GURL app_url = GetSecureAppURL(); |
| const AppId app_id = InstallPWA(app_url); |
| |
| // A non appy tab is showing, so the app settings link should not be visible. |
| EXPECT_FALSE(ShowingAppManagementLink(browser())); |
| |
| // *Launch* the app as a tab in a normal browser window. The app settings link |
| // should be visible. |
| Browser* tabbed_browser = LaunchBrowserForWebAppInTab(app_id); |
| EXPECT_EQ(browser(), tabbed_browser); |
| EXPECT_TRUE(ShowingAppManagementLink(tabbed_browser)); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| All, |
| WebAppBrowserTest_ExternalPrefMigration, |
| ::testing::Values( |
| test::ExternalPrefMigrationTestCases::kDisableMigrationReadPref, |
| test::ExternalPrefMigrationTestCases::kDisableMigrationReadDB, |
| test::ExternalPrefMigrationTestCases::kEnableMigrationReadPref, |
| test::ExternalPrefMigrationTestCases::kEnableMigrationReadDB), |
| test::GetExternalPrefMigrationTestName); |
| |
| } // namespace web_app |