blob: a4f11d03694a3226a84ca8353d9d540579a99da2 [file] [log] [blame]
// Copyright 2019 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/manifest_update_manager.h"
#include <string>
#include <vector>
#include "base/bind_helpers.h"
#include "base/memory/scoped_refptr.h"
#include "base/strings/string_util.h"
#include "base/test/bind_test_util.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/installable/installable_metrics.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/web_applications/components/app_icon_manager.h"
#include "chrome/browser/web_applications/components/app_registry_controller.h"
#include "chrome/browser/web_applications/components/app_shortcut_manager.h"
#include "chrome/browser/web_applications/components/install_finalizer.h"
#include "chrome/browser/web_applications/components/install_manager.h"
#include "chrome/browser/web_applications/components/os_integration_manager.h"
#include "chrome/browser/web_applications/components/pending_app_manager.h"
#include "chrome/browser/web_applications/components/web_app_constants.h"
#include "chrome/browser/web_applications/components/web_app_provider_base.h"
#include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
#include "chrome/browser/web_applications/system_web_app_manager.h"
#include "chrome/browser/web_applications/test/test_system_web_app_installation.h"
#include "chrome/browser/web_applications/test/web_app_install_observer.h"
#include "chrome/browser/web_applications/test/web_app_test.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/url_loader_interceptor.h"
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/test_extension_registry_observer.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/manifest/manifest.h"
#include "third_party/skia/include/core/SkColor.h"
namespace web_app {
namespace {
constexpr char kUpdateHistogramName[] = "Webapp.Update.ManifestUpdateResult";
constexpr char kInstallableIconList[] = R"(
[
{
"src": "launcher-icon-4x.png",
"sizes": "192x192",
"type": "image/png"
}
]
)";
constexpr SkColor kInstallableIconTopLeftColor =
SkColorSetRGB(0x15, 0x96, 0xE0);
constexpr char kAnotherInstallableIconList[] = R"(
[
{
"src": "/banners/image-512px.png",
"sizes": "512x512",
"type": "image/png"
}
]
)";
constexpr char kAnotherShortcutsItemName[] = "Timeline";
constexpr char kAnotherShortcutsItemUrl[] = "/shortcut";
constexpr char kAnotherShortcutsItemShortName[] = "H";
constexpr char kAnotherShortcutsItemDescription[] = "Navigate home";
constexpr char kAnotherIconSrc[] = "/launcher-icon-4x.png";
constexpr int kAnotherIconSize = 192;
constexpr char kShortcutsItem[] = R"(
[
{
"name": "Home",
"short_name": "HM",
"description": "Go home",
"url": ".",
"icons": [
{
"src": "/banners/image-512px.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
]
)";
constexpr char kShortcutsItems[] = R"(
[
{
"name": "Home",
"short_name": "HM",
"description": "Go home",
"url": ".",
"icons": [
{
"src": "/banners/image-512px.png",
"sizes": "512x512",
"type": "image/png"
}
]
},
{
"name": "Settings",
"short_name": "ST",
"description": "App settings",
"url": "/settings",
"icons": [
{
"src": "launcher-icon-4x.png",
"sizes": "192x192",
"type": "image/png"
}
]
}
]
)";
constexpr SkColor kAnotherInstallableIconTopLeftColor =
SkColorSetRGB(0x5C, 0x5C, 0x5C);
ManifestUpdateManager& GetManifestUpdateManager(Browser* browser) {
return WebAppProviderBase::GetProviderBase(browser->profile())
->manifest_update_manager();
}
class UpdateCheckResultAwaiter {
public:
explicit UpdateCheckResultAwaiter(Browser* browser, const GURL& url)
: browser_(browser), url_(url) {
SetCallback();
}
void SetCallback() {
GetManifestUpdateManager(browser_).SetResultCallbackForTesting(
base::BindOnce(&UpdateCheckResultAwaiter::OnResult,
base::Unretained(this)));
}
ManifestUpdateResult AwaitNextResult() && {
run_loop_.Run();
return *result_;
}
void OnResult(const GURL& url, ManifestUpdateResult result) {
if (url != url_) {
SetCallback();
return;
}
result_ = result;
run_loop_.Quit();
}
private:
Browser* browser_ = nullptr;
const GURL& url_;
base::RunLoop run_loop_;
base::Optional<ManifestUpdateResult> result_;
};
} // namespace
class ManifestUpdateManagerBrowserTest
: public InProcessBrowserTest,
public ::testing::WithParamInterface<ProviderType> {
public:
ManifestUpdateManagerBrowserTest() {
if (GetParam() == ProviderType::kWebApps) {
scoped_feature_list_.InitWithFeatures(
{features::kDesktopPWAsLocalUpdating,
features::kDesktopPWAsWithoutExtensions},
{});
} else if (GetParam() == ProviderType::kBookmarkApps) {
scoped_feature_list_.InitWithFeatures(
{features::kDesktopPWAsLocalUpdating},
{features::kDesktopPWAsWithoutExtensions});
}
}
~ManifestUpdateManagerBrowserTest() override = default;
void SetUp() override {
http_server_.AddDefaultHandlers(GetChromeTestDataDir());
http_server_.RegisterRequestHandler(base::BindRepeating(
&ManifestUpdateManagerBrowserTest::RequestHandlerOverride,
base::Unretained(this)));
ASSERT_TRUE(http_server_.Start());
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
GetProvider().os_integration_manager().SuppressOsHooksForTesting();
// Cannot construct RunLoop in constructor due to threading restrictions.
shortcut_run_loop_.emplace();
}
void OnShortcutInfoRetrieved(std::unique_ptr<ShortcutInfo> shortcut_info) {
if (shortcut_info) {
updated_shortcut_top_left_color_ =
shortcut_info->favicon.begin()->AsBitmap().getColor(0, 0);
}
shortcut_run_loop_->Quit();
}
void CheckShortcutInfoUpdated(const AppId& app_id, SkColor top_left_color) {
GetProvider().os_integration_manager().GetShortcutInfoForApp(
app_id, base::BindOnce(
&ManifestUpdateManagerBrowserTest::OnShortcutInfoRetrieved,
base::Unretained(this)));
shortcut_run_loop_->Run();
EXPECT_EQ(updated_shortcut_top_left_color_, top_left_color);
}
std::unique_ptr<net::test_server::HttpResponse> RequestHandlerOverride(
const net::test_server::HttpRequest& request) {
if (request_override_)
return request_override_.Run(request);
return nullptr;
}
void OverrideManifest(const char* manifest_template,
const std::vector<std::string>& substitutions) {
std::string content = base::ReplaceStringPlaceholders(
manifest_template, substitutions, nullptr);
request_override_ = base::BindLambdaForTesting(
[this, content = std::move(content)](
const net::test_server::HttpRequest& request)
-> std::unique_ptr<net::test_server::HttpResponse> {
if (request.GetURL() != GetManifestURL())
return nullptr;
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_FOUND);
http_response->set_content(content);
return std::move(http_response);
});
}
GURL GetAppURL() const {
return http_server_.GetURL("/banners/manifest_test_page.html");
}
GURL GetManifestURL() const {
return http_server_.GetURL("/banners/manifest.json");
}
AppId InstallWebApp() {
GURL app_url = GetAppURL();
ui_test_utils::NavigateToURL(browser(), app_url);
AppId app_id;
base::RunLoop run_loop;
GetProvider().install_manager().InstallWebAppFromManifestWithFallback(
browser()->tab_strip_model()->GetActiveWebContents(),
/*force_shortcut_app=*/false, WebappInstallSource::OMNIBOX_INSTALL_ICON,
base::BindOnce(TestAcceptDialogCallback),
base::BindLambdaForTesting(
[&](const AppId& new_app_id, InstallResultCode code) {
EXPECT_EQ(code, InstallResultCode::kSuccessNewInstall);
app_id = new_app_id;
run_loop.Quit();
}));
run_loop.Run();
return app_id;
}
AppId InstallPolicyApp() {
const GURL app_url = GetAppURL();
base::RunLoop run_loop;
ExternalInstallOptions install_options(
app_url, DisplayMode::kStandalone,
ExternalInstallSource::kExternalPolicy);
install_options.add_to_applications_menu = false;
install_options.add_to_desktop = false;
install_options.add_to_quick_launch_bar = false;
install_options.install_placeholder = true;
GetProvider().pending_app_manager().Install(
std::move(install_options),
base::BindLambdaForTesting(
[&](const GURL& installed_app_url, InstallResultCode code) {
EXPECT_EQ(installed_app_url, app_url);
EXPECT_EQ(code, InstallResultCode::kSuccessNewInstall);
run_loop.Quit();
}));
run_loop.Run();
return GetProvider().registrar().LookupExternalAppId(app_url).value();
}
void SetTimeOverride(base::Time time_override) {
GetManifestUpdateManager(browser()).set_time_override_for_testing(
time_override);
}
ManifestUpdateResult GetResultAfterPageLoad(const GURL& url,
const AppId* app_id) {
UpdateCheckResultAwaiter awaiter(browser(), url);
ui_test_utils::NavigateToURL(browser(), url);
return std::move(awaiter).AwaitNextResult();
}
WebAppProviderBase& GetProvider() {
return *WebAppProviderBase::GetProviderBase(browser()->profile());
}
protected:
net::EmbeddedTestServer::HandleRequestCallback request_override_;
base::HistogramTester histogram_tester_;
net::EmbeddedTestServer http_server_;
private:
base::test::ScopedFeatureList scoped_feature_list_;
base::Optional<base::RunLoop> shortcut_run_loop_;
base::Optional<SkColor> updated_shortcut_top_left_color_;
DISALLOW_COPY_AND_ASSIGN(ManifestUpdateManagerBrowserTest);
};
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckOutOfScopeNavigation) {
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), nullptr),
ManifestUpdateResult::kNoAppInScope);
AppId app_id = InstallWebApp();
EXPECT_EQ(GetResultAfterPageLoad(GURL("http://example.org"), nullptr),
ManifestUpdateResult::kNoAppInScope);
histogram_tester_.ExpectTotalCount(kUpdateHistogramName, 0);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest, CheckIsThrottled) {
constexpr base::TimeDelta kDelayBetweenChecks = base::TimeDelta::FromDays(1);
base::Time time_override = base::Time::UnixEpoch();
SetTimeOverride(time_override);
AppId app_id = InstallWebApp();
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
time_override += kDelayBetweenChecks / 2;
SetTimeOverride(time_override);
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kThrottled);
time_override += kDelayBetweenChecks;
SetTimeOverride(time_override);
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
time_override += kDelayBetweenChecks / 2;
SetTimeOverride(time_override);
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kThrottled);
time_override += kDelayBetweenChecks * 2;
SetTimeOverride(time_override);
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kThrottled, 2);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpToDate, 3);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckCancelledByWebContentsDestroyed) {
AppId app_id = InstallWebApp();
GetManifestUpdateManager(browser()).hang_update_checks_for_testing();
GURL url = GetAppURL();
UpdateCheckResultAwaiter awaiter(browser(), url);
ui_test_utils::NavigateToURL(browser(), url);
chrome::CloseTab(browser());
EXPECT_EQ(std::move(awaiter).AwaitNextResult(),
ManifestUpdateResult::kWebContentsDestroyed);
histogram_tester_.ExpectBucketCount(
kUpdateHistogramName, ManifestUpdateResult::kWebContentsDestroyed, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckCancelledByAppUninstalled) {
AppId app_id = InstallWebApp();
GetManifestUpdateManager(browser()).hang_update_checks_for_testing();
GURL url = GetAppURL();
UpdateCheckResultAwaiter awaiter(browser(), url);
ui_test_utils::NavigateToURL(browser(), url);
GetProvider().install_finalizer().UninstallWebAppFromSyncByUser(
app_id, base::DoNothing());
EXPECT_EQ(std::move(awaiter).AwaitNextResult(),
ManifestUpdateResult::kAppUninstalled);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUninstalled, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckIgnoresWhitespaceDifferences) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1
$2
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, ""});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate, {kInstallableIconList, "\n\n\n\n"});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpToDate, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckIgnoresNameChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "$1",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $2
}
)";
OverrideManifest(kManifestTemplate, {"Test app name", kInstallableIconList});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate,
{"Different app name", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpToDate, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckIgnoresShortNameChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"short_name": "$1",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $2
}
)";
OverrideManifest(kManifestTemplate,
{"Short test app name", kInstallableIconList});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate,
{"Different short test app name", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpToDate, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckIgnoresStartUrlChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": "$1",
"scope": "/",
"display": "standalone",
"icons": $2
}
)";
OverrideManifest(kManifestTemplate, {"a.html", kInstallableIconList});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate, {"b.html", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpToDate, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckIgnoresNoManifestChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList});
AppId app_id = InstallWebApp();
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpToDate, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckIgnoresInvalidManifest) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
$2
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, ""});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate, {kInstallableIconList,
"invalid manifest syntax !@#$%^*&()"});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppNotEligible);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppNotEligible, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckIgnoresNonLocalApps) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"theme_color": "$2"
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, "blue"});
AppId app_id = InstallWebApp();
GetProvider().registry_controller().SetAppIsLocallyInstalled(app_id, false);
EXPECT_FALSE(GetProvider().registrar().IsLocallyInstalled(app_id));
OverrideManifest(kManifestTemplate, {kInstallableIconList, "red"});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kNoAppInScope);
histogram_tester_.ExpectTotalCount(kUpdateHistogramName, 0);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckIgnoresPlaceholderApps) {
// Set up app URL to redirect to force placeholder app to install.
const GURL app_url = GetAppURL();
request_override_ = base::BindLambdaForTesting(
[&app_url](const net::test_server::HttpRequest& request)
-> std::unique_ptr<net::test_server::HttpResponse> {
if (request.GetURL() != app_url)
return nullptr;
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
http_response->AddCustomHeader(
"Location", "http://other-origin.com/defaultresponse");
http_response->set_content("redirect page");
return std::move(http_response);
});
// Install via PendingAppManager, the redirect to a different origin should
// cause it to install a placeholder app.
AppId app_id = InstallPolicyApp();
EXPECT_TRUE(GetProvider().registrar().IsPlaceholderApp(app_id));
// Manifest updating should ignore non-redirect loads for placeholder apps
// because the PendingAppManager will handle these.
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(app_url, &app_id),
ManifestUpdateResult::kAppIsPlaceholder);
histogram_tester_.ExpectBucketCount(
kUpdateHistogramName, ManifestUpdateResult::kAppIsPlaceholder, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckFindsThemeColorChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"theme_color": "$2"
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, "blue"});
AppId app_id = InstallWebApp();
EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id), SK_ColorBLUE);
// Check that OnWebAppInstalled and OnWebAppUninstalled are not called
// if in-place web app update happens.
WebAppInstallObserver install_observer(&GetProvider().registrar());
install_observer.SetWebAppInstalledDelegate(
base::BindLambdaForTesting([](const AppId& app_id) { NOTREACHED(); }));
install_observer.SetWebAppUninstalledDelegate(
base::BindLambdaForTesting([](const AppId& app_id) { NOTREACHED(); }));
// CSS #RRGGBBAA syntax.
OverrideManifest(kManifestTemplate, {kInstallableIconList, "#00FF00F0"});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
// Updated theme_color loses any transparency.
EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id),
SkColorSetARGB(0xFF, 0x00, 0xFF, 0x00));
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest, CheckKeepsSameName) {
constexpr char kManifestTemplate[] = R"(
{
"name": "$1",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $2,
"theme_color": "$3"
}
)";
OverrideManifest(kManifestTemplate,
{"App name 1", kInstallableIconList, "blue"});
AppId app_id = InstallWebApp();
EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id), SK_ColorBLUE);
EXPECT_EQ(GetProvider().registrar().GetAppShortName(app_id), "App name 1");
OverrideManifest(kManifestTemplate,
{"App name 2", kInstallableIconList, "red"});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id), SK_ColorRED);
// The app name must not change without user confirmation.
EXPECT_EQ(GetProvider().registrar().GetAppShortName(app_id), "App name 1");
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckFindsIconUrlChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate, {kAnotherInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kAnotherInstallableIconTopLeftColor);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckUpdatedPolicyAppsNotUninstallable) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"theme_color": "$1",
"icons": $2
}
)";
OverrideManifest(kManifestTemplate, {"blue", kInstallableIconList});
AppId app_id = InstallPolicyApp();
EXPECT_FALSE(
GetProvider().install_finalizer().CanUserUninstallFromSync(app_id));
OverrideManifest(kManifestTemplate, {"red", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
// Policy installed apps should continue to be not uninstallable by the user
// after updating.
EXPECT_FALSE(
GetProvider().install_finalizer().CanUserUninstallFromSync(app_id));
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckFindsScopeChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "$1",
"display": "standalone",
"icons": $2
}
)";
OverrideManifest(kManifestTemplate, {"/banners/", kInstallableIconList});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate, {"/", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
EXPECT_EQ(GetProvider().registrar().GetAppScope(app_id),
http_server_.GetURL("/"));
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckFindsDisplayChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "$1",
"icons": $2
}
)";
OverrideManifest(kManifestTemplate, {"minimal-ui", kInstallableIconList});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate, {"standalone", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
EXPECT_EQ(GetProvider().registrar().GetAppDisplayMode(app_id),
DisplayMode::kStandalone);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckFindsDisplayBrowserChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "$1",
"icons": $2
}
)";
OverrideManifest(kManifestTemplate, {"standalone", kInstallableIconList});
AppId app_id = InstallWebApp();
GetProvider().registry_controller().SetAppUserDisplayMode(
app_id, DisplayMode::kStandalone);
OverrideManifest(kManifestTemplate, {"browser", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
EXPECT_EQ(GetProvider().registrar().GetAppDisplayMode(app_id),
DisplayMode::kBrowser);
// We don't touch the user's launch preference even if the app display mode
// changes. Instead the effective display mode changes.
EXPECT_EQ(GetProvider().registrar().GetAppUserDisplayMode(app_id),
DisplayMode::kStandalone);
EXPECT_EQ(GetProvider().registrar().GetAppEffectiveDisplayMode(app_id),
DisplayMode::kMinimalUi);
}
// A dedicated test fixture for DisplayOverride, which is supported
// only for the new web apps mode, and requires a command line switch
// to enable manifest parsing.
class ManifestUpdateManagerBrowserTest_DisplayOverride
: public ManifestUpdateManagerBrowserTest {
public:
ManifestUpdateManagerBrowserTest_DisplayOverride() {
scoped_feature_list_.InitAndEnableFeature(
features::kWebAppManifestDisplayOverride);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest_DisplayOverride,
CheckFindsDisplayOverrideChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"display_override": $1,
"icons": $2
}
)";
OverrideManifest(kManifestTemplate,
{R"([ "fullscreen", "standalone" ])", kInstallableIconList});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate,
{R"([ "fullscreen", "minimal-ui" ])", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
std::vector<DisplayMode> app_display_mode_override =
GetProvider().registrar().GetAppDisplayModeOverride(app_id);
ASSERT_EQ(2u, app_display_mode_override.size());
EXPECT_EQ(DisplayMode::kFullscreen, app_display_mode_override[0]);
EXPECT_EQ(DisplayMode::kMinimalUi, app_display_mode_override[1]);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest_DisplayOverride,
CheckFindsNewDisplayOverride) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
$1
"icons": $2
}
)";
// No display_override in manifest
OverrideManifest(kManifestTemplate, {"", kInstallableIconList});
AppId app_id = InstallWebApp();
// Add display_override field
OverrideManifest(kManifestTemplate,
{R"("display_override": [ "minimal-ui", "standalone" ],)",
kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
std::vector<DisplayMode> app_display_mode_override =
GetProvider().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]);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest_DisplayOverride,
CheckFindsDeletedDisplayOverride) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
$1
"icons": $2
}
)";
// Ensure display_override exists in initial manifest
OverrideManifest(kManifestTemplate,
{R"("display_override": [ "fullscreen", "minimal-ui" ],)",
kInstallableIconList});
AppId app_id = InstallWebApp();
// Remove display_override from manifest
OverrideManifest(kManifestTemplate, {"", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
std::vector<DisplayMode> app_display_mode_override =
GetProvider().registrar().GetAppDisplayModeOverride(app_id);
ASSERT_EQ(0u, app_display_mode_override.size());
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest_DisplayOverride,
CheckFindsInvalidDisplayOverride) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"display_override": $1,
"icons": $2
}
)";
OverrideManifest(kManifestTemplate,
{R"([ "browser", "fullscreen" ])", kInstallableIconList});
AppId app_id = InstallWebApp();
ASSERT_EQ(2u,
GetProvider().registrar().GetAppDisplayModeOverride(app_id).size());
// display_override contains only invalid values
OverrideManifest(kManifestTemplate,
{R"( [ "invalid", 7 ])", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
std::vector<DisplayMode> app_display_mode_override =
GetProvider().registrar().GetAppDisplayModeOverride(app_id);
ASSERT_EQ(0u, app_display_mode_override.size());
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest_DisplayOverride,
CheckIgnoresDisplayOverrideInvalidChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
$1
"icons": $2
}
)";
// No display_override in manifest
OverrideManifest(kManifestTemplate, {"", kInstallableIconList});
AppId app_id = InstallWebApp();
// display_override contains only invalid values
OverrideManifest(
kManifestTemplate,
{R"("display_override": [ "invalid", 7 ],)", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpToDate, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest_DisplayOverride,
CheckIgnoresDisplayOverrideChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"display_override": $1,
"icons": $2
}
)";
OverrideManifest(kManifestTemplate,
{R"([ "standard", "fullscreen" ])", kInstallableIconList});
AppId app_id = InstallWebApp();
// display_override contains an additional invalid value
OverrideManifest(
kManifestTemplate,
{R"([ "invalid", "standard", "fullscreen" ])", kInstallableIconList});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpToDate, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckFindsIconContentChange) {
constexpr char kManifest[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": [
{
"src": "/web_apps/basic-192.png?ignore",
"sizes": "192x192",
"type": "image/png"
}
]
}
)";
OverrideManifest(kManifest, {});
AppId app_id = InstallWebApp();
// Replace the contents of basic-192.png with blue-192.png without changing
// the URL.
content::URLLoaderInterceptor url_interceptor(base::BindLambdaForTesting(
[this](content::URLLoaderInterceptor::RequestParams* params)
-> bool /*intercepted*/ {
if (params->url_request.url ==
http_server_.GetURL("/web_apps/basic-192.png?ignore")) {
content::URLLoaderInterceptor::WriteResponse(
"chrome/test/data/web_apps/blue-192.png", params->client.get());
return true;
}
return false;
}));
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
CheckShortcutInfoUpdated(app_id, SK_ColorBLUE);
EXPECT_EQ(ReadAppIconPixel(browser()->profile(), app_id, /*size=*/192,
/*x=*/0, /*y=*/0),
SK_ColorBLUE);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTest,
CheckIgnoresIconDownloadFail) {
constexpr char kManifest[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": [
{
"src": "/web_apps/basic-48.png?ignore",
"sizes": "48x48",
"type": "image/png"
},
{
"src": "/web_apps/basic-192.png?ignore",
"sizes": "192x192",
"type": "image/png"
}
]
}
)";
OverrideManifest(kManifest, {});
AppId app_id = InstallWebApp();
// Make basic-48.png fail to download.
// Replace the contents of basic-192.png with blue-192.png without changing
// the URL.
content::URLLoaderInterceptor url_interceptor(base::BindLambdaForTesting(
[this](content::URLLoaderInterceptor::RequestParams* params)
-> bool /*intercepted*/ {
if (params->url_request.url ==
http_server_.GetURL("/web_apps/basic-48.png?ignore")) {
content::URLLoaderInterceptor::WriteResponse("malformed response", "",
params->client.get());
return true;
}
if (params->url_request.url ==
http_server_.GetURL("/web_apps/basic-192.png?ignore")) {
content::URLLoaderInterceptor::WriteResponse(
"chrome/test/data/web_apps/blue-192.png", params->client.get());
return true;
}
return false;
}));
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kIconDownloadFailed);
histogram_tester_.ExpectBucketCount(
kUpdateHistogramName, ManifestUpdateResult::kIconDownloadFailed, 1);
EXPECT_EQ(ReadAppIconPixel(browser()->profile(), app_id, /*size=*/48, /*x=*/0,
/*y=*/0),
SK_ColorBLACK);
EXPECT_EQ(ReadAppIconPixel(browser()->profile(), app_id, /*size=*/192,
/*x=*/0, /*y=*/0),
SK_ColorBLACK);
}
class ManifestUpdateManagerSystemAppBrowserTest
: public ManifestUpdateManagerBrowserTest {
public:
static constexpr char kSystemAppManifestText[] =
R"({
"name": "Test System App",
"display": "standalone",
"icons": [
{
"src": "icon-256.png",
"sizes": "256x256",
"type": "image/png"
}
],
"start_url": "/pwa.html",
"theme_color": "$1"
})";
ManifestUpdateManagerSystemAppBrowserTest()
: system_app_(
TestSystemWebAppInstallation::SetUpStandaloneSingleWindowApp(
false)) {
system_app_->SetManifest(base::ReplaceStringPlaceholders(
kSystemAppManifestText, {"#0f0"}, nullptr));
}
void SetUpOnMainThread() override { system_app_->WaitForAppInstall(); }
protected:
std::unique_ptr<TestSystemWebAppInstallation> system_app_;
};
constexpr char
ManifestUpdateManagerSystemAppBrowserTest::kSystemAppManifestText[];
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerSystemAppBrowserTest,
CheckUpdateSkipped) {
system_app_->SetManifest(base::ReplaceStringPlaceholders(
kSystemAppManifestText, {"#f00"}, nullptr));
AppId app_id = system_app_->GetAppId();
EXPECT_EQ(GetResultAfterPageLoad(system_app_->GetAppUrl(), &app_id),
ManifestUpdateResult::kAppIsSystemWebApp);
histogram_tester_.ExpectBucketCount(
kUpdateHistogramName, ManifestUpdateResult::kAppIsSystemWebApp, 1);
EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id), SK_ColorGREEN);
}
using ManifestUpdateManagerWebAppsBrowserTest =
ManifestUpdateManagerBrowserTest;
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerWebAppsBrowserTest,
CheckFindsThemeColorChangeForShadowBookmarkApp) {
auto* extensions_registry =
extensions::ExtensionRegistry::Get(browser()->profile());
extensions::TestExtensionRegistryObserver extensions_registry_observer(
extensions_registry);
extensions::BookmarkAppRegistrar bookmark_app_registrar{browser()->profile()};
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"theme_color": "$2"
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, "blue"});
AppId app_id = InstallWebApp();
EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id), SK_ColorBLUE);
scoped_refptr<const extensions::Extension> extension =
extensions_registry_observer.WaitForExtensionInstalled();
EXPECT_EQ(extension->id(), app_id);
EXPECT_EQ(bookmark_app_registrar.GetAppThemeColor(app_id).value(),
SK_ColorBLUE);
OverrideManifest(kManifestTemplate, {kInstallableIconList, "red"});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
CheckShortcutInfoUpdated(app_id, kInstallableIconTopLeftColor);
EXPECT_EQ(GetProvider().registrar().GetAppThemeColor(app_id), SK_ColorRED);
// Wait for all update events sequentially. Otherwise the test is flaky.
extensions_registry_observer.WaitForExtensionUnloaded();
extensions_registry_observer.WaitForExtensionLoaded();
extension = extensions_registry_observer.WaitForExtensionReady();
EXPECT_EQ(extension->id(), app_id);
EXPECT_EQ(bookmark_app_registrar.GetAppThemeColor(app_id).value(),
SK_ColorRED);
}
class ManifestUpdateManagerBrowserTestWithShortcutsMenu
: public ManifestUpdateManagerBrowserTest {
public:
ManifestUpdateManagerBrowserTestWithShortcutsMenu() {
scoped_feature_list_.InitAndEnableFeature(
features::kDesktopPWAsAppIconShortcutsMenu);
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTestWithShortcutsMenu,
CheckFindsShortcutsMenuUpdated) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"shortcuts": $2
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, kShortcutsItem});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate, {kInstallableIconList, kShortcutsItems});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
EXPECT_EQ(
GetProvider().registrar().GetAppShortcutsMenuItemInfos(app_id).size(),
2u);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTestWithShortcutsMenu,
CheckFindsItemNameUpdated) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"shortcuts": [
{
"name": "$2",
"short_name": "HM",
"description": "Go home",
"url": ".",
"icons": [
{
"src": "/banners/image-512px.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
]
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, "Home"});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate,
{kInstallableIconList, kAnotherShortcutsItemName});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
EXPECT_EQ(
GetProvider().registrar().GetAppShortcutsMenuItemInfos(app_id)[0].name,
base::UTF8ToUTF16(kAnotherShortcutsItemName));
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTestWithShortcutsMenu,
CheckIgnoresShortNameAndDescriptionChange) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"shortcuts": [
{
"name": "Home",
"short_name": "$2",
"description": "$3",
"url": ".",
"icons": [
{
"src": "/banners/image-512px.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
]
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, "HM", "Go home"});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate,
{kInstallableIconList, kAnotherShortcutsItemShortName,
kAnotherShortcutsItemDescription});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpToDate);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpToDate, 1);
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTestWithShortcutsMenu,
CheckFindsItemUrlUpdated) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"shortcuts": [
{
"name": "Home",
"short_name": "HM",
"description": "Go home",
"url": "$2",
"icons": [
{
"src": "/banners/image-512px.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
]
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, "/"});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate,
{kInstallableIconList, kAnotherShortcutsItemUrl});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
EXPECT_EQ(
GetProvider().registrar().GetAppShortcutsMenuItemInfos(app_id)[0].url,
http_server_.GetURL(kAnotherShortcutsItemUrl));
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTestWithShortcutsMenu,
CheckFindsShortcutIconContentChange) {
constexpr char kManifest[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"shortcuts": [
{
"name": "Home",
"short_name": "HM",
"description": "Go home",
"url": "/",
"icons": [
{
"src": "/web_apps/basic-192.png?ignore",
"sizes": "192x192",
"type": "image/png"
}
]
}
]
}
)";
OverrideManifest(kManifest, {kInstallableIconList});
AppId app_id = InstallWebApp();
// Replace the contents of basic-192.png with blue-192.png without changing
// the URL.
content::URLLoaderInterceptor url_interceptor(base::BindLambdaForTesting(
[this](content::URLLoaderInterceptor::RequestParams* params)
-> bool /*intercepted*/ {
if (params->url_request.url ==
http_server_.GetURL("/web_apps/basic-192.png?ignore")) {
content::URLLoaderInterceptor::WriteResponse(
"chrome/test/data/web_apps/blue-192.png", params->client.get());
return true;
}
return false;
}));
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
// Check that the installed icon is now blue.
base::RunLoop run_loop;
GetProvider().icon_manager().ReadAllShortcutsMenuIcons(
app_id,
base::BindLambdaForTesting(
[&run_loop](ShortcutsMenuIconsBitmaps shortcuts_menu_icons_bitmaps) {
run_loop.Quit();
EXPECT_EQ(shortcuts_menu_icons_bitmaps[0].at(192).getColor(0, 0),
SK_ColorBLUE);
}));
run_loop.Run();
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTestWithShortcutsMenu,
CheckFindsShortcutIconSrcUpdated) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"shortcuts": [
{
"name": "Home",
"short_name": "HM",
"description": "Go home",
"url": ".",
"icons": [
{
"src": "$2",
"sizes": "512x512",
"type": "image/png"
}
]
}
]
}
)";
OverrideManifest(kManifestTemplate,
{kInstallableIconList, "/banners/image-512px.png"});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate, {kInstallableIconList, kAnotherIconSrc});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
EXPECT_EQ(GetProvider()
.registrar()
.GetAppShortcutsMenuItemInfos(app_id)[0]
.shortcut_icon_infos[0]
.url,
http_server_.GetURL(kAnotherIconSrc));
}
IN_PROC_BROWSER_TEST_P(ManifestUpdateManagerBrowserTestWithShortcutsMenu,
CheckFindsShortcutIconSizesUpdated) {
constexpr char kManifestTemplate[] = R"(
{
"name": "Test app name",
"start_url": ".",
"scope": "/",
"display": "standalone",
"icons": $1,
"shortcuts": [
{
"name": "Home",
"short_name": "HM",
"description": "Go home",
"url": ".",
"icons": [
{
"src": "/banners/image-512px.png",
"sizes": "$2",
"type": "image/png"
}
]
}
]
}
)";
OverrideManifest(kManifestTemplate, {kInstallableIconList, "512x512"});
AppId app_id = InstallWebApp();
OverrideManifest(kManifestTemplate,
{kInstallableIconList,
gfx::Size(kAnotherIconSize, kAnotherIconSize).ToString()});
EXPECT_EQ(GetResultAfterPageLoad(GetAppURL(), &app_id),
ManifestUpdateResult::kAppUpdated);
histogram_tester_.ExpectBucketCount(kUpdateHistogramName,
ManifestUpdateResult::kAppUpdated, 1);
EXPECT_EQ(GetProvider()
.registrar()
.GetAppShortcutsMenuItemInfos(app_id)[0]
.shortcut_icon_infos[0]
.square_size_px,
kAnotherIconSize);
}
INSTANTIATE_TEST_SUITE_P(All,
ManifestUpdateManagerBrowserTest,
::testing::Values(ProviderType::kBookmarkApps,
ProviderType::kWebApps),
ProviderTypeParamToString);
INSTANTIATE_TEST_SUITE_P(All,
ManifestUpdateManagerSystemAppBrowserTest,
::testing::Values(ProviderType::kBookmarkApps,
ProviderType::kWebApps),
ProviderTypeParamToString);
INSTANTIATE_TEST_SUITE_P(All,
ManifestUpdateManagerWebAppsBrowserTest,
::testing::Values(ProviderType::kWebApps),
ProviderTypeParamToString);
INSTANTIATE_TEST_SUITE_P(All,
ManifestUpdateManagerBrowserTestWithShortcutsMenu,
::testing::Values(ProviderType::kBookmarkApps,
ProviderType::kWebApps),
ProviderTypeParamToString);
// DisplayOverride is supported only for the new web apps mode
INSTANTIATE_TEST_SUITE_P(All,
ManifestUpdateManagerBrowserTest_DisplayOverride,
::testing::Values(ProviderType::kWebApps),
ProviderTypeParamToString);
} // namespace web_app