#include "chrome/browser/glic/fre/glic_fre_controller.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/run_until.h"
#include "base/time/time.h"
#include "chrome/browser/glic/fre/glic_fre_page_handler.h"
#include "chrome/browser/glic/glic_pref_names.h"
#include "chrome/browser/glic/public/glic_keyed_service.h"
#include "chrome/browser/glic/test_support/glic_test_environment.h"
#include "chrome/browser/glic/test_support/non_interactive_glic_test.h"
#include "chrome/browser/lifetime/application_lifetime_desktop.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/tabs/tab_enums.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/tabs/public/tab_interface.h"
#include "content/public/test/browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/views/widget/widget.h"
namespace glic {
namespace {
class FakeGlicFrePageHandler : public GlicFrePageHandler {
public:
FakeGlicFrePageHandler(bool is_unified,
content::WebContents* web_contents,
GlicFreController& controller)
: GlicFrePageHandler(is_unified, web_contents, {}) {}
void SimulateAccept() { AcceptFre(); }
};
class GlicFreControllerBrowserTest : public NonInteractiveGlicTest {
public:
GlicFreControllerBrowserTest()
: NonInteractiveGlicTest(
{},
GlicTestEnvironmentConfig{.fre_status =
prefs::FreStatus::kNotStarted}) {}
~GlicFreControllerBrowserTest() override = default;
void SetUpOnMainThread() override {
NonInteractiveGlicTest::SetUpOnMainThread();
}
GlicFreController& glic_fre_controller() {
return glic_service()->fre_controller();
}
tabs::TabInterface* GetTabInterfaceForActiveWebContents(Browser* browser) {
content::WebContents* tab_web_contents =
browser->tab_strip_model()->GetActiveWebContents();
return tabs::TabInterface::MaybeGetFromContents(tab_web_contents);
}
void WaitForFreShow() {
ASSERT_TRUE(base::test::RunUntil([&]() {
return glic_fre_controller().IsShowingDialog();
})) << "FRE dialog should have been shown";
}
void WaitForFreInitialized() {
ASSERT_TRUE(base::test::RunUntil([&]() {
return glic_fre_controller().IsShowingDialogAndStateInitialized();
})) << "FRE dialog should have been initialized";
}
void WaitForFreClose() {
ASSERT_TRUE(base::test::RunUntil([&]() {
return !glic_fre_controller().IsShowingDialog();
})) << "FRE dialog should have been closed";
}
void WaitForGlicPanelShow() {
ASSERT_TRUE(base::test::RunUntil([&]() {
return glic_service()->IsWindowShowing();
})) << "Glic panel should have been shown";
}
void EnsureFreDoesNotShow() {
auto end_time = base::TimeTicks::Now() + base::Milliseconds(500);
ASSERT_TRUE(base::test::RunUntil(
[&]() { return end_time < base::TimeTicks::Now(); }));
ASSERT_FALSE(glic_fre_controller().IsShowingDialog())
<< "FRE dialog should not have been shown";
}
protected:
base::UserActionTester user_action_tester_;
base::HistogramTester histogram_tester_;
};
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
FreDialogShowBlockedByModalUI) {
tabs::TabInterface* tab = GetTabInterfaceForActiveWebContents(browser());
auto scoped_tab_modal_ui = tab->ShowModalUI();
EXPECT_FALSE(glic_fre_controller().CanShowFreDialog(browser()));
scoped_tab_modal_ui.reset();
EXPECT_TRUE(glic_fre_controller().CanShowFreDialog(browser()));
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
FreDialogBlocksOtherModalUI) {
tabs::TabInterface* tab = GetTabInterfaceForActiveWebContents(browser());
EXPECT_TRUE(glic_fre_controller().CanShowFreDialog(browser()));
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
EXPECT_FALSE(tab->CanShowModalUI());
glic_fre_controller().DismissFre(mojom::FreWebUiState::kReady);
EXPECT_TRUE(tab->CanShowModalUI());
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
FreDialogShowBlockedByItself) {
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(0);
EXPECT_TRUE(glic_fre_controller().CanShowFreDialog(browser()));
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
EXPECT_FALSE(glic_fre_controller().CanShowFreDialog(browser()));
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
DismissFreDialogOnActiveTab) {
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(0);
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
glic_fre_controller().DismissFreIfOpenOnActiveTab(browser());
EXPECT_FALSE(glic_fre_controller().IsShowingDialog());
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
ShowFreDialogOnFailedCookieSync) {
glic_test_service().SetResultForFutureCookieSyncInFre(false);
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(0);
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
DontDismissFreDialogOnInactiveTab) {
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(0);
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(1);
glic_fre_controller().DismissFreIfOpenOnActiveTab(browser());
EXPECT_TRUE(glic_fre_controller().IsShowingDialog());
}
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#define MAYBE_FreDialogCloseAndReopenForDifferentTab \
DISABLED_FreDialogCloseAndReopenForDifferentTab
#else
#define MAYBE_FreDialogCloseAndReopenForDifferentTab \
FreDialogCloseAndReopenForDifferentTab
#endif
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
MAYBE_FreDialogCloseAndReopenForDifferentTab) {
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(0);
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
tabs::TabInterface* original_tab =
GetTabInterfaceForActiveWebContents(browser());
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(1);
tabs::TabInterface* new_tab = GetTabInterfaceForActiveWebContents(browser());
EXPECT_TRUE(glic_fre_controller().CanShowFreDialog(browser()));
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
EXPECT_TRUE(original_tab->CanShowModalUI());
EXPECT_FALSE(new_tab->CanShowModalUI());
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
InactiveTabFreDialogNotClosedWhenBlockedByModalUI) {
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(0);
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
tabs::TabInterface* original_tab =
GetTabInterfaceForActiveWebContents(browser());
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(1);
tabs::TabInterface* new_tab = GetTabInterfaceForActiveWebContents(browser());
auto scoped_tab_modal_ui = new_tab->ShowModalUI();
EXPECT_FALSE(glic_fre_controller().CanShowFreDialog(browser()));
glic_fre_controller().DismissFreIfOpenOnActiveTab(browser());
WaitForFreShow();
EXPECT_FALSE(original_tab->CanShowModalUI());
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
FreControllerWithWebContentsDestruction) {
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
browser()->tab_strip_model()->ActivateTabAt(1);
browser()->tab_strip_model()->CloseWebContentsAt(
0, TabCloseTypes::CLOSE_USER_GESTURE);
WaitForFreClose();
histogram_tester_.ExpectUniqueSample(
"Glic.Fre.WidgetClosedReason2",
glic::GlicFreWidgetClosedReason::kHostTabClosed,
1);
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest, FreAcceptance) {
if (base::FeatureList::IsEnabled(features::kGlicMultiInstance)) {
GTEST_SKIP() << "Skipping for kGlicMultiInstance";
}
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
glic_fre_controller().AcceptFre(nullptr);
EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.Accept"), 1);
WaitForFreClose();
WaitForGlicPanelShow();
histogram_tester_.ExpectUniqueSample(
"Glic.Fre.WidgetClosedReason2",
glic::GlicFreWidgetClosedReason::kAcceptButtonClicked,
1);
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest, DoNotCrashOnBrowserClose) {
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
chrome::CloseAllBrowsers();
histogram_tester_.ExpectUniqueSample(
"Glic.Fre.WidgetClosedReason2",
glic::GlicFreWidgetClosedReason::kHostTabClosed,
1);
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
NoPanelClosedActionOnBrowserCloseBeforeShow) {
chrome::CloseAllBrowsers();
EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.ErrorPanelClosed"), 0);
EXPECT_EQ(
user_action_tester_.GetActionCount("Glic.Fre.DisabledByAdminPanelClosed"),
0);
EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.OfflinePanelClosed"),
0);
EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.LoadingPanelClosed"),
0);
EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.ReadyPanelClosed"), 0);
EXPECT_EQ(
user_action_tester_.GetActionCount("Glic.Fre.UninitializedPanelClosed"),
0);
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
PanelClosedActionOnBrowserCloseAfterShow) {
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreInitialized();
chrome::CloseAllBrowsers();
EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.LoadingPanelClosed"),
1);
histogram_tester_.ExpectUniqueSample(
"Glic.Fre.WidgetClosedReason2",
glic::GlicFreWidgetClosedReason::kHostTabClosed,
1);
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest, FreRejection) {
glic_fre_controller().ShowFreDialog(
browser(), mojom::InvocationSource::kTopChromeButton);
WaitForFreShow();
glic_fre_controller().RejectFre();
EXPECT_EQ(user_action_tester_.GetActionCount("Glic.Fre.NoThanks"), 1);
WaitForFreClose();
histogram_tester_.ExpectUniqueSample(
"Glic.Fre.WidgetClosedReason2",
glic::GlicFreWidgetClosedReason::kCancelButtonClicked,
1);
}
IN_PROC_BROWSER_TEST_F(GlicFreControllerBrowserTest,
FreAcceptanceClosesOtherHandlers) {
chrome::AddTabAt(browser(), GURL("about:blank"), -1, true);
content::WebContents* wc1 = browser()->tab_strip_model()->GetWebContentsAt(0);
content::WebContents* wc2 = browser()->tab_strip_model()->GetWebContentsAt(1);
glic_service()->ToggleUI(browser(), true,
mojom::InvocationSource::kTopChromeButton);
FakeGlicFrePageHandler handler1(true, wc1,
glic_fre_controller());
glic_service()->ToggleUI(browser(), true,
mojom::InvocationSource::kTopChromeButton);
FakeGlicFrePageHandler handler2(true, wc2,
glic_fre_controller());
handler1.SimulateAccept();
histogram_tester_.ExpectTotalCount("Glic.UnifiedFre.TotalTime.Accepted", 1);
histogram_tester_.ExpectTotalCount(
"Glic.UnifiedFre.TotalTime.AcceptedByOtherInstance", 1);
histogram_tester_.ExpectTotalCount("Glic.Fre.TotalTime.Dismissed", 0);
histogram_tester_.ExpectTotalCount("Glic.UnifiedFre.TotalTime.Dismissed", 0);
}
}
}