blob: ee8fd3113aaf103163d83b7750684b115f843488 [file] [log] [blame]
// Copyright 2016 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 <vector>
#include "base/command_line.h"
#include "base/run_loop.h"
#include "base/test/histogram_tester.h"
#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/banners/app_banner_manager.h"
#include "chrome/browser/banners/app_banner_metrics.h"
#include "chrome/browser/banners/app_banner_settings_helper.h"
#include "chrome/browser/engagement/site_engagement_service.h"
#include "chrome/browser/installable/installable_logging.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
namespace banners {
// Browser tests for web app banners.
// NOTE: this test relies on service workers; failures and flakiness may be due
// to changes in SW code.
class AppBannerManagerTest : public AppBannerManager {
public:
explicit AppBannerManagerTest(content::WebContents* web_contents)
: AppBannerManager(web_contents) {}
~AppBannerManagerTest() override {}
bool will_show() { return will_show_.get() && *will_show_; }
bool is_active() { return AppBannerManager::is_active(); }
bool need_to_log_status() { return need_to_log_status_; }
void Prepare(base::Closure quit_closure) {
will_show_.reset(nullptr);
quit_closure_ = quit_closure;
}
protected:
// All calls to RequestAppBanner should terminate in one of Stop() (not
// showing banner) or ShowBanner(). Override those two methods to capture test
// status.
void Stop() override {
AppBannerManager::Stop();
ASSERT_FALSE(will_show_.get());
will_show_.reset(new bool(false));
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
}
void ShowBanner() override {
// Fake the call to ReportStatus here - this is usually called in
// platform-specific code which is not exposed here.
ReportStatus(nullptr, SHOWING_WEB_APP_BANNER);
RecordDidShowBanner("AppBanner.WebApp.Shown");
ASSERT_FALSE(will_show_.get());
will_show_.reset(new bool(true));
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, quit_closure_);
}
private:
bool IsDebugMode() const override { return false; }
base::Closure quit_closure_;
std::unique_ptr<bool> will_show_;
};
class AppBannerManagerBrowserTest : public InProcessBrowserTest {
public:
void SetUpOnMainThread() override {
AppBannerSettingsHelper::SetTotalEngagementToTrigger(10);
ASSERT_TRUE(embedded_test_server()->Start());
InProcessBrowserTest::SetUpOnMainThread();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
// Make sure app banners are disabled in the browser, otherwise they will
// interfere with the test.
command_line->AppendSwitch(switches::kDisableAddToShelf);
}
protected:
// Returns a test server URL to a page controlled by a service worker with
// |manifest_url| injected as the manifest tag.
std::string GetURLOfPageWithServiceWorkerAndManifest(
const std::string& manifest_url) {
return "/banners/manifest_test_page.html?manifest=" +
embedded_test_server()->GetURL(manifest_url).spec();
}
void RunBannerTest(Browser* browser,
const std::string& url,
const std::vector<double>& engagement_scores,
InstallableStatusCode expected_code_for_histogram,
bool expected_to_show) {
base::HistogramTester histograms;
GURL test_url = embedded_test_server()->GetURL(url);
content::WebContents* web_contents =
browser->tab_strip_model()->GetActiveWebContents();
std::unique_ptr<AppBannerManagerTest> manager(
new AppBannerManagerTest(web_contents));
// Loop through the vector of engagement scores. We only expect the banner
// pipeline to trigger on the last one; otherwise, nothing is expected to
// happen.
int iterations = 0;
SiteEngagementService* service =
SiteEngagementService::Get(browser->profile());
for (double engagement : engagement_scores) {
if (iterations > 0) {
ui_test_utils::NavigateToURL(browser, test_url);
EXPECT_EQ(false, manager->will_show());
EXPECT_FALSE(manager->is_active());
histograms.ExpectTotalCount(banners::kMinutesHistogram, 0);
histograms.ExpectTotalCount(banners::kInstallableStatusCodeHistogram,
0);
}
service->ResetScoreForURL(test_url, engagement);
++iterations;
}
// On the final loop, we expect the banner pipeline to trigger - the
// navigation should generate the final engagement to show the banner. Spin
// the run loop, which should be quit by either Stop() or ShowBanner().
base::RunLoop run_loop;
manager->Prepare(run_loop.QuitClosure());
ui_test_utils::NavigateToURL(browser, test_url);
run_loop.Run();
EXPECT_EQ(expected_to_show, manager->will_show());
EXPECT_FALSE(manager->is_active());
// Navigate to ensure the InstallableStatusCodeHistogram is logged.
ui_test_utils::NavigateToURL(browser, GURL("about:blank"));
// If in incognito, ensure that nothing is recorded.
// If showing the banner, ensure that the minutes histogram is recorded.
if (browser->profile()->IsOffTheRecord()) {
histograms.ExpectTotalCount(banners::kMinutesHistogram, 0);
histograms.ExpectTotalCount(banners::kInstallableStatusCodeHistogram, 0);
} else {
histograms.ExpectTotalCount(banners::kMinutesHistogram,
(manager->will_show() ? 1 : 0));
histograms.ExpectUniqueSample(banners::kInstallableStatusCodeHistogram,
expected_code_for_histogram, 1);
EXPECT_FALSE(manager->need_to_log_status());
}
}
};
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, WebAppBannerCreated) {
std::vector<double> engagement_scores{0, 10};
RunBannerTest(browser(), "/banners/manifest_test_page.html",
engagement_scores, SHOWING_WEB_APP_BANNER, true);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest,
WebAppBannerCreatedImmediately) {
std::vector<double> engagement_scores{10};
RunBannerTest(browser(), "/banners/manifest_test_page.html",
engagement_scores, SHOWING_WEB_APP_BANNER, true);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest,
WebAppBannerCreatedAfterSeveralVisits) {
std::vector<double> engagement_scores{0, 1, 2, 3, 4, 5, 10};
RunBannerTest(browser(), "/banners/manifest_test_page.html",
engagement_scores, SHOWING_WEB_APP_BANNER, true);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest,
WebAppBannerNotSeenAfterShowing) {
std::vector<double> engagement_scores{0, 10};
RunBannerTest(browser(), "/banners/manifest_test_page.html",
engagement_scores, SHOWING_WEB_APP_BANNER, true);
AppBannerManager::SetTimeDeltaForTesting(1);
RunBannerTest(browser(), "/banners/manifest_test_page.html",
engagement_scores, PREVIOUSLY_IGNORED, false);
AppBannerManager::SetTimeDeltaForTesting(13);
RunBannerTest(browser(), "/banners/manifest_test_page.html",
engagement_scores, PREVIOUSLY_IGNORED, false);
AppBannerManager::SetTimeDeltaForTesting(14);
RunBannerTest(browser(), "/banners/manifest_test_page.html",
engagement_scores, SHOWING_WEB_APP_BANNER, true);
AppBannerSettingsHelper::SetDaysAfterDismissAndIgnoreToTrigger(90, 2);
AppBannerManager::SetTimeDeltaForTesting(16);
RunBannerTest(browser(), "/banners/manifest_test_page.html",
engagement_scores, SHOWING_WEB_APP_BANNER, true);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest,
WebAppBannerNoTypeInManifest) {
std::vector<double> engagement_scores{0, 10};
RunBannerTest(browser(), GetURLOfPageWithServiceWorkerAndManifest(
"/banners/manifest_no_type.json"),
engagement_scores, SHOWING_WEB_APP_BANNER, true);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest,
WebAppBannerNoTypeInManifestCapsExtension) {
std::vector<double> engagement_scores{0, 10};
RunBannerTest(browser(), GetURLOfPageWithServiceWorkerAndManifest(
"/banners/manifest_no_type_caps.json"),
engagement_scores, SHOWING_WEB_APP_BANNER, true);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, NoManifest) {
std::vector<double> engagement_scores{10};
RunBannerTest(browser(), "/banners/no_manifest_test_page.html",
engagement_scores, NO_MANIFEST, false);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, MissingManifest) {
std::vector<double> engagement_scores{10};
RunBannerTest(browser(), GetURLOfPageWithServiceWorkerAndManifest(
"/banners/manifest_missing.json"),
engagement_scores, MANIFEST_EMPTY, false);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, CancelBannerDirect) {
std::vector<double> engagement_scores{10};
RunBannerTest(browser(), "/banners/cancel_test_page.html", engagement_scores,
RENDERER_CANCELLED, false);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, PromptBanner) {
std::vector<double> engagement_scores{0, 5, 10};
RunBannerTest(browser(), "/banners/prompt_test_page.html", engagement_scores,
SHOWING_WEB_APP_BANNER, true);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, PromptBannerInHandler) {
std::vector<double> engagement_scores{0, 2, 5, 10};
RunBannerTest(browser(), "/banners/prompt_in_handler_test_page.html",
engagement_scores, SHOWING_WEB_APP_BANNER, true);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, WebAppBannerInIFrame) {
std::vector<double> engagement_scores{10};
RunBannerTest(browser(), "/banners/iframe_test_page.html", engagement_scores,
NO_MANIFEST, false);
}
IN_PROC_BROWSER_TEST_F(AppBannerManagerBrowserTest, DoesNotShowInIncognito) {
std::vector<double> engagement_scores{10};
Browser* incognito_browser =
OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
RunBannerTest(incognito_browser, "/banners/manifest_test_page.html",
engagement_scores, IN_INCOGNITO, false);
}
} // namespace banners