blob: b3e3ccd398a977a6ab3bac816b6bc7c95f76a67d [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/command_line.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "chrome/browser/banners/test_app_banner_manager_desktop.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/views/intent_picker_bubble_view.h"
#include "chrome/browser/ui/web_applications/app_browser_controller.h"
#include "chrome/browser/ui/web_applications/test/web_app_browsertest_util.h"
#include "chrome/browser/ui/web_applications/web_app_browsertest_base.h"
#include "chrome/browser/ui/web_applications/web_app_dialogs.h"
#include "chrome/browser/web_applications/test/command_metrics_test_helper.h"
#include "chrome/browser/web_applications/test/web_app_test_utils.h"
#include "chrome/browser/web_applications/web_app_command_manager.h"
#include "chrome/browser/web_applications/web_app_helpers.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/browser/web_applications/web_install_service_impl.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/webapps/browser/install_result_code.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_renderer_host.h"
#include "net/base/url_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features_generated.h"
#include "third_party/blink/public/mojom/use_counter/metrics/webdx_feature.mojom.h"
#include "ui/views/test/dialog_test.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/widget/any_widget_observer.h"
#include "web_install_service_impl.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "ash/constants/ash_switches.h"
#include "chrome/test/base/testing_profile.h"
#include "components/user_manager/user_names.h"
#endif // BUILDFLAG(IS_CHROMEOS)
namespace {
constexpr webapps::WebappInstallSource kInstallSource =
webapps::WebappInstallSource::WEB_INSTALL;
constexpr char kAbortError[] = "AbortError";
constexpr char kDataError[] = "DataError";
constexpr char kNotAllowedError[] = "NotAllowedError";
constexpr char kTypeError[] = "TypeError";
constexpr char kInstallResultUma[] = "WebApp.WebInstallApi.Result";
constexpr char kInstallTypeUma[] = "WebApp.WebInstallApi.InstallType";
} // namespace
namespace web_app {
class WebInstallCurrentDocumentBrowserTest : public WebAppBrowserTestBase {
public:
WebInstallCurrentDocumentBrowserTest() = default;
void SetUpOnMainThread() override {
WebAppBrowserTestBase::SetUpOnMainThread();
webapps::TestAppBannerManagerDesktop::SetUp();
}
// 0 parameter navigator.install()
bool TryInstallApp(bool with_gesture = true) {
const std::string script =
"navigator.install()"
".then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});";
if (with_gesture) {
return ExecJs(web_contents(), script);
} else {
return ExecJs(web_contents(), script,
content::EXECUTE_SCRIPT_NO_USER_GESTURE);
}
}
// Tests start on an about:blank page. We need to navigate to any valid URL
// before we can execute `navigator.install()`
void NavigateToValidUrl() {
VLOG(0) << https_server()->GetURL("/simple.html").spec();
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_server()->GetURL("/simple.html")));
}
void NavigateAndConfigureCurrentDocumentForInstall(
const GURL& current_doc_url) {
auto* manager =
webapps::TestAppBannerManagerDesktop::FromWebContents(web_contents());
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), current_doc_url));
manager->WaitForInstallableCheck();
}
content::WebContents* web_contents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
bool ResultExists(content::WebContents* contents = nullptr) {
if (!contents) {
contents = web_contents();
}
// ExecJs returns false when an error is thrown, including when a variable
// is undefined.
return ExecJs(contents, "webInstallResult");
}
bool ErrorExists(content::WebContents* contents = nullptr) {
if (!contents) {
contents = web_contents();
}
// ExecJs returns false when an error is thrown, including when a variable
// is undefined.
return ExecJs(contents, "webInstallError");
}
const std::string GetManifestIdResult(
content::WebContents* contents = nullptr) {
if (!contents) {
contents = web_contents();
}
return EvalJs(contents, "webInstallResult.manifestId").ExtractString();
}
const std::string GetErrorName(content::WebContents* contents = nullptr) {
if (!contents) {
contents = web_contents();
}
return EvalJs(contents, "webInstallError.name").ExtractString();
}
private:
base::test::ScopedFeatureList scoped_feature_list_{
blink::features::kWebAppInstallation};
};
IN_PROC_BROWSER_TEST_F(WebInstallCurrentDocumentBrowserTest, Install_NoParams) {
GURL current_doc_url =
https_server()->GetURL("/banners/manifest_with_id_test_page.html");
const std::string manifest_id =
GenerateManifestId("some_id", current_doc_url).spec();
NavigateAndConfigureCurrentDocumentForInstall(current_doc_url);
auto auto_accept_pwa_install_confirmation =
SetAutoAcceptPWAInstallConfirmationForTesting();
base::test::TestFuture<const webapps::AppId&, webapps::InstallResultCode>
install_future;
SetInstalledCallbackForTesting(install_future.GetCallback());
base::HistogramTester histograms;
ui_test_utils::BrowserChangeObserver wait_for_web_app(
nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
ASSERT_TRUE(TryInstallApp());
// Verify that the app was installed.
EXPECT_TRUE(install_future.Wait());
ASSERT_TRUE(install_future.Get<webapps::InstallResultCode>() ==
webapps::InstallResultCode::kSuccessNewInstall);
// Verify that the app was launched.
auto* app_browser = wait_for_web_app.Wait();
ASSERT_TRUE(web_app::AppBrowserController::IsWebApp(app_browser));
auto* app_web_contents =
app_browser->tab_strip_model()->GetActiveWebContents();
// Validate JS results.
EXPECT_TRUE(ResultExists(app_web_contents));
EXPECT_FALSE(ErrorExists(app_web_contents));
histograms.ExpectBucketCount("Blink.UseCounter.WebDXFeatures",
blink::mojom::WebDXFeature::kDRAFT_WebInstallAPI,
1);
// Validate browser results.
histograms.ExpectUniqueSample("WebApp.Install.Source.Success", kInstallSource,
1);
// Current document installs launch via reparenting.
histograms.ExpectUniqueSample("WebApp.LaunchSource",
apps::LaunchSource::kFromReparenting, 1);
histograms.ExpectUniqueSample("WebApp.NewCraftedAppInstalled.ByUser",
/*sample=*/true, 1);
histograms.ExpectBucketCount(kInstallResultUma,
web_app::WebInstallApiResult::kSuccess, 1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
// TODO(crbug.com/402806158): Log the correct InstallMetrics for current
// document installs. Until we refactor all the commands, just verify that
// FetchManifestAndInstall was logged, as that's what current doc installs
// are using for now.
EXPECT_THAT(histograms,
test::ForAllGetAllSamples(
test::GetInstallCommandResultHistogramNames(
".FetchManifestAndInstall", ".Crafted"),
base::BucketsAre(base::Bucket(
webapps::InstallResultCode::kSuccessNewInstall, 1))));
EXPECT_THAT(histograms,
test::ForAllGetAllSamples(
test::GetInstallCommandSourceHistogramNames(
".FetchManifestAndInstall", ".Crafted"),
base::BucketsAre(base::Bucket(
webapps::WebappInstallSource::WEB_INSTALL, 1))));
}
IN_PROC_BROWSER_TEST_F(WebInstallCurrentDocumentBrowserTest,
UserDeclinesInstallDialog) {
GURL current_doc_url =
https_server()->GetURL("/banners/manifest_with_id_test_page.html");
NavigateAndConfigureCurrentDocumentForInstall(current_doc_url);
// Simulate the user declining the install dialog.
auto auto_decline_pwa_install_confirmation =
SetAutoDeclinePWAInstallConfirmationForTesting();
base::HistogramTester histograms;
ASSERT_TRUE(TryInstallApp());
// Validate JS results.
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kAbortError);
// Validate browser results.
histograms.ExpectUniqueSample("WebApp.Install.Source.Failure", kInstallSource,
1);
histograms.ExpectBucketCount(
kInstallResultUma, web_app::WebInstallApiResult::kCanceledByUser, 1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
}
IN_PROC_BROWSER_TEST_F(WebInstallCurrentDocumentBrowserTest,
UserAcceptsOpenDialog) {
GURL current_doc_url =
https_server()->GetURL("/banners/manifest_with_id_test_page.html");
const std::string manifest_id =
GenerateManifestId("some_id", current_doc_url).spec();
auto auto_accept_pwa_install_confirmation =
SetAutoAcceptPWAInstallConfirmationForTesting();
base::HistogramTester histograms;
// Install current doc, wait for app browser window to appear and close it.
webapps::AppId app_id = web_app::InstallWebAppFromPageAndCloseAppBrowser(
browser(), current_doc_url);
// Verify that the app was installed and launched.
histograms.ExpectUniqueSample("WebApp.LaunchSource",
apps::LaunchSource::kFromReparenting, 1);
// Navigate again to the just installed current doc in the browser window.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), current_doc_url));
auto auto_accept_intent_picker =
IntentPickerBubbleView::SetAutoAcceptIntentPickerBubbleForTesting();
ui_test_utils::BrowserChangeObserver wait_for_launch_app(
nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
// Call navigator.install() to trigger the intent picker.
ASSERT_TRUE(TryInstallApp());
// Verify the app was launched again after accepting the intent picker.
auto* launched_app_browser = wait_for_launch_app.Wait();
ASSERT_TRUE(web_app::AppBrowserController::IsWebApp(launched_app_browser));
auto* launched_app_web_contents =
launched_app_browser->tab_strip_model()->GetActiveWebContents();
// Validate JS results.
EXPECT_TRUE(ResultExists(launched_app_web_contents));
EXPECT_FALSE(ErrorExists(launched_app_web_contents));
// Validate browser results.
histograms.ExpectUniqueSample("WebApp.LaunchSource",
apps::LaunchSource::kFromReparenting, 2);
histograms.ExpectBucketCount(
kInstallResultUma, web_app::WebInstallApiResult::kSuccessAlreadyInstalled,
1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
}
IN_PROC_BROWSER_TEST_F(WebInstallCurrentDocumentBrowserTest,
UserCancelsOpenDialog) {
GURL current_doc_url =
https_server()->GetURL("/banners/manifest_with_id_test_page.html");
const std::string manifest_id =
GenerateManifestId("some_id", current_doc_url).spec();
auto auto_accept_pwa_install_confirmation =
SetAutoAcceptPWAInstallConfirmationForTesting();
base::HistogramTester histograms;
// Install current doc, wait for app browser window to appear and close it.
webapps::AppId app_id = web_app::InstallWebAppFromPageAndCloseAppBrowser(
browser(), current_doc_url);
// Verify that the app was installed and launched.
histograms.ExpectUniqueSample("WebApp.LaunchSource",
apps::LaunchSource::kFromReparenting, 1);
// Navigate again to the just installed current doc in the browser window.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), current_doc_url));
auto auto_cancel_intent_picker =
IntentPickerBubbleView::SetAutoCancelIntentPickerBubbleForTesting();
ASSERT_TRUE(TryInstallApp());
// Validate JS results.
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
// Validate browser results.
histograms.ExpectBucketCount(
kInstallResultUma, web_app::WebInstallApiResult::kSuccessAlreadyInstalled,
1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
}
IN_PROC_BROWSER_TEST_F(WebInstallCurrentDocumentBrowserTest,
IntentPickerAfterTabSwitching) {
GURL current_doc_url =
https_server()->GetURL("/banners/manifest_with_id_test_page.html");
auto auto_accept_pwa_install_confirmation =
SetAutoAcceptPWAInstallConfirmationForTesting();
base::HistogramTester histograms;
// Install current doc, wait for app browser window to appear and close it.
webapps::AppId app_id = web_app::InstallWebAppFromPageAndCloseAppBrowser(
browser(), current_doc_url);
// Verify that the app was installed and launched.
histograms.ExpectUniqueSample("WebApp.LaunchSource",
apps::LaunchSource::kFromReparenting, 1);
views::NamedWidgetShownWaiter intent_picker_bubble_shown(
views::test::AnyWidgetTestPasskey{},
IntentPickerBubbleView::kViewClassName);
// Navigate again to the just installed current doc in the browser window.
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), current_doc_url));
// EvalJs blocks until the promise resolves which only happens after the
// dialog is closed. Execute the script asynchronously so we can change tabs
// before the promise times out.
ExecuteScriptAsync(web_contents(),
"navigator.install()"
".then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});");
// Wait for the intent picker bubble to show.
views::Widget* intent_picker =
intent_picker_bubble_shown.WaitIfNeededAndGet();
ASSERT_NE(intent_picker, nullptr);
// Change focus to a new tab.
chrome::NewTab(browser());
// Switch back to the tab with the app to validate JS results.
chrome::SelectPreviousTab(browser());
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kAbortError);
// Validate browser results.
histograms.ExpectBucketCount(
kInstallResultUma, web_app::WebInstallApiResult::kSuccessAlreadyInstalled,
1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
}
// Tests for WebAppInstallNotSupportedDialog appearing in Incognito and Guest
// modes since web app installs are not supported in these modes. The dialog
// appears for all current and background document installs.
IN_PROC_BROWSER_TEST_F(WebInstallCurrentDocumentBrowserTest,
NotSupportedDialogInIncognito) {
// Open incognito window and navigate to a valid URL.
GURL test_url = https_server()->GetURL("/simple.html");
Browser* incognito_browser =
OpenURLOffTheRecord(browser()->profile(), test_url);
views::NamedWidgetShownWaiter widget_waiter(
views::test::AnyWidgetTestPasskey{}, "WebAppInstallNotSupportedDialog");
content::WebContents* incognito_web_contents =
incognito_browser->tab_strip_model()->GetActiveWebContents();
base::HistogramTester histograms;
// Trigger the Install Not Supported dialog by initiating an install request.
ExecuteScriptAsync(incognito_web_contents,
"navigator.install()"
".then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});");
// Wait for the dialog to show.
views::Widget* widget = widget_waiter.WaitIfNeededAndGet();
ASSERT_NE(widget, nullptr);
views::test::WidgetDestroyedWaiter destroyed(widget);
// Verify dialog title for Incognito mode.
EXPECT_EQ(
widget->widget_delegate()->AsBubbleDialogDelegate()->GetWindowTitle(),
u"Web app installs aren't supported in Incognito mode");
// Simulate the user accepting the dialog.
views::test::AcceptDialog(widget);
destroyed.Wait();
// Validate JS results.
EXPECT_FALSE(ResultExists(incognito_web_contents));
EXPECT_TRUE(ErrorExists(incognito_web_contents));
EXPECT_EQ(GetErrorName(incognito_web_contents), kAbortError);
histograms.ExpectBucketCount(
kInstallResultUma, web_app::WebInstallApiResult::kUnsupportedProfile, 1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
}
IN_PROC_BROWSER_TEST_F(WebInstallCurrentDocumentBrowserTest,
NotSupportedDialogAfterTabSwitching) {
// Open incognito window and navigate to a valid URL.
GURL test_url = https_server()->GetURL("/simple.html");
Browser* incognito_browser =
OpenURLOffTheRecord(browser()->profile(), test_url);
views::NamedWidgetShownWaiter widget_waiter(
views::test::AnyWidgetTestPasskey{}, "WebAppInstallNotSupportedDialog");
content::WebContents* incognito_web_contents =
incognito_browser->tab_strip_model()->GetActiveWebContents();
base::HistogramTester histograms;
// Trigger the Install Not Supported dialog by initiating an install request.
ExecuteScriptAsync(incognito_web_contents,
"navigator.install()"
".then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});");
// Wait for the dialog to show.
views::Widget* widget = widget_waiter.WaitIfNeededAndGet();
ASSERT_NE(widget, nullptr);
// Change focus to a new tab.
chrome::NewTab(incognito_browser);
// Validate JS results.
EXPECT_FALSE(ResultExists(incognito_web_contents));
EXPECT_TRUE(ErrorExists(incognito_web_contents));
EXPECT_EQ(GetErrorName(incognito_web_contents), kAbortError);
histograms.ExpectBucketCount(
kInstallResultUma, web_app::WebInstallApiResult::kUnsupportedProfile, 1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
}
class WebInstallGuestModeTest : public WebInstallCurrentDocumentBrowserTest {
public:
WebInstallGuestModeTest() = default;
WebInstallGuestModeTest(const WebInstallGuestModeTest&) = delete;
WebInstallGuestModeTest& operator=(const WebInstallGuestModeTest&) = delete;
#if BUILDFLAG(IS_CHROMEOS)
// To create a guest session in ChromeOS, CreateGuestBrowser() cannot be used
// and proper switches to commandline need to be set.
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(ash::switches::kGuestSession);
command_line->AppendSwitchASCII(ash::switches::kLoginUser,
user_manager::kGuestUserName);
command_line->AppendSwitchASCII(ash::switches::kLoginProfile,
TestingProfile::kTestUserProfileDir);
}
#endif // BUILDFLAG(IS_CHROMEOS)
};
IN_PROC_BROWSER_TEST_F(WebInstallGuestModeTest, NotSupportedDialogInGuestMode) {
// Open a new guest mode window.
#if BUILDFLAG(IS_CHROMEOS)
Browser* guest_browser = browser();
#else
Browser* guest_browser = CreateGuestBrowser();
#endif // BUILDFLAG(IS_CHROMEOS)
ASSERT_TRUE(guest_browser->profile()->IsGuestSession());
// Navigate to a valid URL in the guest browser.
ASSERT_TRUE(ui_test_utils::NavigateToURL(
guest_browser, https_server()->GetURL("/simple.html")));
views::NamedWidgetShownWaiter widget_waiter(
views::test::AnyWidgetTestPasskey{}, "WebAppInstallNotSupportedDialog");
content::WebContents* guest_web_contents =
guest_browser->tab_strip_model()->GetActiveWebContents();
base::HistogramTester histograms;
// Trigger the Install Not Supported dialog by initiating an install request.
ExecuteScriptAsync(guest_web_contents,
"navigator.install()"
".then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});");
// Confirm Install Not Supported Dialog shows.
views::Widget* widget = widget_waiter.WaitIfNeededAndGet();
ASSERT_NE(widget, nullptr);
views::test::WidgetDestroyedWaiter destroyed(widget);
// Verify dialog title for Guest mode.
EXPECT_EQ(
widget->widget_delegate()->AsBubbleDialogDelegate()->GetWindowTitle(),
u"Web app installs aren't supported in Guest mode");
// Simulate the user accepting the dialog.
views::test::AcceptDialog(widget);
destroyed.Wait();
// Validate JS results.
EXPECT_FALSE(ResultExists(guest_web_contents));
EXPECT_TRUE(ErrorExists(guest_web_contents));
EXPECT_EQ(GetErrorName(guest_web_contents), kAbortError);
histograms.ExpectBucketCount(
kInstallResultUma, web_app::WebInstallApiResult::kUnsupportedProfile, 1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
}
// Manifest validation for current document installs.
using WebInstallCurrentDocumentBrowserTestManifestErrors =
WebInstallCurrentDocumentBrowserTest;
IN_PROC_BROWSER_TEST_F(WebInstallCurrentDocumentBrowserTestManifestErrors,
NoManifest) {
GURL current_doc_url =
https_server()->GetURL("/banners/no_manifest_test_page.html");
NavigateAndConfigureCurrentDocumentForInstall(current_doc_url);
base::HistogramTester histograms;
ASSERT_TRUE(TryInstallApp());
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kAbortError);
histograms.ExpectBucketCount(
kInstallResultUma, web_app::WebInstallApiResult::kInstallCommandFailed,
1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
}
IN_PROC_BROWSER_TEST_F(WebInstallCurrentDocumentBrowserTestManifestErrors,
MissingId) {
GURL current_doc_url = GetInstallableAppURL();
NavigateAndConfigureCurrentDocumentForInstall(current_doc_url);
base::HistogramTester histograms;
ASSERT_TRUE(TryInstallApp());
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kDataError);
histograms.ExpectBucketCount(
kInstallResultUma, web_app::WebInstallApiResult::kNoCustomManifestId, 1);
histograms.ExpectBucketCount(kInstallTypeUma,
web_app::WebInstallApiType::kCurrentDocument, 1);
}
// Implementation-generic tests for bad JavaScript API inputs. This failure
// handling is on the blink side, so there aren't any browser results to verify.
using WebInstallServiceImplBrowserTestBadInput =
WebInstallCurrentDocumentBrowserTest;
IN_PROC_BROWSER_TEST_F(WebInstallServiceImplBrowserTestBadInput,
MissingUserGesture) {
NavigateToValidUrl();
std::string install_url = GetInstallableAppURL().spec();
std::string manifest_id = install_url;
ASSERT_TRUE(TryInstallApp(/*with_gesture=*/false));
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kNotAllowedError);
}
IN_PROC_BROWSER_TEST_F(WebInstallServiceImplBrowserTestBadInput,
OneParam_Undefined) {
NavigateToValidUrl();
const std::string script =
"let install_url;"
"navigator.install(install_url).then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});";
ASSERT_TRUE(ExecJs(web_contents(), script));
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kTypeError);
}
IN_PROC_BROWSER_TEST_F(WebInstallServiceImplBrowserTestBadInput,
OneParam_Null) {
NavigateToValidUrl();
const std::string script =
"let install_url=null;"
"navigator.install(install_url).then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});";
ASSERT_TRUE(ExecJs(web_contents(), script));
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kTypeError);
}
IN_PROC_BROWSER_TEST_F(WebInstallServiceImplBrowserTestBadInput,
OneParam_Number) {
NavigateToValidUrl();
const std::string script =
"let install_url = new Number(1);"
"navigator.install(install_url).then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});";
ASSERT_TRUE(ExecJs(web_contents(), script));
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kTypeError);
}
IN_PROC_BROWSER_TEST_F(WebInstallServiceImplBrowserTestBadInput,
OneParam_Empty) {
NavigateToValidUrl();
const std::string script =
"let install_url='';"
"navigator.install(install_url).then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});";
ASSERT_TRUE(ExecJs(web_contents(), script));
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kTypeError);
}
IN_PROC_BROWSER_TEST_F(WebInstallServiceImplBrowserTestBadInput,
TwoParams_UndefinedInstallUrl) {
NavigateToValidUrl();
const std::string manifest_id = GetInstallableAppURL().spec();
const std::string script =
"let install_url;"
"navigator.install(install_url, '" +
manifest_id +
"').then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});";
ASSERT_TRUE(ExecJs(web_contents(), script));
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kTypeError);
}
IN_PROC_BROWSER_TEST_F(WebInstallServiceImplBrowserTestBadInput,
TwoParams_UndefinedManifestId) {
NavigateToValidUrl();
const std::string install_url = GetInstallableAppURL().spec();
const std::string script =
"let manifest_id;"
"navigator.install('" +
install_url +
"', manifest_id).then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});";
ASSERT_TRUE(ExecJs(web_contents(), script));
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kTypeError);
}
IN_PROC_BROWSER_TEST_F(WebInstallServiceImplBrowserTestBadInput,
TwoParams_EmptyManifestId) {
NavigateToValidUrl();
const std::string install_url = GetInstallableAppURL().spec();
const std::string script =
"let manifest_id = '';"
"navigator.install('" +
install_url +
"', manifest_id).then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});";
ASSERT_TRUE(ExecJs(web_contents(), script));
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kTypeError);
}
IN_PROC_BROWSER_TEST_F(WebInstallServiceImplBrowserTestBadInput,
TwoParams_NullManifestId) {
NavigateToValidUrl();
const std::string install_url = GetInstallableAppURL().spec();
const std::string script =
"let manifest_id = null;"
"navigator.install('" +
install_url +
"', manifest_id).then(result => {"
" webInstallResult = result;"
"}).catch(error => {"
" webInstallError = error;"
"});";
ASSERT_TRUE(ExecJs(web_contents(), script));
EXPECT_FALSE(ResultExists());
EXPECT_TRUE(ErrorExists());
EXPECT_EQ(GetErrorName(), kTypeError);
}
} // namespace web_app