blob: ad616049b191c5b207e68b282497068a09591ac5 [file] [log] [blame]
// 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