| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/web_applications/web_app_registrar.h" |
| |
| #include <memory> |
| #include <set> |
| #include <string> |
| #include <utility> |
| |
| #include "base/callback_helpers.h" |
| #include "base/containers/contains.h" |
| #include "base/logging.h" |
| #include "base/notreached.h" |
| #include "base/run_loop.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/test/bind.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "build/chromeos_buildflags.h" |
| #include "chrome/browser/web_applications/commands/run_on_os_login_command.h" |
| #include "chrome/browser/web_applications/policy/web_app_policy_manager.h" |
| #include "chrome/browser/web_applications/test/fake_web_app_database_factory.h" |
| #include "chrome/browser/web_applications/test/fake_web_app_registry_controller.h" |
| #include "chrome/browser/web_applications/test/web_app_test.h" |
| #include "chrome/browser/web_applications/test/web_app_test_utils.h" |
| #include "chrome/browser/web_applications/user_display_mode.h" |
| #include "chrome/browser/web_applications/web_app.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_registry_update.h" |
| #include "chrome/browser/web_applications/web_app_sync_bridge.h" |
| #include "chrome/browser/web_applications/web_app_utils.h" |
| #include "content/public/common/content_features.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/abseil-cpp/absl/types/optional.h" |
| #include "url/gurl.h" |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| #include "ash/constants/ash_features.h" |
| #include "chrome/browser/web_applications/test/with_crosapi_param.h" |
| |
| using web_app::test::CrosapiParam; |
| using web_app::test::WithCrosapiParam; |
| #endif |
| |
| namespace web_app { |
| |
| namespace { |
| |
| Registry CreateRegistryForTesting(const std::string& base_url, int num_apps) { |
| Registry registry; |
| |
| for (int i = 0; i < num_apps; ++i) { |
| const auto url = base_url + base::NumberToString(i); |
| const AppId app_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, GURL(url)); |
| |
| auto web_app = std::make_unique<WebApp>(app_id); |
| web_app->AddSource(WebAppManagement::kSync); |
| web_app->SetStartUrl(GURL(url)); |
| web_app->SetName("Name" + base::NumberToString(i)); |
| web_app->SetDisplayMode(DisplayMode::kBrowser); |
| web_app->SetUserDisplayMode(UserDisplayMode::kBrowser); |
| |
| registry.emplace(app_id, std::move(web_app)); |
| } |
| |
| return registry; |
| } |
| |
| int CountApps(const WebAppRegistrar::AppSet& app_set) { |
| int count = 0; |
| for (const auto& web_app : app_set) { |
| EXPECT_FALSE(web_app.is_uninstalling()); |
| ++count; |
| } |
| return count; |
| } |
| |
| } // namespace |
| |
| class WebAppRegistrarTest : public WebAppTest { |
| public: |
| void SetUp() override { |
| WebAppTest::SetUp(); |
| |
| fake_registry_controller_ = |
| std::make_unique<FakeWebAppRegistryController>(); |
| fake_registry_controller_->SetUp(profile()); |
| } |
| |
| protected: |
| FakeWebAppRegistryController& controller() { |
| return *fake_registry_controller_; |
| } |
| |
| FakeWebAppDatabaseFactory& database_factory() { |
| return controller().database_factory(); |
| } |
| WebAppRegistrar& registrar() { return controller().registrar(); } |
| WebAppRegistrarMutable& mutable_registrar() { |
| return controller().mutable_registrar(); |
| } |
| WebAppSyncBridge& sync_bridge() { return controller().sync_bridge(); } |
| |
| std::set<AppId> RegisterAppsForTesting(Registry registry) { |
| std::set<AppId> ids; |
| |
| ScopedRegistryUpdate update(&sync_bridge()); |
| for (auto& kv : registry) { |
| ids.insert(kv.first); |
| update->CreateApp(std::move(kv.second)); |
| } |
| |
| return ids; |
| } |
| |
| void RegisterApp(std::unique_ptr<WebApp> web_app) { |
| controller().RegisterApp(std::move(web_app)); |
| } |
| |
| void UnregisterApp(const AppId& app_id) { |
| controller().UnregisterApp(app_id); |
| } |
| |
| void UnregisterAll() { controller().UnregisterAll(); } |
| |
| AppId InitRegistrarWithApp(std::unique_ptr<WebApp> app) { |
| DCHECK(registrar().is_empty()); |
| |
| AppId app_id = app->app_id(); |
| |
| Registry registry; |
| registry.emplace(app_id, std::move(app)); |
| |
| InitRegistrarWithRegistry(registry); |
| return app_id; |
| } |
| |
| std::set<AppId> InitRegistrarWithApps(const std::string& base_url, |
| int num_apps) { |
| DCHECK(registrar().is_empty()); |
| |
| Registry registry = CreateRegistryForTesting(base_url, num_apps); |
| return InitRegistrarWithRegistry(registry); |
| } |
| |
| std::set<AppId> InitRegistrarWithRegistry(const Registry& registry) { |
| std::set<AppId> app_ids; |
| for (auto& kv : registry) |
| app_ids.insert(kv.second->app_id()); |
| |
| database_factory().WriteRegistry(registry); |
| controller().Init(); |
| |
| return app_ids; |
| } |
| |
| void SyncBridgeCommitUpdate(std::unique_ptr<WebAppRegistryUpdate> update) { |
| base::RunLoop run_loop; |
| sync_bridge().CommitUpdate(std::move(update), |
| base::BindLambdaForTesting([&](bool success) { |
| EXPECT_TRUE(success); |
| run_loop.Quit(); |
| })); |
| |
| run_loop.Run(); |
| } |
| |
| private: |
| std::unique_ptr<FakeWebAppRegistryController> fake_registry_controller_; |
| }; |
| |
| class WebAppRegistrarTest_TabStrip : public WebAppRegistrarTest { |
| public: |
| WebAppRegistrarTest_TabStrip() = default; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_{ |
| features::kDesktopPWAsTabStrip}; |
| }; |
| |
| TEST_F(WebAppRegistrarTest, CreateRegisterUnregister) { |
| controller().Init(); |
| |
| EXPECT_EQ(nullptr, registrar().GetAppById(AppId())); |
| EXPECT_FALSE(registrar().GetAppById(AppId())); |
| |
| const GURL start_url = GURL("https://example.com/path"); |
| const AppId app_id = GenerateAppId(/*manifest_id=*/absl::nullopt, start_url); |
| const std::string name = "Name"; |
| const std::string description = "Description"; |
| const GURL scope = GURL("https://example.com/scope"); |
| const absl::optional<SkColor> theme_color = 0xAABBCCDD; |
| |
| const GURL start_url2 = GURL("https://example.com/path2"); |
| const AppId app_id2 = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, start_url2); |
| |
| auto web_app = std::make_unique<WebApp>(app_id); |
| auto web_app2 = std::make_unique<WebApp>(app_id2); |
| |
| web_app->AddSource(WebAppManagement::kSync); |
| web_app->SetDisplayMode(DisplayMode::kStandalone); |
| web_app->SetUserDisplayMode(UserDisplayMode::kStandalone); |
| web_app->SetName(name); |
| web_app->SetDescription(description); |
| web_app->SetStartUrl(start_url); |
| web_app->SetScope(scope); |
| web_app->SetThemeColor(theme_color); |
| |
| web_app2->AddSource(WebAppManagement::kDefault); |
| web_app2->SetDisplayMode(DisplayMode::kBrowser); |
| web_app2->SetUserDisplayMode(UserDisplayMode::kBrowser); |
| web_app2->SetStartUrl(start_url2); |
| web_app2->SetName(name); |
| |
| EXPECT_EQ(nullptr, registrar().GetAppById(app_id)); |
| EXPECT_EQ(nullptr, registrar().GetAppById(app_id2)); |
| EXPECT_TRUE(registrar().is_empty()); |
| |
| RegisterApp(std::move(web_app)); |
| EXPECT_TRUE(registrar().IsInstalled(app_id)); |
| const WebApp* app = registrar().GetAppById(app_id); |
| |
| EXPECT_EQ(app_id, app->app_id()); |
| EXPECT_EQ(name, app->untranslated_name()); |
| EXPECT_EQ(description, app->untranslated_description()); |
| EXPECT_EQ(start_url, app->start_url()); |
| EXPECT_EQ(scope, app->scope()); |
| EXPECT_EQ(theme_color, app->theme_color()); |
| |
| EXPECT_EQ(nullptr, registrar().GetAppById(app_id2)); |
| EXPECT_FALSE(registrar().is_empty()); |
| |
| RegisterApp(std::move(web_app2)); |
| EXPECT_TRUE(registrar().IsInstalled(app_id2)); |
| const WebApp* app2 = registrar().GetAppById(app_id2); |
| EXPECT_EQ(app_id2, app2->app_id()); |
| EXPECT_FALSE(registrar().is_empty()); |
| EXPECT_EQ(CountApps(registrar().GetApps()), 2); |
| |
| UnregisterApp(app_id); |
| EXPECT_FALSE(registrar().IsInstalled(app_id)); |
| EXPECT_EQ(nullptr, registrar().GetAppById(app_id)); |
| EXPECT_FALSE(registrar().is_empty()); |
| |
| // Check that app2 is still registered. |
| app2 = registrar().GetAppById(app_id2); |
| EXPECT_TRUE(registrar().IsInstalled(app_id2)); |
| EXPECT_EQ(app_id2, app2->app_id()); |
| |
| UnregisterApp(app_id2); |
| EXPECT_FALSE(registrar().IsInstalled(app_id2)); |
| EXPECT_EQ(nullptr, registrar().GetAppById(app_id2)); |
| EXPECT_TRUE(registrar().is_empty()); |
| EXPECT_EQ(CountApps(registrar().GetApps()), 0); |
| } |
| |
| TEST_F(WebAppRegistrarTest, DestroyRegistrarOwningRegisteredApps) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(GURL("https://example.com/path")); |
| RegisterApp(std::move(web_app)); |
| |
| auto web_app2 = test::CreateWebApp(GURL("https://example.com/path2")); |
| RegisterApp(std::move(web_app2)); |
| |
| controller().DestroySubsystems(); |
| } |
| |
| TEST_F(WebAppRegistrarTest, InitRegistrarAndDoForEachApp) { |
| std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 100); |
| |
| for (const WebApp& web_app : registrar().GetAppsIncludingStubs()) { |
| const size_t num_removed = ids.erase(web_app.app_id()); |
| EXPECT_EQ(1U, num_removed); |
| } |
| |
| EXPECT_TRUE(ids.empty()); |
| } |
| |
| TEST_F(WebAppRegistrarTest, GetAppsIncludingStubsMutable) { |
| std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 10); |
| |
| for (WebApp& web_app : mutable_registrar().GetAppsIncludingStubsMutable()) { |
| web_app.SetDisplayMode(DisplayMode::kStandalone); |
| const size_t num_removed = ids.erase(web_app.app_id()); |
| EXPECT_EQ(1U, num_removed); |
| } |
| |
| EXPECT_TRUE(ids.empty()); |
| } |
| |
| TEST_F(WebAppRegistrarTest, DoForEachAndUnregisterAllApps) { |
| controller().Init(); |
| |
| Registry registry = CreateRegistryForTesting("https://example.com/path", 100); |
| auto ids = RegisterAppsForTesting(std::move(registry)); |
| EXPECT_EQ(100UL, ids.size()); |
| |
| for (const WebApp& web_app : registrar().GetAppsIncludingStubs()) { |
| const size_t num_removed = ids.erase(web_app.app_id()); |
| EXPECT_EQ(1U, num_removed); |
| } |
| EXPECT_TRUE(ids.empty()); |
| |
| EXPECT_FALSE(registrar().is_empty()); |
| UnregisterAll(); |
| EXPECT_TRUE(registrar().is_empty()); |
| } |
| |
| TEST_F(WebAppRegistrarTest, FilterApps) { |
| controller().Init(); |
| |
| Registry registry = CreateRegistryForTesting("https://example.com/path", 100); |
| auto ids = RegisterAppsForTesting(std::move(registry)); |
| |
| for ([[maybe_unused]] const WebApp& web_app : |
| mutable_registrar().FilterAppsMutableForTesting( |
| [](const WebApp& web_app) { return false; })) { |
| NOTREACHED(); |
| } |
| |
| for (const WebApp& web_app : mutable_registrar().FilterAppsMutableForTesting( |
| [](const WebApp& web_app) { return true; })) { |
| const size_t num_removed = ids.erase(web_app.app_id()); |
| EXPECT_EQ(1U, num_removed); |
| } |
| EXPECT_TRUE(ids.empty()); |
| } |
| |
| TEST_F(WebAppRegistrarTest, GetApps) { |
| std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 10); |
| |
| int not_in_sync_install_count = 0; |
| for (const WebApp& web_app : registrar().GetApps()) { |
| ++not_in_sync_install_count; |
| EXPECT_TRUE(base::Contains(ids, web_app.app_id())); |
| } |
| EXPECT_EQ(10, not_in_sync_install_count); |
| |
| auto web_app_in_sync1 = test::CreateWebApp(GURL("https://example.org/sync1")); |
| web_app_in_sync1->SetIsFromSyncAndPendingInstallation(true); |
| const AppId web_app_id_in_sync1 = web_app_in_sync1->app_id(); |
| RegisterApp(std::move(web_app_in_sync1)); |
| |
| auto web_app_in_sync2 = test::CreateWebApp(GURL("https://example.org/sync2")); |
| web_app_in_sync2->SetIsFromSyncAndPendingInstallation(true); |
| const AppId web_app_id_in_sync2 = web_app_in_sync2->app_id(); |
| RegisterApp(std::move(web_app_in_sync2)); |
| |
| int all_apps_count = 0; |
| for ([[maybe_unused]] const WebApp& web_app : |
| registrar().GetAppsIncludingStubs()) { |
| ++all_apps_count; |
| } |
| EXPECT_EQ(12, all_apps_count); |
| |
| for (const WebApp& web_app : registrar().GetApps()) { |
| EXPECT_NE(web_app_id_in_sync1, web_app.app_id()); |
| EXPECT_NE(web_app_id_in_sync2, web_app.app_id()); |
| |
| const size_t num_removed = ids.erase(web_app.app_id()); |
| EXPECT_EQ(1U, num_removed); |
| } |
| EXPECT_TRUE(ids.empty()); |
| |
| UnregisterApp(web_app_id_in_sync1); |
| UnregisterApp(web_app_id_in_sync2); |
| |
| not_in_sync_install_count = 0; |
| for ([[maybe_unused]] const WebApp& web_app : registrar().GetApps()) { |
| ++not_in_sync_install_count; |
| } |
| EXPECT_EQ(10, not_in_sync_install_count); |
| } |
| |
| TEST_F(WebAppRegistrarTest, WebAppSyncBridge) { |
| std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 100); |
| |
| // Add 1 app after Init. |
| auto web_app = test::CreateWebApp(GURL("https://example.com/path")); |
| const AppId app_id = web_app->app_id(); |
| |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(101UL, database_factory().ReadAllAppIds().size()); |
| EXPECT_EQ(101UL, controller().mutable_registrar().registry().size()); |
| |
| // Remove 1 app after Init. |
| UnregisterApp(app_id); |
| EXPECT_EQ(100UL, controller().mutable_registrar().registry().size()); |
| EXPECT_EQ(100UL, database_factory().ReadAllAppIds().size()); |
| |
| // Remove 100 apps after Init. |
| UnregisterAll(); |
| EXPECT_TRUE(database_factory().ReadAllAppIds().empty()); |
| EXPECT_TRUE(registrar().is_empty()); |
| } |
| |
| TEST_F(WebAppRegistrarTest, GetAppDataFields) { |
| controller().Init(); |
| |
| const GURL start_url = GURL("https://example.com/path"); |
| const AppId app_id = GenerateAppId(/*manifest_id=*/absl::nullopt, start_url); |
| const std::string name = "Name"; |
| const std::string description = "Description"; |
| const absl::optional<SkColor> theme_color = 0xAABBCCDD; |
| const auto display_mode = DisplayMode::kMinimalUi; |
| const auto user_display_mode = UserDisplayMode::kStandalone; |
| std::vector<DisplayMode> display_mode_override; |
| |
| EXPECT_EQ(std::string(), registrar().GetAppShortName(app_id)); |
| EXPECT_EQ(GURL(), registrar().GetAppStartUrl(app_id)); |
| |
| auto web_app = std::make_unique<WebApp>(app_id); |
| WebApp* web_app_ptr = web_app.get(); |
| |
| display_mode_override.push_back(DisplayMode::kMinimalUi); |
| display_mode_override.push_back(DisplayMode::kStandalone); |
| |
| web_app->AddSource(WebAppManagement::kSync); |
| web_app->SetName(name); |
| web_app->SetDescription(description); |
| web_app->SetThemeColor(theme_color); |
| web_app->SetStartUrl(start_url); |
| web_app->SetDisplayMode(display_mode); |
| web_app->SetUserDisplayMode(user_display_mode); |
| web_app->SetDisplayModeOverride(display_mode_override); |
| web_app->SetIsLocallyInstalled(/*is_locally_installed*/ false); |
| |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(name, registrar().GetAppShortName(app_id)); |
| EXPECT_EQ(description, registrar().GetAppDescription(app_id)); |
| EXPECT_EQ(theme_color, registrar().GetAppThemeColor(app_id)); |
| EXPECT_EQ(start_url, registrar().GetAppStartUrl(app_id)); |
| EXPECT_EQ(UserDisplayMode::kStandalone, |
| registrar().GetAppUserDisplayMode(app_id)); |
| |
| { |
| std::vector<DisplayMode> app_display_mode_override = |
| registrar().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]); |
| } |
| |
| { |
| EXPECT_FALSE(registrar().IsLocallyInstalled(app_id)); |
| EXPECT_FALSE(registrar().IsActivelyInstalled(app_id)); |
| |
| EXPECT_FALSE(registrar().IsLocallyInstalled("unknown")); |
| web_app_ptr->SetIsLocallyInstalled(/*is_locally_installed*/ true); |
| EXPECT_TRUE(registrar().IsLocallyInstalled(app_id)); |
| EXPECT_TRUE(registrar().IsActivelyInstalled(app_id)); |
| } |
| |
| { |
| EXPECT_FALSE(registrar().GetAppUserDisplayMode("unknown").has_value()); |
| |
| web_app_ptr->SetUserDisplayMode(UserDisplayMode::kBrowser); |
| EXPECT_EQ(UserDisplayMode::kBrowser, |
| registrar().GetAppUserDisplayMode(app_id)); |
| |
| sync_bridge().SetAppUserDisplayMode(app_id, UserDisplayMode::kStandalone, |
| /*is_user_action=*/false); |
| EXPECT_EQ(UserDisplayMode::kStandalone, web_app_ptr->user_display_mode()); |
| EXPECT_EQ(DisplayMode::kMinimalUi, web_app_ptr->display_mode()); |
| |
| ASSERT_EQ(2u, web_app_ptr->display_mode_override().size()); |
| EXPECT_EQ(DisplayMode::kMinimalUi, web_app_ptr->display_mode_override()[0]); |
| EXPECT_EQ(DisplayMode::kStandalone, |
| web_app_ptr->display_mode_override()[1]); |
| } |
| } |
| |
| TEST_F(WebAppRegistrarTest, CanFindAppsInScope) { |
| controller().Init(); |
| |
| const GURL origin_scope("https://example.com/"); |
| |
| const GURL app1_scope("https://example.com/app"); |
| const GURL app2_scope("https://example.com/app-two"); |
| const GURL app3_scope("https://not-example.com/app"); |
| |
| const AppId app1_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app1_scope); |
| const AppId app2_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app2_scope); |
| const AppId app3_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app3_scope); |
| |
| std::vector<AppId> in_scope = registrar().FindAppsInScope(origin_scope); |
| EXPECT_EQ(0u, in_scope.size()); |
| EXPECT_FALSE(registrar().DoesScopeContainAnyApp(origin_scope)); |
| EXPECT_FALSE(registrar().DoesScopeContainAnyApp(app3_scope)); |
| |
| auto app1 = test::CreateWebApp(app1_scope); |
| app1->SetScope(app1_scope); |
| RegisterApp(std::move(app1)); |
| |
| in_scope = registrar().FindAppsInScope(origin_scope); |
| EXPECT_THAT(in_scope, testing::UnorderedElementsAre(app1_id)); |
| EXPECT_TRUE(registrar().DoesScopeContainAnyApp(origin_scope)); |
| EXPECT_FALSE(registrar().DoesScopeContainAnyApp(app3_scope)); |
| |
| in_scope = registrar().FindAppsInScope(app1_scope); |
| EXPECT_THAT(in_scope, testing::UnorderedElementsAre(app1_id)); |
| EXPECT_TRUE(registrar().DoesScopeContainAnyApp(app1_scope)); |
| |
| auto app2 = test::CreateWebApp(app2_scope); |
| app2->SetScope(app2_scope); |
| RegisterApp(std::move(app2)); |
| |
| in_scope = registrar().FindAppsInScope(origin_scope); |
| EXPECT_THAT(in_scope, testing::UnorderedElementsAre(app1_id, app2_id)); |
| EXPECT_TRUE(registrar().DoesScopeContainAnyApp(origin_scope)); |
| EXPECT_FALSE(registrar().DoesScopeContainAnyApp(app3_scope)); |
| |
| in_scope = registrar().FindAppsInScope(app1_scope); |
| EXPECT_THAT(in_scope, testing::UnorderedElementsAre(app1_id, app2_id)); |
| EXPECT_TRUE(registrar().DoesScopeContainAnyApp(app1_scope)); |
| |
| in_scope = registrar().FindAppsInScope(app2_scope); |
| EXPECT_THAT(in_scope, testing::UnorderedElementsAre(app2_id)); |
| EXPECT_TRUE(registrar().DoesScopeContainAnyApp(app2_scope)); |
| |
| auto app3 = test::CreateWebApp(app3_scope); |
| app3->SetScope(app3_scope); |
| RegisterApp(std::move(app3)); |
| |
| in_scope = registrar().FindAppsInScope(origin_scope); |
| EXPECT_THAT(in_scope, testing::UnorderedElementsAre(app1_id, app2_id)); |
| EXPECT_TRUE(registrar().DoesScopeContainAnyApp(origin_scope)); |
| |
| in_scope = registrar().FindAppsInScope(app3_scope); |
| EXPECT_THAT(in_scope, testing::UnorderedElementsAre(app3_id)); |
| EXPECT_TRUE(registrar().DoesScopeContainAnyApp(app3_scope)); |
| } |
| |
| TEST_F(WebAppRegistrarTest, CanFindAppWithUrlInScope) { |
| controller().Init(); |
| |
| const GURL origin_scope("https://example.com/"); |
| |
| const GURL app1_scope("https://example.com/app"); |
| const GURL app2_scope("https://example.com/app-two"); |
| const GURL app3_scope("https://not-example.com/app"); |
| const GURL app4_scope("https://app-four.com/"); |
| |
| const AppId app1_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app1_scope); |
| const AppId app2_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app2_scope); |
| const AppId app3_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app3_scope); |
| const AppId app4_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app3_scope); |
| |
| auto app1 = test::CreateWebApp(app1_scope); |
| app1->SetScope(app1_scope); |
| RegisterApp(std::move(app1)); |
| |
| absl::optional<AppId> app2_match = |
| registrar().FindAppWithUrlInScope(app2_scope); |
| DCHECK(app2_match); |
| EXPECT_EQ(*app2_match, app1_id); |
| |
| absl::optional<AppId> app3_match = |
| registrar().FindAppWithUrlInScope(app3_scope); |
| EXPECT_FALSE(app3_match); |
| |
| absl::optional<AppId> app4_match = |
| registrar().FindAppWithUrlInScope(app4_scope); |
| EXPECT_FALSE(app4_match); |
| |
| auto app2 = test::CreateWebApp(app2_scope); |
| app2->SetScope(app2_scope); |
| RegisterApp(std::move(app2)); |
| |
| auto app3 = test::CreateWebApp(app3_scope); |
| app3->SetScope(app3_scope); |
| RegisterApp(std::move(app3)); |
| |
| auto app4 = test::CreateWebApp(app4_scope); |
| app4->SetScope(app4_scope); |
| app4->SetIsUninstalling(true); |
| RegisterApp(std::move(app4)); |
| |
| absl::optional<AppId> origin_match = |
| registrar().FindAppWithUrlInScope(origin_scope); |
| EXPECT_FALSE(origin_match); |
| |
| absl::optional<AppId> app1_match = |
| registrar().FindAppWithUrlInScope(app1_scope); |
| DCHECK(app1_match); |
| EXPECT_EQ(*app1_match, app1_id); |
| |
| app2_match = registrar().FindAppWithUrlInScope(app2_scope); |
| DCHECK(app2_match); |
| EXPECT_EQ(*app2_match, app2_id); |
| |
| app3_match = registrar().FindAppWithUrlInScope(app3_scope); |
| DCHECK(app3_match); |
| EXPECT_EQ(*app3_match, app3_id); |
| |
| // Apps in the process of uninstalling are ignored. |
| app4_match = registrar().FindAppWithUrlInScope(app4_scope); |
| EXPECT_FALSE(app4_match); |
| } |
| |
| TEST_F(WebAppRegistrarTest, CanFindShortcutWithUrlInScope) { |
| controller().Init(); |
| |
| const GURL app1_page("https://example.com/app/page"); |
| const GURL app2_page("https://example.com/app-two/page"); |
| const GURL app3_page("https://not-example.com/app/page"); |
| |
| const GURL app1_launch("https://example.com/app/launch"); |
| const GURL app2_launch("https://example.com/app-two/launch"); |
| const GURL app3_launch("https://not-example.com/app/launch"); |
| |
| const AppId app1_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app1_launch); |
| const AppId app2_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app2_launch); |
| const AppId app3_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app3_launch); |
| |
| // Implicit scope "https://example.com/app/" |
| auto app1 = test::CreateWebApp(app1_launch); |
| RegisterApp(std::move(app1)); |
| |
| absl::optional<AppId> app2_match = |
| registrar().FindAppWithUrlInScope(app2_page); |
| EXPECT_FALSE(app2_match); |
| |
| absl::optional<AppId> app3_match = |
| registrar().FindAppWithUrlInScope(app3_page); |
| EXPECT_FALSE(app3_match); |
| |
| auto app2 = test::CreateWebApp(app2_launch); |
| RegisterApp(std::move(app2)); |
| |
| auto app3 = test::CreateWebApp(app3_launch); |
| RegisterApp(std::move(app3)); |
| |
| absl::optional<AppId> app1_match = |
| registrar().FindAppWithUrlInScope(app1_page); |
| DCHECK(app1_match); |
| EXPECT_EQ(app1_match, absl::optional<AppId>(app1_id)); |
| |
| app2_match = registrar().FindAppWithUrlInScope(app2_page); |
| DCHECK(app2_match); |
| EXPECT_EQ(app2_match, absl::optional<AppId>(app2_id)); |
| |
| app3_match = registrar().FindAppWithUrlInScope(app3_page); |
| DCHECK(app3_match); |
| EXPECT_EQ(app3_match, absl::optional<AppId>(app3_id)); |
| } |
| |
| TEST_F(WebAppRegistrarTest, FindPwaOverShortcut) { |
| controller().Init(); |
| |
| const GURL app1_launch("https://example.com/app/specific/launch1"); |
| |
| const GURL app2_scope("https://example.com/app"); |
| const GURL app2_page("https://example.com/app/specific/page2"); |
| const AppId app2_id = |
| GenerateAppId(/*manifest_id=*/absl::nullopt, app2_scope); |
| |
| const GURL app3_launch("https://example.com/app/specific/launch3"); |
| |
| auto app1 = test::CreateWebApp(app1_launch); |
| RegisterApp(std::move(app1)); |
| |
| auto app2 = test::CreateWebApp(app2_scope); |
| app2->SetScope(app2_scope); |
| RegisterApp(std::move(app2)); |
| |
| auto app3 = test::CreateWebApp(app3_launch); |
| RegisterApp(std::move(app3)); |
| |
| absl::optional<AppId> app2_match = |
| registrar().FindAppWithUrlInScope(app2_page); |
| DCHECK(app2_match); |
| EXPECT_EQ(app2_match, absl::optional<AppId>(app2_id)); |
| } |
| |
| TEST_F(WebAppRegistrarTest, BeginAndCommitUpdate) { |
| std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 10); |
| |
| std::unique_ptr<WebAppRegistryUpdate> update = sync_bridge().BeginUpdate(); |
| |
| for (auto& app_id : ids) { |
| WebApp* app = update->UpdateApp(app_id); |
| EXPECT_TRUE(app); |
| app->SetName("New Name"); |
| } |
| |
| // Acquire each app second time to make sure update requests get merged. |
| for (auto& app_id : ids) { |
| WebApp* app = update->UpdateApp(app_id); |
| EXPECT_TRUE(app); |
| app->SetDisplayMode(DisplayMode::kStandalone); |
| } |
| |
| SyncBridgeCommitUpdate(std::move(update)); |
| |
| // Make sure that all app ids were written to the database. |
| auto registry_written = database_factory().ReadRegistry(); |
| EXPECT_EQ(ids.size(), registry_written.size()); |
| |
| for (auto& kv : registry_written) { |
| EXPECT_EQ("New Name", kv.second->untranslated_name()); |
| ids.erase(kv.second->app_id()); |
| } |
| |
| EXPECT_TRUE(ids.empty()); |
| } |
| |
| TEST_F(WebAppRegistrarTest, CommitEmptyUpdate) { |
| std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 10); |
| const auto initial_registry = database_factory().ReadRegistry(); |
| |
| { |
| std::unique_ptr<WebAppRegistryUpdate> update = sync_bridge().BeginUpdate(); |
| SyncBridgeCommitUpdate(std::move(update)); |
| |
| auto registry = database_factory().ReadRegistry(); |
| EXPECT_TRUE(IsRegistryEqual(initial_registry, registry)); |
| } |
| |
| { |
| std::unique_ptr<WebAppRegistryUpdate> update = sync_bridge().BeginUpdate(); |
| update.reset(); |
| SyncBridgeCommitUpdate(std::move(update)); |
| |
| auto registry = database_factory().ReadRegistry(); |
| EXPECT_TRUE(IsRegistryEqual(initial_registry, registry)); |
| } |
| |
| { |
| std::unique_ptr<WebAppRegistryUpdate> update = sync_bridge().BeginUpdate(); |
| |
| WebApp* app = update->UpdateApp("unknown"); |
| EXPECT_FALSE(app); |
| |
| SyncBridgeCommitUpdate(std::move(update)); |
| |
| auto registry = database_factory().ReadRegistry(); |
| EXPECT_TRUE(IsRegistryEqual(initial_registry, registry)); |
| } |
| } |
| |
| TEST_F(WebAppRegistrarTest, ScopedRegistryUpdate) { |
| std::set<AppId> ids = InitRegistrarWithApps("https://example.com/path", 10); |
| const auto initial_registry = database_factory().ReadRegistry(); |
| |
| // Test empty update first. |
| { ScopedRegistryUpdate update(&sync_bridge()); } |
| EXPECT_TRUE( |
| IsRegistryEqual(initial_registry, database_factory().ReadRegistry())); |
| |
| { |
| ScopedRegistryUpdate update(&sync_bridge()); |
| |
| for (auto& app_id : ids) { |
| WebApp* app = update->UpdateApp(app_id); |
| EXPECT_TRUE(app); |
| app->SetDescription("New Description"); |
| } |
| } |
| |
| // Make sure that all app ids were written to the database. |
| auto updated_registry = database_factory().ReadRegistry(); |
| EXPECT_EQ(ids.size(), updated_registry.size()); |
| |
| for (auto& kv : updated_registry) { |
| EXPECT_EQ(kv.second->untranslated_description(), "New Description"); |
| ids.erase(kv.second->app_id()); |
| } |
| |
| EXPECT_TRUE(ids.empty()); |
| } |
| |
| TEST_F(WebAppRegistrarTest, CopyOnWrite) { |
| controller().Init(); |
| |
| const GURL start_url("https://example.com"); |
| const AppId app_id = GenerateAppId(/*manifest_id=*/absl::nullopt, start_url); |
| const WebApp* app = nullptr; |
| { |
| auto new_app = test::CreateWebApp(start_url); |
| app = new_app.get(); |
| RegisterApp(std::move(new_app)); |
| } |
| |
| { |
| std::unique_ptr<WebAppRegistryUpdate> update = sync_bridge().BeginUpdate(); |
| |
| WebApp* app_copy = update->UpdateApp(app_id); |
| EXPECT_TRUE(app_copy); |
| EXPECT_NE(app_copy, app); |
| |
| app_copy->SetName("New Name"); |
| EXPECT_EQ(app_copy->untranslated_name(), "New Name"); |
| EXPECT_EQ(app->untranslated_name(), "Name"); |
| |
| app_copy->AddSource(WebAppManagement::kPolicy); |
| app_copy->RemoveSource(WebAppManagement::kSync); |
| |
| EXPECT_FALSE(app_copy->IsSynced()); |
| EXPECT_TRUE(app_copy->HasAnySources()); |
| |
| EXPECT_TRUE(app->IsSynced()); |
| EXPECT_TRUE(app->HasAnySources()); |
| |
| SyncBridgeCommitUpdate(std::move(update)); |
| } |
| |
| // Pointer value stays the same. |
| EXPECT_EQ(app, registrar().GetAppById(app_id)); |
| |
| EXPECT_EQ(app->untranslated_name(), "New Name"); |
| EXPECT_FALSE(app->IsSynced()); |
| EXPECT_TRUE(app->HasAnySources()); |
| } |
| |
| TEST_F(WebAppRegistrarTest, CountUserInstalledApps) { |
| controller().Init(); |
| |
| const std::string base_url{"https://example.com/path"}; |
| |
| for (int i = WebAppManagement::kMinValue + 1; |
| i <= WebAppManagement::kMaxValue; ++i) { |
| auto source = static_cast<WebAppManagement::Type>(i); |
| auto web_app = |
| test::CreateWebApp(GURL(base_url + base::NumberToString(i)), source); |
| RegisterApp(std::move(web_app)); |
| } |
| |
| EXPECT_EQ(2, registrar().CountUserInstalledApps()); |
| } |
| |
| TEST_F(WebAppRegistrarTest, |
| AppsFromSyncAndPendingInstallationExcludedFromGetAppIds) { |
| InitRegistrarWithApps("https://example.com/path/", 100); |
| |
| EXPECT_EQ(100u, registrar().GetAppIds().size()); |
| |
| std::unique_ptr<WebApp> web_app_in_sync_install = |
| test::CreateWebApp(GURL("https://example.org/")); |
| web_app_in_sync_install->SetIsFromSyncAndPendingInstallation(true); |
| |
| const AppId web_app_in_sync_install_id = web_app_in_sync_install->app_id(); |
| RegisterApp(std::move(web_app_in_sync_install)); |
| |
| // Tests that GetAppIds() excludes web app in sync install: |
| std::vector<AppId> ids = registrar().GetAppIds(); |
| EXPECT_EQ(100u, ids.size()); |
| for (const AppId& app_id : ids) |
| EXPECT_NE(app_id, web_app_in_sync_install_id); |
| |
| // Tests that GetAppsIncludingStubs() returns a web app which is either in |
| // GetAppIds() set or it is the web app in sync install: |
| bool web_app_in_sync_install_found = false; |
| for (const WebApp& web_app : registrar().GetAppsIncludingStubs()) { |
| if (web_app.app_id() == web_app_in_sync_install_id) |
| web_app_in_sync_install_found = true; |
| else |
| EXPECT_TRUE(base::Contains(ids, web_app.app_id())); |
| } |
| EXPECT_TRUE(web_app_in_sync_install_found); |
| } |
| |
| TEST_F(WebAppRegistrarTest, NotLocallyInstalledAppGetsDisplayModeBrowser) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(); |
| const AppId app_id = web_app->app_id(); |
| web_app->SetDisplayMode(DisplayMode::kStandalone); |
| web_app->SetUserDisplayMode(UserDisplayMode::kStandalone); |
| web_app->SetIsLocallyInstalled(false); |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(DisplayMode::kBrowser, |
| registrar().GetAppEffectiveDisplayMode(app_id)); |
| |
| sync_bridge().SetAppIsLocallyInstalled(app_id, true); |
| |
| EXPECT_EQ(DisplayMode::kStandalone, |
| registrar().GetAppEffectiveDisplayMode(app_id)); |
| } |
| |
| TEST_F(WebAppRegistrarTest, |
| NotLocallyInstalledAppGetsDisplayModeBrowserEvenForIsolatedApps) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(); |
| const AppId app_id = web_app->app_id(); |
| web_app->SetDisplayMode(DisplayMode::kStandalone); |
| web_app->SetUserDisplayMode(UserDisplayMode::kStandalone); |
| web_app->SetIsLocallyInstalled(false); |
| |
| // Not locally installed apps get browser display mode because they do not |
| // have information aboud isolation because manifest is not available. |
| web_app->SetStorageIsolated(true); |
| |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(DisplayMode::kBrowser, |
| registrar().GetAppEffectiveDisplayMode(app_id)); |
| } |
| |
| TEST_F(WebAppRegistrarTest, |
| IsolatedAppsGetDisplayModeStandaloneRegardlessOfUserSettings) { |
| controller().Init(); |
| |
| std::unique_ptr<WebApp> web_app = test::CreateWebApp(); |
| const AppId app_id = web_app->app_id(); |
| |
| // Valid manifest must have standalone display mode |
| web_app->SetDisplayMode(DisplayMode::kStandalone); |
| web_app->SetUserDisplayMode(UserDisplayMode::kBrowser); |
| web_app->SetIsLocallyInstalled(true); |
| web_app->SetStorageIsolated(true); |
| |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(DisplayMode::kStandalone, |
| registrar().GetAppEffectiveDisplayMode(app_id)); |
| } |
| |
| TEST_F(WebAppRegistrarTest, NotLocallyInstalledAppGetsDisplayModeOverride) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(); |
| const AppId app_id = web_app->app_id(); |
| std::vector<DisplayMode> display_mode_overrides; |
| display_mode_overrides.push_back(DisplayMode::kFullscreen); |
| display_mode_overrides.push_back(DisplayMode::kMinimalUi); |
| |
| web_app->SetDisplayMode(DisplayMode::kStandalone); |
| web_app->SetUserDisplayMode(UserDisplayMode::kStandalone); |
| web_app->SetDisplayModeOverride(display_mode_overrides); |
| web_app->SetIsLocallyInstalled(false); |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(DisplayMode::kBrowser, |
| registrar().GetAppEffectiveDisplayMode(app_id)); |
| |
| sync_bridge().SetAppIsLocallyInstalled(app_id, true); |
| |
| EXPECT_EQ(DisplayMode::kMinimalUi, |
| registrar().GetAppEffectiveDisplayMode(app_id)); |
| } |
| |
| TEST_F(WebAppRegistrarTest, |
| CheckDisplayOverrideFromGetEffectiveDisplayModeFromManifest) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(); |
| const AppId app_id = web_app->app_id(); |
| std::vector<DisplayMode> display_mode_overrides; |
| display_mode_overrides.push_back(DisplayMode::kFullscreen); |
| display_mode_overrides.push_back(DisplayMode::kMinimalUi); |
| |
| web_app->SetDisplayMode(DisplayMode::kStandalone); |
| web_app->SetUserDisplayMode(UserDisplayMode::kStandalone); |
| web_app->SetDisplayModeOverride(display_mode_overrides); |
| web_app->SetIsLocallyInstalled(false); |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(DisplayMode::kFullscreen, |
| registrar().GetEffectiveDisplayModeFromManifest(app_id)); |
| |
| sync_bridge().SetAppIsLocallyInstalled(app_id, true); |
| EXPECT_EQ(DisplayMode::kFullscreen, |
| registrar().GetEffectiveDisplayModeFromManifest(app_id)); |
| } |
| |
| TEST_F(WebAppRegistrarTest, WindowControlsOverlay) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(); |
| const AppId app_id = web_app->app_id(); |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(false, registrar().GetWindowControlsOverlayEnabled(app_id)); |
| |
| sync_bridge().SetAppWindowControlsOverlayEnabled(app_id, true); |
| EXPECT_EQ(true, registrar().GetWindowControlsOverlayEnabled(app_id)); |
| |
| sync_bridge().SetAppWindowControlsOverlayEnabled(app_id, false); |
| EXPECT_EQ(false, registrar().GetWindowControlsOverlayEnabled(app_id)); |
| } |
| |
| TEST_F(WebAppRegistrarTest, AllowedLaunchProtocols) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(GURL("https://example.com/path")); |
| const AppId app_id1 = web_app->app_id(); |
| const std::string protocol_scheme1 = "test"; |
| RegisterApp(std::move(web_app)); |
| |
| auto web_app2 = test::CreateWebApp(GURL("https://example.com/path2")); |
| const AppId app_id2 = web_app2->app_id(); |
| const std::string protocol_scheme2 = "test2"; |
| RegisterApp(std::move(web_app2)); |
| |
| // Test we can add and remove allowed protocols. |
| EXPECT_EQ(false, |
| registrar().IsAllowedLaunchProtocol(app_id1, protocol_scheme1)); |
| |
| sync_bridge().AddAllowedLaunchProtocol(app_id1, protocol_scheme1); |
| EXPECT_EQ(true, |
| registrar().IsAllowedLaunchProtocol(app_id1, protocol_scheme1)); |
| |
| sync_bridge().RemoveAllowedLaunchProtocol(app_id1, protocol_scheme1); |
| EXPECT_EQ(false, |
| registrar().IsAllowedLaunchProtocol(app_id1, protocol_scheme1)); |
| |
| // Test that we can get allowed protocols from multiple web apps. |
| sync_bridge().AddAllowedLaunchProtocol(app_id1, protocol_scheme1); |
| sync_bridge().AddAllowedLaunchProtocol(app_id2, protocol_scheme2); |
| |
| { |
| auto allowed_protocols = registrar().GetAllAllowedLaunchProtocols(); |
| EXPECT_TRUE(base::Contains(allowed_protocols, protocol_scheme1)); |
| EXPECT_TRUE(base::Contains(allowed_protocols, protocol_scheme2)); |
| |
| sync_bridge().RemoveAllowedLaunchProtocol(app_id2, protocol_scheme2); |
| } |
| { |
| auto allowed_protocols = registrar().GetAllAllowedLaunchProtocols(); |
| EXPECT_TRUE(base::Contains(allowed_protocols, protocol_scheme1)); |
| EXPECT_FALSE(base::Contains(allowed_protocols, protocol_scheme2)); |
| } |
| } |
| |
| TEST_F(WebAppRegistrarTest, DisallowedLaunchProtocols) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(GURL("https://example.com/path")); |
| const AppId app_id1 = web_app->app_id(); |
| const std::string protocol_scheme1 = "test"; |
| RegisterApp(std::move(web_app)); |
| |
| auto web_app2 = test::CreateWebApp(GURL("https://example.com/path2")); |
| const AppId app_id2 = web_app2->app_id(); |
| const std::string protocol_scheme2 = "test2"; |
| RegisterApp(std::move(web_app2)); |
| |
| // Test we can add and remove diallowed protocols. |
| EXPECT_EQ(false, |
| registrar().IsDisallowedLaunchProtocol(app_id1, protocol_scheme1)); |
| |
| sync_bridge().AddDisallowedLaunchProtocol(app_id1, protocol_scheme1); |
| EXPECT_EQ(true, |
| registrar().IsDisallowedLaunchProtocol(app_id1, protocol_scheme1)); |
| |
| sync_bridge().RemoveDisallowedLaunchProtocol(app_id1, protocol_scheme1); |
| EXPECT_EQ(false, |
| registrar().IsDisallowedLaunchProtocol(app_id1, protocol_scheme1)); |
| |
| // Test that we can get disallowed protocols from multiple web apps. |
| sync_bridge().AddDisallowedLaunchProtocol(app_id1, protocol_scheme1); |
| sync_bridge().AddDisallowedLaunchProtocol(app_id2, protocol_scheme2); |
| |
| { |
| auto disallowed_protocols = registrar().GetAllDisallowedLaunchProtocols(); |
| EXPECT_TRUE(base::Contains(disallowed_protocols, protocol_scheme1)); |
| EXPECT_TRUE(base::Contains(disallowed_protocols, protocol_scheme2)); |
| |
| sync_bridge().RemoveDisallowedLaunchProtocol(app_id2, protocol_scheme2); |
| } |
| { |
| auto disallowed_protocols = registrar().GetAllDisallowedLaunchProtocols(); |
| EXPECT_TRUE(base::Contains(disallowed_protocols, protocol_scheme1)); |
| EXPECT_FALSE(base::Contains(disallowed_protocols, protocol_scheme2)); |
| } |
| } |
| |
| TEST_F(WebAppRegistrarTest, IsRegisteredLaunchProtocol) { |
| controller().Init(); |
| |
| apps::ProtocolHandlerInfo protocol_handler_info1; |
| protocol_handler_info1.protocol = "web+test"; |
| protocol_handler_info1.url = GURL("http://example.com/test=%s"); |
| |
| apps::ProtocolHandlerInfo protocol_handler_info2; |
| protocol_handler_info2.protocol = "web+test2"; |
| protocol_handler_info2.url = GURL("http://example.com/test2=%s"); |
| |
| auto web_app = test::CreateWebApp(GURL("https://example.com/path")); |
| const AppId app_id = web_app->app_id(); |
| web_app->SetProtocolHandlers( |
| {protocol_handler_info1, protocol_handler_info2}); |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_TRUE(registrar().IsRegisteredLaunchProtocol(app_id, "web+test")); |
| EXPECT_TRUE(registrar().IsRegisteredLaunchProtocol(app_id, "web+test2")); |
| EXPECT_FALSE(registrar().IsRegisteredLaunchProtocol(app_id, "web+test3")); |
| EXPECT_FALSE(registrar().IsRegisteredLaunchProtocol(app_id, "mailto")); |
| } |
| |
| TEST_F(WebAppRegistrarTest, TestIsDefaultManagementInstalled) { |
| controller().Init(); |
| |
| auto web_app1 = |
| test::CreateWebApp(GURL("https://start.com"), WebAppManagement::kDefault); |
| auto web_app2 = test::CreateWebApp(GURL("https://starter.com"), |
| WebAppManagement::kPolicy); |
| const AppId app_id1 = web_app1->app_id(); |
| const AppId app_id2 = web_app2->app_id(); |
| RegisterApp(std::move(web_app1)); |
| RegisterApp(std::move(web_app2)); |
| |
| // Currently default installed. |
| EXPECT_TRUE(registrar().IsInstalledByDefaultManagement(app_id1)); |
| // Currently installed by source other than installed. |
| EXPECT_FALSE(registrar().IsInstalledByDefaultManagement(app_id2)); |
| |
| // Uninstalling the previously default installed app. |
| UnregisterApp(app_id1); |
| EXPECT_FALSE(registrar().IsInstalledByDefaultManagement(app_id1)); |
| } |
| |
| TEST_F(WebAppRegistrarTest_TabStrip, TabbedAppNewTabUrl) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(GURL("https://example.com/path")); |
| AppId app_id = web_app->app_id(); |
| GURL new_tab_url = GURL("https://example.com/path/newtab"); |
| |
| blink::Manifest::NewTabButtonParams new_tab_button_params; |
| new_tab_button_params.url = new_tab_url; |
| TabStrip tab_strip; |
| tab_strip.new_tab_button = new_tab_button_params; |
| |
| web_app->SetDisplayMode(DisplayMode::kTabbed); |
| web_app->SetTabStrip(tab_strip); |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(registrar().GetAppNewTabUrl(app_id), new_tab_url); |
| } |
| |
| TEST_F(WebAppRegistrarTest_TabStrip, TabbedAppAutoNewTabUrl) { |
| controller().Init(); |
| |
| auto web_app = test::CreateWebApp(GURL("https://example.com/path")); |
| AppId app_id = web_app->app_id(); |
| |
| TabStrip tab_strip; |
| tab_strip.new_tab_button = TabStrip::Visibility::kAuto; |
| |
| web_app->SetDisplayMode(DisplayMode::kTabbed); |
| web_app->SetTabStrip(tab_strip); |
| RegisterApp(std::move(web_app)); |
| |
| EXPECT_EQ(registrar().GetAppNewTabUrl(app_id), |
| registrar().GetAppStartUrl(app_id)); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS_ASH) |
| |
| class WebAppRegistrarAshTest : public WebAppTest, public WithCrosapiParam { |
| public: |
| WebAppRegistrarAshTest() { |
| // Avoid crash during TestingProfile construction when Lacros support is |
| // enabled. |
| scoped_feature_list_.InitAndDisableFeature( |
| chromeos::features::kArcAccountRestrictions); |
| } |
| ~WebAppRegistrarAshTest() override = default; |
| |
| private: |
| base::test::ScopedFeatureList scoped_feature_list_; |
| }; |
| |
| TEST_P(WebAppRegistrarAshTest, SourceSupported) { |
| const GURL example_url("https://example.com/my-app/start"); |
| const GURL swa_url("chrome://swa/start"); |
| const GURL uninstalling_url("https://example.com/uninstalling/start"); |
| |
| AppId example_id; |
| AppId swa_id; |
| AppId uninstalling_id; |
| WebAppRegistrarMutable registrar(profile()); |
| { |
| Registry registry; |
| |
| auto example_app = test::CreateWebApp(example_url); |
| example_id = example_app->app_id(); |
| registry.emplace(example_id, std::move(example_app)); |
| |
| auto swa_app = test::CreateWebApp(swa_url, WebAppManagement::Type::kSystem); |
| swa_id = swa_app->app_id(); |
| registry.emplace(swa_id, std::move(swa_app)); |
| |
| auto uninstalling_app = |
| test::CreateWebApp(uninstalling_url, WebAppManagement::Type::kSystem); |
| uninstalling_app->SetIsUninstalling(true); |
| uninstalling_id = uninstalling_app->app_id(); |
| registry.emplace(uninstalling_id, std::move(uninstalling_app)); |
| |
| registrar.InitRegistry(std::move(registry)); |
| } |
| |
| if (GetParam() == CrosapiParam::kEnabled) { |
| // Non-system web apps are managed by Lacros, excluded in Ash |
| // WebAppRegistrar. |
| EXPECT_EQ(registrar.CountUserInstalledApps(), 0); |
| EXPECT_EQ(CountApps(registrar.GetApps()), 1); |
| |
| EXPECT_FALSE(registrar.FindAppWithUrlInScope(example_url).has_value()); |
| EXPECT_TRUE(registrar.GetAppScope(example_id).is_empty()); |
| EXPECT_FALSE(registrar.GetAppUserDisplayMode(example_id).has_value()); |
| } else { |
| EXPECT_EQ(registrar.CountUserInstalledApps(), 1); |
| EXPECT_EQ(CountApps(registrar.GetApps()), 2); |
| |
| EXPECT_EQ(registrar.FindAppWithUrlInScope(example_url), example_id); |
| EXPECT_EQ(registrar.GetAppScope(example_id), |
| GURL("https://example.com/my-app/")); |
| EXPECT_TRUE(registrar.GetAppUserDisplayMode(example_id).has_value()); |
| } |
| |
| EXPECT_EQ(registrar.FindAppWithUrlInScope(swa_url), swa_id); |
| EXPECT_EQ(registrar.GetAppScope(swa_id), GURL("chrome://swa/")); |
| EXPECT_TRUE(registrar.GetAppUserDisplayMode(swa_id).has_value()); |
| |
| EXPECT_FALSE(registrar.FindAppWithUrlInScope(uninstalling_url).has_value()); |
| EXPECT_EQ(registrar.GetAppScope(uninstalling_id), |
| GURL("https://example.com/uninstalling/")); |
| EXPECT_TRUE(registrar.GetAppUserDisplayMode(uninstalling_id).has_value()); |
| EXPECT_FALSE(base::Contains(registrar.GetAppIds(), uninstalling_id)); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P(All, |
| WebAppRegistrarAshTest, |
| ::testing::Values(CrosapiParam::kEnabled, |
| CrosapiParam::kDisabled), |
| WithCrosapiParam::ParamToString); |
| #endif |
| |
| #if BUILDFLAG(IS_CHROMEOS_LACROS) |
| |
| using WebAppRegistrarLacrosTest = WebAppTest; |
| |
| TEST_F(WebAppRegistrarLacrosTest, SwaSourceNotSupported) { |
| const GURL example_url("https://example.com/my-app/start"); |
| const GURL swa_url("chrome://swa/start"); |
| const GURL uninstalling_url("https://example.com/uninstalling/start"); |
| |
| AppId example_id; |
| AppId swa_id; |
| AppId uninstalling_id; |
| WebAppRegistrarMutable registrar(profile()); |
| { |
| Registry registry; |
| |
| auto example_app = test::CreateWebApp(example_url); |
| example_id = example_app->app_id(); |
| registry.emplace(example_id, std::move(example_app)); |
| |
| auto swa_app = test::CreateWebApp(swa_url, WebAppManagement::Type::kSystem); |
| swa_id = swa_app->app_id(); |
| registry.emplace(swa_id, std::move(swa_app)); |
| |
| auto uninstalling_app = test::CreateWebApp(uninstalling_url); |
| uninstalling_app->SetIsUninstalling(true); |
| uninstalling_id = uninstalling_app->app_id(); |
| registry.emplace(uninstalling_id, std::move(uninstalling_app)); |
| |
| registrar.InitRegistry(std::move(registry)); |
| } |
| |
| EXPECT_EQ(registrar.FindAppWithUrlInScope(example_url), example_id); |
| EXPECT_EQ(registrar.GetAppScope(example_id), |
| GURL("https://example.com/my-app/")); |
| EXPECT_TRUE(registrar.GetAppUserDisplayMode(example_id).has_value()); |
| EXPECT_EQ(registrar.CountUserInstalledApps(), 1); |
| |
| // System web apps are managed by Ash, excluded in Lacros |
| // WebAppRegistrar. |
| EXPECT_EQ(CountApps(registrar.GetApps()), 1); |
| |
| EXPECT_FALSE(registrar.FindAppWithUrlInScope(swa_url).has_value()); |
| EXPECT_TRUE(registrar.GetAppScope(swa_id).is_empty()); |
| EXPECT_FALSE(registrar.GetAppUserDisplayMode(swa_id).has_value()); |
| |
| EXPECT_FALSE(registrar.FindAppWithUrlInScope(uninstalling_url).has_value()); |
| EXPECT_EQ(registrar.GetAppScope(uninstalling_id), |
| GURL("https://example.com/uninstalling/")); |
| EXPECT_TRUE(registrar.GetAppUserDisplayMode(uninstalling_id).has_value()); |
| EXPECT_FALSE(base::Contains(registrar.GetAppIds(), uninstalling_id)); |
| } |
| |
| #endif // BUILDFLAG(IS_CHROMEOS_LACROS) |
| |
| } // namespace web_app |