| // Copyright 2024 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <climits> |
| #include <initializer_list> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <tuple> |
| #include <vector> |
| |
| #include "base/base_paths.h" |
| #include "base/check.h" |
| #include "base/functional/function_ref.h" |
| #include "base/path_service.h" |
| #include "base/strings/string_util.h" |
| #include "base/values.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/badging/badge_manager.h" |
| #include "chrome/browser/badging/badge_manager_factory.h" |
| #include "chrome/browser/devtools/protocol/devtools_protocol_test_support.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_finder.h" |
| #include "chrome/browser/ui/browser_window/public/browser_window_features.h" |
| #include "chrome/browser/ui/browser_window/public/browser_window_interface.h" |
| #include "chrome/browser/ui/web_applications/app_browser_controller.h" |
| #include "chrome/browser/web_applications/proto/web_app.pb.h" |
| #include "chrome/browser/web_applications/proto/web_app_os_integration_state.pb.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/web_app.h" |
| #include "chrome/browser/web_applications/web_app_helpers.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_tab_helper.h" |
| #include "chrome/test/base/ui_test_utils.h" |
| #include "components/services/app_service/public/cpp/file_handler.h" |
| #include "components/ukm/test_ukm_recorder.h" |
| #include "components/webapps/common/web_app_id.h" |
| #include "content/public/browser/devtools_agent_host.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "url/gurl.h" |
| |
| namespace { |
| |
| using web_app::WebAppInstallInfo; |
| using web_app::WebAppProvider; |
| using webapps::ManifestId; |
| |
| class PWAProtocolTestWithoutApp : public DevToolsProtocolTestBase { |
| public: |
| void SetUpOnMainThread() override { |
| DevToolsProtocolTestBase::SetUpOnMainThread(); |
| AttachToBrowserTarget(); |
| } |
| |
| protected: |
| void LoadWebContents(GURL url) { |
| ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); |
| ASSERT_TRUE(content::WaitForLoadStop(web_contents())); |
| } |
| |
| void ReattachToWebContents(GURL url) { |
| LoadWebContents(std::move(url)); |
| DetachProtocolClient(); |
| Attach(); |
| } |
| |
| void AssertErrorMessageContains( |
| std::initializer_list<std::string> pieces) const { |
| ASSERT_TRUE(error()); |
| const std::string& message = *error()->FindString("message"); |
| for (const auto& piece : pieces) { |
| EXPECT_THAT(message, testing::HasSubstr(piece)); |
| } |
| } |
| }; |
| |
| class PWAProtocolTest : public PWAProtocolTestWithoutApp { |
| public: |
| void SetUp() override { |
| embedded_test_server()->AddDefaultHandlers(GetChromeTestDataDir()); |
| test_server_closer_ = embedded_test_server()->StartAndReturnHandle(); |
| // This is strange, but the tests are running in the SetUp(), so the |
| // embedded_test_server() needs to be started first. |
| PWAProtocolTestWithoutApp::SetUp(); |
| } |
| |
| void SetUpOnMainThread() override { |
| PWAProtocolTestWithoutApp::SetUpOnMainThread(); |
| override_registration_ = |
| web_app::OsIntegrationTestOverrideImpl::OverrideForTesting(); |
| test_data_path_ = |
| base::PathService::CheckedGet(base::DIR_SRC_TEST_DATA_ROOT); |
| } |
| |
| void TearDownOnMainThread() override { |
| web_app::test::UninstallAllWebApps(browser()->profile()); |
| override_registration_.reset(); |
| PWAProtocolTestWithoutApp::TearDownOnMainThread(); |
| } |
| |
| protected: |
| webapps::AppId InstallWebApp( |
| base::FunctionRef<void(WebAppInstallInfo&)> init) const { |
| std::unique_ptr<WebAppInstallInfo> web_app_info = |
| WebAppInstallInfo::CreateWithStartUrlForTesting(InstallableWebAppUrl()); |
| // The title needs to match the web app to avoid triggering an update. |
| web_app_info->title = u"Basic web app"; |
| init(*web_app_info); |
| return web_app::test::InstallWebApp(browser()->profile(), |
| std::move(web_app_info)); |
| } |
| |
| webapps::AppId InstallWebApp() const { |
| return InstallWebApp([](WebAppInstallInfo& web_app_info) {}); |
| } |
| |
| GURL InstallableWebAppUrl() const { |
| return embedded_test_server()->GetURL("/web_apps/basic.html"); |
| } |
| |
| // For basic.html, the manifest-id equals to its start-url. |
| ManifestId InstallableWebAppManifestId() const { |
| return InstallableWebAppUrl(); |
| } |
| |
| GURL NotInstallableWebAppUrl() const { |
| return embedded_test_server()->GetURL( |
| "/web_apps/title_appname_prefix.html"); |
| } |
| |
| // The default manifest uses the original url if it's not a web-app without |
| // a manifest link. |
| ManifestId NotInstallableWebAppManifestId() const { |
| return NotInstallableWebAppUrl(); |
| } |
| |
| GURL HasManifestIdWebAppUrl() const { |
| return embedded_test_server()->GetURL("/web_apps/has_manifest_id.html"); |
| } |
| |
| ManifestId HasManifestIdWebAppManifestId() const { |
| return embedded_test_server()->GetURL( |
| "/web_apps/has_manifest_id_unique_id"); |
| } |
| |
| GURL GetInstallableSiteWithManifest(std::string_view json_path) const { |
| return embedded_test_server()->GetURL( |
| std::string("/web_apps/get_manifest.html?").append(json_path)); |
| } |
| |
| bool AppExists(const ManifestId& manifest_id) { |
| auto* provider = WebAppProvider::GetForTest(browser()->profile()); |
| CHECK(provider); |
| return provider->registrar_unsafe().IsInRegistrar( |
| web_app::GenerateAppIdFromManifestId(manifest_id)); |
| } |
| |
| void InstallFromManifest() { |
| EXPECT_TRUE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{}.Set("manifestId", |
| InstallableWebAppManifestId().spec()))); |
| EXPECT_TRUE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| void InstallFromUrl(const ManifestId& manifest_id, const GURL& url) { |
| EXPECT_TRUE(SendCommandSync("PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", manifest_id.spec()) |
| .Set("installUrlOrBundleUrl", url.spec()))); |
| EXPECT_TRUE(AppExists(manifest_id)); |
| } |
| |
| void InstallFromMatchingUrlAndManifestId( |
| const GURL& install_url_and_manifest_id) { |
| InstallFromUrl(install_url_and_manifest_id, install_url_and_manifest_id); |
| } |
| |
| void InstallFromUrl() { |
| InstallFromUrl(InstallableWebAppManifestId(), InstallableWebAppUrl()); |
| } |
| |
| static GURL UpperCaseScheme(const GURL& origin) { |
| std::string spec{origin.spec()}; |
| for (size_t i = 0; i < origin.GetScheme().length(); i++) { |
| spec[i] = base::ToUpperASCII(spec[i]); |
| } |
| return GURL{spec}; |
| } |
| |
| void AssertActiveWebContentsBelongToApp(const GURL& url, |
| const webapps::AppId& app_id) { |
| content::WebContents* contents = |
| chrome::FindLastActive()->tab_strip_model()->GetActiveWebContents(); |
| EXPECT_TRUE(contents); |
| EXPECT_TRUE(content::WaitForLoadStop(contents)); |
| EXPECT_EQ(contents->GetLastCommittedURL(), url); |
| const std::string* contents_app_id = |
| web_app::WebAppTabHelper::GetAppId(contents); |
| ASSERT_TRUE(contents_app_id); |
| EXPECT_EQ(*contents_app_id, app_id); |
| } |
| |
| void AssertActiveWebContentsBelongToApp(const ManifestId& manifest_id) { |
| AssertActiveWebContentsBelongToApp( |
| manifest_id, web_app::GenerateAppIdFromManifestId(manifest_id)); |
| } |
| |
| base::Value::List AbsolutePaths(std::initializer_list<std::string> paths) { |
| base::Value::List result{}; |
| for (const auto& path : paths) { |
| result.Append( |
| test_data_path_.Append(FILE_PATH_LITERAL("chrome/test/data")) |
| .AppendASCII(path) |
| .AsUTF8Unsafe()); |
| } |
| return result; |
| } |
| |
| bool AttachToLaunchFilesInAppResult() { |
| const base::Value::List* ids = result()->FindList("targetIds"); |
| if (ids == nullptr || ids->size() != 1 || !ids->front().is_string()) { |
| return false; |
| } |
| return SendCommandSync( |
| "Target.attachToTarget", |
| base::Value::Dict{}.Set("targetId", ids->front().GetString())); |
| } |
| |
| using AppUserSettings = |
| std::tuple<web_app::proto::LinkCapturingUserPreference, |
| web_app::mojom::UserDisplayMode>; |
| |
| AppUserSettings GetAppUserSettings(const ManifestId& manifest_id) { |
| auto* provider = WebAppProvider::GetForTest(browser()->profile()); |
| CHECK(provider); |
| const auto* web_app = provider->registrar_unsafe().GetAppById( |
| web_app::GenerateAppIdFromManifestId(manifest_id)); |
| CHECK(web_app); |
| return {web_app->user_link_capturing_preference(), |
| web_app->user_display_mode()}; |
| } |
| |
| private: |
| net::test_server::EmbeddedTestServerHandle test_server_closer_; |
| std::unique_ptr<web_app::OsIntegrationTestOverrideImpl::BlockingRegistration> |
| override_registration_; |
| base::FilePath test_data_path_; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTestWithoutApp, GetOsAppState_CannotFindApp) { |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.getOsAppState", |
| base::Value::Dict{}.Set("manifestId", "ThisIsNotAValidManifestId"))); |
| // Expect the input manifestId to be carried over by the error message. |
| AssertErrorMessageContains({"ThisIsNotAValidManifestId"}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetOsAppState) { |
| InstallWebApp(); |
| const base::Value::Dict* result = |
| SendCommandSync("PWA.getOsAppState", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec())); |
| ASSERT_TRUE(result); |
| ASSERT_EQ(*result->FindInt("badgeCount"), 0); |
| ASSERT_TRUE(result->FindList("fileHandlers")->empty()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetOsAppState_WithBadge) { |
| webapps::AppId app_id = InstallWebApp(); |
| ukm::TestUkmRecorder test_recorder; |
| badging::BadgeManagerFactory::GetForProfile(browser()->profile()) |
| ->SetBadgeForTesting(app_id, 11, &test_recorder); |
| const base::Value::Dict* result = |
| SendCommandSync("PWA.getOsAppState", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec())); |
| ASSERT_TRUE(result); |
| ASSERT_EQ(*result->FindInt("badgeCount"), 11); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetOsAppState_WithZeroBadge) { |
| webapps::AppId app_id = InstallWebApp(); |
| ukm::TestUkmRecorder test_recorder; |
| badging::BadgeManagerFactory::GetForProfile(browser()->profile()) |
| ->SetBadgeForTesting(app_id, 0, &test_recorder); |
| const base::Value::Dict* result = |
| SendCommandSync("PWA.getOsAppState", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec())); |
| ASSERT_TRUE(result); |
| ASSERT_EQ(*result->FindInt("badgeCount"), 0); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetOsAppState_WithBadgeOverInt) { |
| webapps::AppId app_id = InstallWebApp(); |
| ukm::TestUkmRecorder test_recorder; |
| badging::BadgeManagerFactory::GetForProfile(browser()->profile()) |
| ->SetBadgeForTesting(app_id, static_cast<uint64_t>(INT_MAX) + 1, |
| &test_recorder); |
| const base::Value::Dict* result = |
| SendCommandSync("PWA.getOsAppState", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec())); |
| ASSERT_TRUE(result); |
| ASSERT_EQ(*result->FindInt("badgeCount"), INT_MAX); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetOsAppState_WithFileHandler) { |
| webapps::AppId app_id = |
| InstallWebApp([this](WebAppInstallInfo& web_app_info) { |
| apps::FileHandler file_handler; |
| file_handler.action = InstallableWebAppUrl().Resolve("/file_handler"); |
| apps::FileHandler::AcceptEntry entry; |
| entry.mime_type = "image/jpeg"; |
| entry.file_extensions.insert(".jpg"); |
| entry.file_extensions.insert(".jpeg"); |
| file_handler.accept.push_back(entry); |
| web_app_info.file_handlers.push_back(file_handler); |
| }); |
| const base::Value::Dict* result = |
| SendCommandSync("PWA.getOsAppState", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec())); |
| ASSERT_TRUE(result); |
| ASSERT_EQ(result->FindList("fileHandlers")->size(), 1UL); |
| const auto& handler = result->FindList("fileHandlers")->front().DebugString(); |
| // Check if several fields exist instead of repeating the conversions. |
| ASSERT_NE(handler.find("/file_handler"), std::string::npos); |
| ASSERT_NE(handler.find("image/jpeg"), std::string::npos); |
| ASSERT_NE(handler.find(".jpg"), std::string::npos); |
| ASSERT_NE(handler.find(".jpeg"), std::string::npos); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetProcessedManifest_CannotFindApp) { |
| ASSERT_FALSE(SendCommandSync( |
| "Page.getAppManifest", |
| base::Value::Dict{}.Set("manifestId", "ThisIsNotAValidManifestId"))); |
| AssertErrorMessageContains({"Page.getAppManifest"}); |
| // The error message should also carry the input manifest id, but now the API |
| // won't work on browser target at all. |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| GetProcessedManifest_CannotFindApp_WithoutManfiestId) { |
| ASSERT_FALSE(SendCommandSync("Page.getAppManifest", base::Value::Dict{})); |
| ASSERT_TRUE(error()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| GetProcessedManifest_WithoutManifestId) { |
| ReattachToWebContents(InstallableWebAppUrl()); |
| const base::Value::Dict* result = |
| SendCommandSync("Page.getAppManifest", base::Value::Dict{}); |
| ASSERT_TRUE(result); |
| result = result->FindDict("manifest"); |
| ASSERT_TRUE(result); |
| ASSERT_EQ(*result->FindString("id"), InstallableWebAppUrl().spec()); |
| const auto& manifest = result->DebugString(); |
| // Check if several fields exist instead of repeating the conversions. |
| ASSERT_NE(manifest.find("/web_apps/basic-48.png"), std::string::npos); |
| ASSERT_NE(manifest.find("/web_apps/basic-192.png"), std::string::npos); |
| ASSERT_NE(manifest.find("preferRelatedApplications"), std::string::npos); |
| ASSERT_NE(manifest.find("kStandalone"), std::string::npos); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetProcessedManifest_WithManifestId) { |
| ReattachToWebContents(InstallableWebAppUrl()); |
| const base::Value::Dict* result = |
| SendCommandSync("Page.getAppManifest", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec())); |
| ASSERT_TRUE(result); |
| result = result->FindDict("manifest"); |
| ASSERT_TRUE(result); |
| ASSERT_EQ(*result->FindString("id"), InstallableWebAppUrl().spec()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetProcessedManifest_IconWithNoSizes) { |
| ReattachToWebContents( |
| GetInstallableSiteWithManifest("icon_with_no_sizes.json")); |
| const base::Value::Dict* result = |
| SendCommandSync("Page.getAppManifest", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec())); |
| ASSERT_TRUE(result); |
| auto* manifest = result->FindDict("manifest"); |
| ASSERT_TRUE(manifest); |
| auto* icons = manifest->FindList("icons"); |
| ASSERT_TRUE(icons); |
| ASSERT_EQ(icons->size(), 1u); |
| auto* icon = (*icons)[0].GetIfDict(); |
| ASSERT_TRUE(icon); |
| auto* sizes = icon->FindString("sizes"); |
| ASSERT_TRUE(sizes); |
| EXPECT_EQ(*sizes, ""); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetProcessedManifest_MismatchId) { |
| ReattachToWebContents(InstallableWebAppUrl()); |
| ASSERT_FALSE(SendCommandSync( |
| "Page.getAppManifest", |
| base::Value::Dict{}.Set("manifestId", "ThisIsNotAValidManifestId"))); |
| // Expect the input manifest id and original manifest id to be carried over by |
| // the error message. |
| AssertErrorMessageContains( |
| {InstallableWebAppUrl().spec(), "ThisIsNotAValidManifestId"}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| GetProcessedManifest_NotOnPage_WithManifestId) { |
| ASSERT_FALSE( |
| SendCommandSync("Page.getAppManifest", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| AssertErrorMessageContains({"Page.getAppManifest"}); |
| // The error message should also carry the input manifest id, but now the API |
| // won't work on browser target at all. |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, GetProcessedManifest_NotInstallable) { |
| ReattachToWebContents(NotInstallableWebAppUrl()); |
| const base::Value::Dict* result = |
| SendCommandSync("Page.getAppManifest", base::Value::Dict{}); |
| ASSERT_TRUE(result); |
| result = result->FindDict("manifest"); |
| ASSERT_TRUE(result); |
| ASSERT_EQ(*result->FindString("id"), NotInstallableWebAppUrl().spec()); |
| ASSERT_EQ(*result->FindString("startUrl"), NotInstallableWebAppUrl().spec()); |
| ASSERT_EQ(*result->FindString("scope"), |
| embedded_test_server()->GetURL("/web_apps/").spec()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Uninstall) { |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| InstallWebApp(); |
| ASSERT_TRUE(AppExists(InstallableWebAppManifestId())); |
| |
| SendCommandSync("PWA.uninstall", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec())); |
| ASSERT_TRUE(result()); |
| ASSERT_FALSE(error()); |
| |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Uninstall_CannotFindApp) { |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| // Treat uninstalling nonexisting apps as a success. |
| ASSERT_TRUE( |
| SendCommandSync("PWA.uninstall", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Uninstall_MissingManifestId) { |
| ASSERT_FALSE(SendCommandSync("PWA.uninstall", base::Value::Dict{})); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromManifest) { |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| ReattachToWebContents(InstallableWebAppUrl()); |
| InstallFromManifest(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromManifest_Twice) { |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| ReattachToWebContents(InstallableWebAppUrl()); |
| InstallFromManifest(); |
| // Install a same application twice won't trigger an error. |
| InstallFromManifest(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromManifest_NoWebContents) { |
| // Only load the WebContents without attaching the devtools session to it. |
| // By default, the devtools is being attached to the browser in the |
| // PWAProtocolTestWithoutApp::SetUpOnMainThread. |
| // So the PWAHandler cannot install the webapp with only the manifest-id. |
| LoadWebContents(InstallableWebAppUrl()); |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| AssertErrorMessageContains({InstallableWebAppUrl().spec()}); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromManifest_InvalidStartUrl) { |
| const GURL url{GetInstallableSiteWithManifest("invalid_start_url.json")}; |
| ReattachToWebContents(url); |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", base::Value::Dict{}.Set("manifestId", url.spec()))); |
| AssertErrorMessageContains({url.spec()}); |
| ASSERT_FALSE(AppExists(url)); |
| ASSERT_FALSE(AppExists(ManifestId{"http://different.origin/is-invalid"})); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| Install_FromManifest_InconsistentAppId) { |
| const GURL url{GetInstallableSiteWithManifest("basic.json")}; |
| ReattachToWebContents(url); |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", base::Value::Dict{}.Set("manifestId", url.spec()))); |
| AssertErrorMessageContains( |
| {url.spec(), GetInstallableSiteWithManifest("basic.json").spec()}); |
| ASSERT_FALSE(AppExists(url)); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromManifest_HasManifestId) { |
| ReattachToWebContents(HasManifestIdWebAppUrl()); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{}.Set("manifestId", |
| HasManifestIdWebAppManifestId().spec()))); |
| ASSERT_TRUE(AppExists(HasManifestIdWebAppManifestId())); |
| ASSERT_FALSE(AppExists(HasManifestIdWebAppUrl())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| Install_FromManifest_HasManifestId_UrlAsManifestId) { |
| ReattachToWebContents(HasManifestIdWebAppUrl()); |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{}.Set("manifestId", HasManifestIdWebAppUrl().spec()))); |
| AssertErrorMessageContains({HasManifestIdWebAppUrl().spec()}); |
| ASSERT_FALSE(AppExists(HasManifestIdWebAppManifestId())); |
| ASSERT_FALSE(AppExists(HasManifestIdWebAppUrl())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl) { |
| InstallFromUrl(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_Twice) { |
| InstallFromUrl(); |
| // Install a same application twice won't trigger an error. |
| InstallFromUrl(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromManifest_FromUrl) { |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| ReattachToWebContents(InstallableWebAppUrl()); |
| InstallFromManifest(); |
| // Install a same application twice won't trigger an error. |
| InstallFromUrl(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_FromManifest) { |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| InstallFromUrl(); |
| // Install a same application twice won't trigger an error. |
| ReattachToWebContents(InstallableWebAppUrl()); |
| InstallFromManifest(); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_UpperCase) { |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", |
| UpperCaseScheme(InstallableWebAppManifestId()).spec()) |
| .Set("installUrlOrBundleUrl", |
| UpperCaseScheme(InstallableWebAppUrl()).spec()))); |
| ASSERT_TRUE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_Unreachable) { |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("installUrlOrBundleUrl", "http://hello/this/is/not/existing"))); |
| AssertErrorMessageContains( |
| {InstallableWebAppUrl().spec(), "http://hello/this/is/not/existing"}); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_UnmatchManifestId) { |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", NotInstallableWebAppUrl().spec()) |
| .Set("installUrlOrBundleUrl", InstallableWebAppUrl().spec()))); |
| AssertErrorMessageContains( |
| {InstallableWebAppUrl().spec(), NotInstallableWebAppUrl().spec()}); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| ASSERT_FALSE(AppExists(NotInstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_InvalidManifestId) { |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", "bad_id 😝") |
| .Set("installUrlOrBundleUrl", InstallableWebAppUrl().spec()))); |
| AssertErrorMessageContains({"bad_id 😝", "Invalid manifestId"}); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| ASSERT_FALSE(AppExists(NotInstallableWebAppManifestId())); |
| } |
| |
| // TODO(crbug.com/331214986): May want a test to trigger the installation |
| // failure when installing from the url. |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| Install_FromUrl_ValidManifestId_DifferentInstallUrl) { |
| const GURL url{GetInstallableSiteWithManifest("basic.json")}; |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("installUrlOrBundleUrl", url.spec()))); |
| ASSERT_FALSE(AppExists(url)); |
| ASSERT_TRUE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_InconsistentAppId) { |
| const GURL url{GetInstallableSiteWithManifest("basic.json")}; |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("installUrlOrBundleUrl", InstallableWebAppUrl().spec()))); |
| AssertErrorMessageContains({url.spec()}); |
| ASSERT_FALSE(AppExists(url)); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_NoScheme) { |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("installUrlOrBundleUrl", "localhost/"))); |
| AssertErrorMessageContains({"localhost/"}); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_UnsupportedScheme) { |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("installUrlOrBundleUrl", "ftp://localhost/"))); |
| AssertErrorMessageContains({"ftp", "ftp://localhost/"}); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_FromUrl_HasManifestId) { |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.install", |
| base::Value::Dict{} |
| .Set("manifestId", HasManifestIdWebAppManifestId().spec()) |
| .Set("installUrlOrBundleUrl", HasManifestIdWebAppUrl().spec()))); |
| ASSERT_TRUE(AppExists(HasManifestIdWebAppManifestId())); |
| ASSERT_FALSE(AppExists(HasManifestIdWebAppUrl())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Install_Uninstall) { |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| ReattachToWebContents(InstallableWebAppUrl()); |
| base::Value::Dict params; |
| params.Set("manifestId", InstallableWebAppManifestId().spec()); |
| |
| ASSERT_TRUE(SendCommandSync("PWA.install", params.Clone())); |
| ASSERT_TRUE(AppExists(InstallableWebAppManifestId())); |
| |
| ASSERT_TRUE(SendCommandSync("PWA.uninstall", params.Clone())); |
| ASSERT_FALSE(AppExists(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch) { |
| InstallFromUrl(); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launch", base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| ASSERT_FALSE(error()); |
| AssertActiveWebContentsBelongToApp(InstallableWebAppUrl()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch_ReturnsAttachableTargetId) { |
| InstallFromUrl(); |
| const base::Value::Dict* result = SendCommandSync( |
| "PWA.launch", base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec())); |
| ASSERT_TRUE(result); |
| ASSERT_TRUE(SendCommandSync( |
| "Target.attachToTarget", |
| base::Value::Dict{}.Set("targetId", *result->FindString("targetId")))); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch_AutoAttach) { |
| InstallFromUrl(); |
| ASSERT_TRUE( |
| SendCommandSync("Target.setAutoAttach", |
| base::Value::Dict{} |
| .Set("autoAttach", true) |
| .Set("waitForDebuggerOnStart", true) |
| .Set("filter", base::Value::List{} |
| .Append(base::Value::Dict{} |
| .Set("type", "tab") |
| .Set("exclude", false)) |
| .Append(base::Value::Dict{} |
| .Set("type", "page") |
| .Set("exclude", true))) |
| .Set("flatten", true))); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launch", base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| ASSERT_TRUE(HasExistingNotificationMatching( |
| [expected_target_id = *result()->FindString("targetId")]( |
| const base::Value::Dict& notification) { |
| if (*notification.FindString("method") != "Target.attachedToTarget") { |
| return false; |
| } |
| const std::string* target_id = |
| notification.FindStringByDottedPath("params.targetInfo.targetId"); |
| const std::string* type = |
| notification.FindStringByDottedPath("params.targetInfo.type"); |
| return target_id && *target_id == expected_target_id && type && |
| *type == content::DevToolsAgentHost::kTypeTab; |
| })); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch_NoApp) { |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.launch", base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| AssertErrorMessageContains({InstallableWebAppManifestId().spec()}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch_InFullScreenMode) { |
| GURL url{embedded_test_server()->GetURL("/web_apps/display_fullscreen.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launch", base::Value::Dict{}.Set("manifestId", url.spec()))); |
| ASSERT_FALSE(error()); |
| AssertActiveWebContentsBelongToApp(url); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch_FromUrl) { |
| InstallFromUrl(); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launch", base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("url", InstallableWebAppUrl().spec()))); |
| ASSERT_FALSE(error()); |
| AssertActiveWebContentsBelongToApp(InstallableWebAppUrl()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch_FromUrl_InScope) { |
| InstallFromUrl(); |
| GURL url{ |
| embedded_test_server()->GetURL("/web_apps/different_start_url.html")}; |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launch", base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("url", url.spec()))); |
| ASSERT_FALSE(error()); |
| AssertActiveWebContentsBelongToApp( |
| url, web_app::GenerateAppIdFromManifestId(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch_FromUrl_NoApp) { |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.launch", base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("url", InstallableWebAppUrl().spec()))); |
| AssertErrorMessageContains( |
| {InstallableWebAppManifestId().spec(), InstallableWebAppUrl().spec()}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch_FromUrl_InvalidUrl) { |
| InstallFromUrl(); |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.launch", base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("url", "invalid-url@@@invalid/url"))); |
| AssertErrorMessageContains({"invalid-url@@@invalid/url"}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, Launch_FromUrl_OutOfScopeUrl) { |
| InstallFromUrl(); |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.launch", base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("url", "https://www.google.com/"))); |
| AssertErrorMessageContains({"https://www.google.com/"}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp) { |
| GURL url{embedded_test_server()->GetURL("/web_apps/file_handler_index.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_TRUE( |
| SendCommandSync("PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", AbsolutePaths({"cors-ok.txt"})))); |
| ASSERT_TRUE(AttachToLaunchFilesInAppResult()); |
| AssertActiveWebContentsBelongToApp( |
| embedded_test_server()->GetURL("/web_apps/file_handler_action.html"), |
| web_app::GenerateAppIdFromManifestId(url)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_MultipleFiles) { |
| GURL url{embedded_test_server()->GetURL("/web_apps/file_handler_index.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", |
| AbsolutePaths({"cors-ok.txt", "download-autoopen.txt"})))); |
| ASSERT_TRUE(AttachToLaunchFilesInAppResult()); |
| AssertActiveWebContentsBelongToApp( |
| embedded_test_server()->GetURL("/web_apps/file_handler_action.html"), |
| web_app::GenerateAppIdFromManifestId(url)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_RepeatedFiles) { |
| GURL url{embedded_test_server()->GetURL("/web_apps/file_handler_index.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", AbsolutePaths({"cors-ok.txt", "cors-ok.txt"})))); |
| ASSERT_TRUE(AttachToLaunchFilesInAppResult()); |
| AssertActiveWebContentsBelongToApp( |
| embedded_test_server()->GetURL("/web_apps/file_handler_action.html"), |
| web_app::GenerateAppIdFromManifestId(url)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_MultipleTypes) { |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/file_handler/basic.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", |
| AbsolutePaths({"cors-ok.txt", "web_apps/basic-192.png"})))); |
| ASSERT_TRUE(result()->FindList("targetIds")->size() == 2); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| LaunchFilesInApp_OneTypeMultipleFilesPerRequest) { |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/file_handler/basic.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", |
| AbsolutePaths({"cors-ok.txt", "download-autoopen.txt"})))); |
| ASSERT_TRUE(AttachToLaunchFilesInAppResult()); |
| // Multiple-Clients launch type should open one page per file. |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", AbsolutePaths({"web_apps/basic-192.png", |
| "web_apps/basic-48.png"})))); |
| ASSERT_TRUE(result()->FindList("targetIds")->size() == 2); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| LaunchFilesInApp_MultipleTypesMultipleFiles) { |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/file_handler/basic.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", |
| AbsolutePaths({"web_apps/basic-192.png", "web_apps/basic-48.png", |
| "cors-ok.txt", "download-autoopen.txt"})))); |
| ASSERT_TRUE(result()->FindList("targetIds")->size() == 3); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_PartiallyUnsupported) { |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/file_handler/basic.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", |
| AbsolutePaths({"web_apps/basic-192.png", "web_apps/basic-48.png", |
| "web_apps/basic.html", "cors-ok.txt", |
| "download-autoopen.txt"})))); |
| ASSERT_TRUE(result()->FindList("targetIds")->size() == 3); |
| } |
| |
| // TODO(crbug.com/331214986): May want a test to trigger the LaunchFilesInApp |
| // failure in LaunchApp callback. |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_PartiallyFailed) { |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/file_handler/basic.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| // The action for "jpg" is out of scope, and should be ignored. |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", |
| AbsolutePaths({"web_apps/basic-192.png", "web_apps/basic-48.png", |
| "web_apps/basic.html", "cors-ok.txt", |
| "android/watch.jpg", "download-autoopen.txt"})))); |
| ASSERT_TRUE(result()->FindList("targetIds")->size() == 3); |
| } |
| |
| // The existence of the files should be checked somewhere, but now the launch |
| // app command still succeed. So this test does not check the return value of |
| // the command, but only ensure it won't crash the browser. |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_NonexistentFiles) { |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/file_handler/basic.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| SendCommandSync("PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", "/hey/this/file/should/not/exist.txt")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_NoFileHandlers) { |
| InstallFromUrl(); |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("files", AbsolutePaths({"cors-ok.txt"})))); |
| AssertErrorMessageContains({InstallableWebAppManifestId().spec()}); |
| } |
| |
| // This scenario does not reach the handler itself, but it's worth ensuring that |
| // running PWA.launchFilesInApp without "files" parameter would always fail. |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_NoFilesField) { |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/file_handler/basic.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_FALSE( |
| SendCommandSync("PWA.launchFilesInApp", |
| base::Value::Dict{}.Set("manifestId", url.spec()))); |
| ASSERT_TRUE(error()); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_NoFile) { |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/file_handler/basic.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_FALSE(SendCommandSync("PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", base::Value::List{}))); |
| AssertErrorMessageContains({url.spec()}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, LaunchFilesInApp_UnsupportedFile) { |
| GURL url{embedded_test_server()->GetURL("/web_apps/file_handler_index.html")}; |
| InstallFromMatchingUrlAndManifestId(url); |
| ASSERT_FALSE(SendCommandSync("PWA.launchFilesInApp", |
| base::Value::Dict{} |
| .Set("manifestId", url.spec()) |
| .Set("files", AbsolutePaths({"file.png"})))); |
| AssertErrorMessageContains({url.spec()}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, OpenCurrentPageInApp) { |
| // The current browser will be taken over by the web app and the |
| // uninstallation will also close it. |
| set_agent_host_can_close(); |
| InstallFromUrl(); |
| ReattachToWebContents(InstallableWebAppUrl()); |
| ASSERT_TRUE( |
| SendCommandSync("PWA.openCurrentPageInApp", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, OpenCurrentPageInApp_NoWebContents) { |
| InstallFromUrl(); |
| ASSERT_FALSE( |
| SendCommandSync("PWA.openCurrentPageInApp", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| AssertErrorMessageContains({InstallableWebAppManifestId().spec()}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, OpenCurrentPageInApp_NotInstalled) { |
| ReattachToWebContents(InstallableWebAppUrl()); |
| ASSERT_FALSE( |
| SendCommandSync("PWA.openCurrentPageInApp", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| AssertErrorMessageContains({InstallableWebAppManifestId().spec()}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| OpenCurrentPageInApp_DifferentManifestIdUrl) { |
| set_agent_host_can_close(); |
| ManifestId manifest_id{embedded_test_server()->GetURL( |
| "/webapps_integration/standalone/basic.html")}; |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/standalone/basic.html?manifest=basic.json")}; |
| InstallFromUrl(manifest_id, url); |
| ReattachToWebContents(url); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.openCurrentPageInApp", |
| base::Value::Dict{}.Set("manifestId", manifest_id.spec()))); |
| } |
| |
| // This test should fail since web apps with browser display mode shouldn't be |
| // reparentable to match the behavior of post-installation reparenting. |
| // TODO(crbug.com/339453521): Find a proper way to check the display mode. |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| DISABLED_OpenCurrentPageInApp_NotReparentable) { |
| ManifestId manifest_id{embedded_test_server()->GetURL( |
| "/webapps_integration/standalone/basic.html")}; |
| GURL url{embedded_test_server()->GetURL( |
| "/webapps_integration/standalone/" |
| "basic.html?manifest=manifest_browser.json")}; |
| InstallFromUrl(manifest_id, url); |
| ReattachToWebContents(url); |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.openCurrentPageInApp", |
| base::Value::Dict{}.Set("manifestId", manifest_id.spec()))); |
| AssertErrorMessageContains({manifest_id.spec(), url.spec()}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| OpenCurrentPageInApp_StillAttachedInNewAppWindow) { |
| set_agent_host_can_close(); |
| InstallFromUrl(); |
| ReattachToWebContents(InstallableWebAppUrl()); |
| auto* web_contents_before = |
| browser()->tab_strip_model()->GetActiveWebContents(); |
| ASSERT_TRUE( |
| SendCommandSync("PWA.openCurrentPageInApp", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| |
| const webapps::AppId app_id = |
| web_app::GenerateAppIdFromManifestId(InstallableWebAppManifestId()); |
| BrowserWindowInterface* app_browser = |
| web_app::AppBrowserController::FindForWebApp(*browser()->profile(), |
| app_id); |
| auto* web_contents_after = |
| app_browser->GetFeatures().tab_strip_model()->GetActiveWebContents(); |
| EXPECT_NE(app_browser->GetBrowserForMigrationOnly(), browser()); |
| EXPECT_EQ(web_contents_before, web_contents_after); |
| // Use a page target API to verify the WebContents is still attached. |
| ASSERT_TRUE( |
| SendCommandSync("Page.getAppManifest", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| } |
| |
| #if BUILDFLAG(IS_MAC) |
| // Only macos needs a shortcut to open the page in app. |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, OpenCurrentPageInApp_NoShortcut) { |
| // Unlike the PWA.install, web_app::test::InstallWebApp won't create |
| // shortcuts. |
| InstallWebApp(); |
| ASSERT_FALSE( |
| SendCommandSync("PWA.openCurrentPageInApp", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| AssertErrorMessageContains({InstallableWebAppManifestId().spec()}); |
| } |
| #endif |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, ChangeAppUserSettings_ChangeNothing) { |
| InstallFromUrl(); |
| auto user_settings_before_change = |
| GetAppUserSettings(InstallableWebAppManifestId()); |
| ASSERT_TRUE( |
| SendCommandSync("PWA.changeAppUserSettings", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| EXPECT_EQ(user_settings_before_change, |
| GetAppUserSettings(InstallableWebAppManifestId())); |
| } |
| |
| #if BUILDFLAG(IS_CHROMEOS) |
| // Setting linkCapturing on ChromeOS is not supported yet. |
| // TODO(crbug.com/339453269): Implement setting linkCapturing on ChromeOS. |
| #define DISABLE_ON_CHROMEOS(x) DISABLED_##x |
| #else |
| #define DISABLE_ON_CHROMEOS(x) x |
| #endif |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| DISABLE_ON_CHROMEOS(ChangeAppUserSettings_NoApp)) { |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.changeAppUserSettings", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("linkCapturing", true) |
| .Set("displayMode", "standalone"))); |
| AssertErrorMessageContains({InstallableWebAppManifestId().spec()}); |
| } |
| |
| // Unlike the NoApp test above, even without changes, the API should check the |
| // existence of the app and returns an error. |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, ChangeAppUserSettings_NoAppNoChange) { |
| ASSERT_FALSE( |
| SendCommandSync("PWA.changeAppUserSettings", |
| base::Value::Dict{}.Set( |
| "manifestId", InstallableWebAppManifestId().spec()))); |
| AssertErrorMessageContains({InstallableWebAppManifestId().spec()}); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| PWAProtocolTest, |
| DISABLE_ON_CHROMEOS( |
| ChangeAppUserSettings_ChangeLinkCapturingAndDisplayMode)) { |
| InstallFromUrl(); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.changeAppUserSettings", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("linkCapturing", true) |
| .Set("displayMode", "standalone"))); |
| EXPECT_EQ( |
| GetAppUserSettings(InstallableWebAppManifestId()), |
| std::make_tuple(web_app::proto::NAVIGATION_CAPTURING_PREFERENCE_CAPTURE, |
| web_app::mojom::UserDisplayMode::kStandalone)); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| ChangeAppUserSettings_ChangeToStandaloneDisplayMode) { |
| InstallFromUrl(); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.changeAppUserSettings", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("displayMode", "standalone"))); |
| EXPECT_EQ(std::get<web_app::mojom::UserDisplayMode>( |
| GetAppUserSettings(InstallableWebAppManifestId())), |
| web_app::mojom::UserDisplayMode::kStandalone); |
| } |
| |
| // Even though supporting on ChromeOS hasn't been implemented, it should not |
| // crash. |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, ChangeAppUserSettings_NotCrash) { |
| InstallFromUrl(); |
| SendCommandSync("PWA.changeAppUserSettings", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("linkCapturing", true) |
| .Set("displayMode", "standalone")); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, |
| ChangeAppUserSettings_UnknownDisplayMode) { |
| InstallFromUrl(); |
| auto user_settings_before_change = |
| GetAppUserSettings(InstallableWebAppManifestId()); |
| ASSERT_FALSE(SendCommandSync( |
| "PWA.changeAppUserSettings", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("linkCapturing", true) |
| .Set("displayMode", "hello"))); |
| AssertErrorMessageContains( |
| {InstallableWebAppManifestId().spec(), "displayMode", "hello"}); |
| EXPECT_EQ(user_settings_before_change, |
| GetAppUserSettings(InstallableWebAppManifestId())); |
| } |
| |
| IN_PROC_BROWSER_TEST_F( |
| PWAProtocolTest, |
| DISABLE_ON_CHROMEOS(ChangeAppUserSettings_DoNotCapture)) { |
| InstallFromUrl(); |
| ASSERT_TRUE(SendCommandSync( |
| "PWA.changeAppUserSettings", |
| base::Value::Dict{} |
| .Set("manifestId", InstallableWebAppManifestId().spec()) |
| .Set("linkCapturing", false))); |
| EXPECT_EQ(std::get<web_app::proto::LinkCapturingUserPreference>( |
| GetAppUserSettings(InstallableWebAppManifestId())), |
| web_app::proto::NAVIGATION_CAPTURING_PREFERENCE_DO_NOT_CAPTURE); |
| } |
| |
| // This scenario does not reach the handler itself, but it's worth ensuring that |
| // running PWA.changeAppUserSettings without manifestId would always fail. |
| // The same concept applies to other APIs, but since they are using same |
| // implementation, the test won't be repeated. |
| IN_PROC_BROWSER_TEST_F(PWAProtocolTest, ChangeAppUserSettings_NoManifestId) { |
| InstallFromUrl(); |
| ASSERT_FALSE( |
| SendCommandSync("PWA.changeAppUserSettings", base::Value::Dict{})); |
| EXPECT_TRUE(error()); |
| } |
| |
| } // namespace |