#include <math.h>
#include <algorithm>
#include <deque>
#include <memory>
#include <ranges>
#include <string>
#include <string_view>
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/containers/to_vector.h"
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/json/json_writer.h"
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task/sequenced_task_runner.h"
#include "base/test/bind.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/metrics/user_action_tester.h"
#include "base/test/run_until.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/scoped_logging_settings.h"
#include "base/test/test_future.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "base/types/cxx23_to_underlying.h"
#include "base/values.h"
#include "base/version_info/version_info.h"
#include "build/build_config.h"
#include "chrome/browser/actor/actor_policy_checker.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/contextual_cueing/contextual_cueing_features.h"
#include "chrome/browser/contextual_cueing/contextual_cueing_service.h"
#include "chrome/browser/contextual_cueing/contextual_cueing_service_factory.h"
#include "chrome/browser/contextual_cueing/mock_contextual_cueing_service.h"
#include "chrome/browser/enterprise/browser_management/browser_management_service.h"
#include "chrome/browser/enterprise/browser_management/management_service_factory.h"
#include "chrome/browser/glic/glic_metrics.h"
#include "chrome/browser/glic/glic_pref_names.h"
#include "chrome/browser/glic/glic_profile_manager.h"
#include "chrome/browser/glic/host/context/glic_tab_data.h"
#include "chrome/browser/glic/host/glic.mojom.h"
#include "chrome/browser/glic/host/glic_features.mojom.h"
#include "chrome/browser/glic/host/glic_page_handler.h"
#include "chrome/browser/glic/host/glic_region_capture_controller.h"
#include "chrome/browser/glic/host/host.h"
#include "chrome/browser/glic/public/glic_keyed_service.h"
#include "chrome/browser/glic/public/glic_keyed_service_factory.h"
#include "chrome/browser/glic/service/metrics/glic_instance_coordinator_metrics.h"
#include "chrome/browser/glic/service/metrics/glic_instance_helper_metrics.h"
#include "chrome/browser/glic/test_support/glic_api_test.h"
#include "chrome/browser/glic/test_support/glic_test_util.h"
#include "chrome/browser/glic/test_support/interactive_test_util.h"
#include "chrome/browser/glic/test_support/non_interactive_glic_test.h"
#include "chrome/browser/glic/widget/glic_window_controller.h"
#include "chrome/browser/media/audio_ducker.h"
#include "chrome/browser/permissions/system/mock_platform_handle.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/resource_coordinator/lifecycle_unit_state.mojom.h"
#include "chrome/browser/resource_coordinator/tab_lifecycle_unit_external.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/passwords/ui_utils.h"
#include "chrome/browser/ui/views/side_panel/glic/glic_side_panel_coordinator.h"
#include "chrome/common/channel_info.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/test/interaction/interactive_browser_test.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/metrics/metrics_service.h"
#include "components/optimization_guide/content/browser/page_content_proto_provider.h"
#include "components/policy/core/browser/browser_policy_connector.h"
#include "components/policy/core/common/management/management_service.h"
#include "components/policy/core/common/management/scoped_management_service_override_for_testing.h"
#include "components/policy/core/common/mock_configuration_policy_provider.h"
#include "components/policy/policy_constants.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/tabs/public/tab_interface.h"
#include "components/variations/synthetic_trial_registry.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "mojo/public/cpp/base/big_buffer.h"
#include "net/dns/mock_host_resolver.h"
#include "pdf/buildflags.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/screen.h"
#if !BUILDFLAG(IS_CHROMEOS)
#include "chrome/browser/ui/profiles/profile_picker.h"
#endif
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
defined(MEMORY_SANITIZER)
#define SLOW_BINARY
#endif
#define SKIP_TEST_FOR_MULTI_INSTANCE() \
do { \
if (GetParam().multi_instance) { \
GTEST_SKIP() << "Not supported in multi-instance mode"; \
return; \
} \
} while (0)
#define TODO_SKIP_BROKEN_MULTI_INSTANCE_TEST() SKIP_TEST_FOR_MULTI_INSTANCE()
#if BUILDFLAG(IS_CHROMEOS)
#define MAYBE(test_name) DISABLED_##test_name
#else
#define MAYBE(test_name) test_name
#endif
namespace glic {
namespace {
using ::base::Bucket;
using ::base::BucketsAre;
using ::base::test::RunOnceCallbackRepeatedly;
using ::testing::_;
using ::testing::Contains;
using ::testing::IsEmpty;
using ::testing::Pair;
using ::testing::UnorderedElementsAre;
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kFirstTab);
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSecondTab);
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kThirdTab);
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kSettingsTab);
std::vector<std::string> GetTestSuiteNames() {
return {
"GlicApiTest",
"GlicApiTestWithOneTab",
"GlicApiTestWithFastTimeout",
"GlicApiTestSystemSettingsTest",
"GlicApiTestWithOneTabAndContextualCueing",
"GlicApiTestWithOneTabAndPreloading",
"GlicApiTestUserStatusCheckTest",
"GlicApiTestWithOneTabMoreDebounceDelay",
"GlicGetHostCapabilityApiTest",
"GlicApiTestWithDefaultTabContextDisabled",
"GlicApiTestWithDefaultTabContextEnabled",
"GlicApiTestWithMqlsIdGetterEnabled",
"GlicApiTestWithMqlsIdGetterDisabled",
"GlicApiTestRuntimeFeatureOff",
"GlicApiTestWithWebActuationSettingDisabled",
"GlicApiTestWithWebActuationSettingEnabled",
"GlicApiTestWithGeminiActOnWebPolicy",
"GlicApiTestHibernateAllOnMemoryPressure",
"GlicApiTestHibernateAllAggressiveOnMemoryPressure",
"GlicApiTestHibernateOnMemoryUsage",
};
}
struct TestParams {
bool multi_instance = false;
bool enable_scroll_to_pdf = false;
};
class WithTestParams : public testing::WithParamInterface<TestParams> {
public:
WithTestParams() {
if (GetParam().multi_instance) {
test_param_features_.InitAndEnableFeature(features::kGlicMultiInstance);
} else {
test_param_features_.InitAndDisableFeature(features::kGlicMultiInstance);
}
}
static std::string PrintTestVariant(
const ::testing::TestParamInfo<TestParams>& info) {
std::vector<std::string> result;
if (info.param.enable_scroll_to_pdf) {
result.push_back("EnableScrollToPdf");
}
if (info.param.multi_instance) {
result.push_back("MultiInst");
}
if (result.empty()) {
return "Default";
}
return base::JoinString(result, "_");
}
private:
base::test::ScopedFeatureList test_param_features_;
};
class GlicApiTest : public NonInteractiveGlicApiTest, public WithTestParams {
public:
GlicApiTest() : NonInteractiveGlicApiTest("./glic_api_browsertest.js") {
features_.InitWithFeaturesAndParameters(
{
{features::kGlicScrollTo, {}},
{features::kGlicClosedCaptioning, {}},
{features::kGlicApiActivationGating, {}},
{mojom::features::kGlicMultiTab, {}},
{features::kGlicWebActuationSetting, {}},
{features::kGlicCaptureRegion, {}},
{features::kGlicPopupWindowsEnabled, {}},
{features::kGlicUserStatusCheck,
{{features::kGlicUserStatusRefreshApi.name, "true"},
{features::kGlicUserStatusThrottleInterval.name, "2s"}}},
{features::kGlicOpenPasswordManagerSettingsPageApi, {}},
},
{
features::kGlicWarming,
});
SetUseElementIdentifiers(false);
}
void SetUpOnMainThread() override {
NonInteractiveGlicApiTest::SetUpOnMainThread();
histogram_tester = std::make_unique<base::HistogramTester>();
user_action_tester = std::make_unique<base::UserActionTester>();
}
void SetUpCommandLine(base::CommandLine* command_line) override {
vmodule_switches_.InitWithSwitches("glic_focused_browser_manager=1");
NonInteractiveGlicApiTest::SetUpCommandLine(command_line);
}
void NavigateTabAndOpenGlic(bool open_floating = false) {
if (open_floating) {
TrackFloatingGlicInstance();
}
RunTestSequence(
InstrumentTab(kFirstTab), NavigateWebContents(kFirstTab, page_url()),
Log("Opening Glic window"),
!open_floating
? OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents)
: OpenGlicFloatingWindow(GlicInstrumentMode::kHostAndContents),
Log("Done opening glic window"));
}
void NavigateTabAndOpenGlicFloating() { NavigateTabAndOpenGlic(true); }
GURL page_url() {
return InProcessBrowserTest::embedded_test_server()->GetURL(
"/glic/browser_tests/test.html");
}
GlicInstanceImpl* OpenGlicInNewTabAndGetInstance(
int index,
ui::ElementIdentifier tab_id) {
EXPECT_TRUE(AddTabAtIndex(index, page_url(), ui::PAGE_TRANSITION_TYPED));
browser()->tab_strip_model()->ActivateTabAt(index);
TrackGlicInstanceWithTabIndex(index);
RunTestSequence(
InstrumentTab(tab_id),
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone),
RegisterConversation("instance_" + base::NumberToString(index)));
GlicInstanceImpl* instance = GetGlicInstanceImpl();
return instance;
}
std::unique_ptr<base::HistogramTester> histogram_tester;
std::unique_ptr<base::UserActionTester> user_action_tester;
protected:
GlicRegionCaptureController& region_capture_controller() {
return GetService()->region_capture_controller();
}
base::test::ScopedFeatureList features_;
logging::ScopedVmoduleSwitches vmodule_switches_;
};
class GlicApiTestWithOneTab : public GlicApiTest {
public:
GlicApiTestWithOneTab() {
scoped_feature_list_.InitWithFeatures(
{features::kGlicClosedCaptioning},
{features::kGlicDefaultTabContextSetting});
}
void SetUpOnMainThread() override {
GlicApiTest::SetUpOnMainThread();
NavigateTabAndOpenGlic();
}
std::string GetDocumentIdForTab(ui::ElementIdentifier tab_id) {
ui::TrackedElement* const element =
ui::ElementTracker::GetElementTracker()->GetElementInAnyContext(tab_id);
CHECK(element);
content::RenderFrameHost* rfh = AsInstrumentedWebContents(element)
->web_contents()
->GetPrimaryMainFrame();
return optimization_guide::DocumentIdentifierUserData::
GetDocumentIdentifier(rfh->GetGlobalFrameToken())
.value();
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
class GlicApiTestWithDefaultTabContextEnabled : public GlicApiTestWithOneTab {
public:
GlicApiTestWithDefaultTabContextEnabled() {
feature_list_.InitWithFeatures({features::kGlicDefaultTabContextSetting},
{});
}
void SetUpOnMainThread() override { GlicApiTest::SetUpOnMainThread(); }
private:
base::test::ScopedFeatureList feature_list_;
};
class GlicApiTestWithDefaultTabContextDisabled : public GlicApiTestWithOneTab {
public:
GlicApiTestWithDefaultTabContextDisabled() {
feature_list_.InitWithFeatures({},
{features::kGlicDefaultTabContextSetting});
}
private:
base::test::ScopedFeatureList feature_list_;
};
class GlicApiTestWithWebActuationSettingEnabled : public GlicApiTestWithOneTab {
public:
GlicApiTestWithWebActuationSettingEnabled() {
feature_list_.InitWithFeatures({features::kGlicWebActuationSetting}, {});
}
private:
base::test::ScopedFeatureList feature_list_;
};
class GlicApiTestWithWebActuationSettingDisabled
: public GlicApiTestWithOneTab {
public:
GlicApiTestWithWebActuationSettingDisabled() {
feature_list_.InitWithFeatures({}, {features::kGlicWebActuationSetting});
}
private:
base::test::ScopedFeatureList feature_list_;
};
class GlicApiTestWithMqlsIdGetterEnabled : public GlicApiTestWithOneTab {
public:
GlicApiTestWithMqlsIdGetterEnabled() {
scoped_feature_list_.InitWithFeatures(
{mojom::features::kGlicAppendModelQualityClientId},
{});
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
class GlicApiTestWithMqlsIdGetterDisabled : public GlicApiTestWithOneTab {
public:
GlicApiTestWithMqlsIdGetterDisabled() {
scoped_feature_list_.InitWithFeatures(
{},
{mojom::features::kGlicAppendModelQualityClientId});
}
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
class GlicApiTestWithOneTabAndPreloading : public GlicApiTestWithOneTab {
public:
GlicApiTestWithOneTabAndPreloading() {
features_.InitWithFeaturesAndParameters(
{{features::kGlic,
{
{"glic-default-hotkey", "Ctrl+G"},
{features::kGlicPreLoadingTimeMs.name, "20"},
{features::kGlicMinLoadingTimeMs.name, "40"},
}},
{features::kGlicApiActivationGating, {}},
{features::kGlicWarming,
{{features::kGlicWarmingDelayMs.name, "0"},
{features::kGlicWarmingJitterMs.name, "0"}}}},
{});
GlicProfileManager::ForceMemoryPressureForTesting(
base::MEMORY_PRESSURE_LEVEL_CRITICAL);
GlicProfileManager::ForceConnectionTypeForTesting(
network::mojom::ConnectionType::CONNECTION_ETHERNET);
}
auto CreateAndWarmGlic() {
return Do([this] { GetService()->TryPreload(); });
}
auto ResetMemoryPressure() {
return Do([]() {
GlicProfileManager::ForceMemoryPressureForTesting(
base::MEMORY_PRESSURE_LEVEL_NONE);
});
}
void SetUpOnMainThread() override {
GlicApiTest::SetUpOnMainThread();
histogram_tester = std::make_unique<base::HistogramTester>();
RunTestSequence(InstrumentTab(kFirstTab),
NavigateWebContents(kFirstTab, page_url()));
RunTestSequence(WaitForShow(kGlicButtonElementId), ResetMemoryPressure(),
ObserveState(glic::test::internal::kWebUiState, GetHost()),
CreateAndWarmGlic(),
WaitForState(glic::test::internal::kWebUiState,
mojom::WebUiState::kReady),
CheckControllerShowing(false));
}
void TearDown() override {
GlicApiTestWithOneTab::TearDown();
GlicProfileManager::ForceMemoryPressureForTesting(std::nullopt);
GlicProfileManager::ForceConnectionTypeForTesting(std::nullopt);
}
private:
base::test::ScopedFeatureList features_;
};
class GlicApiTestWithOneTabAndContextualCueing : public GlicApiTestWithOneTab {
public:
GlicApiTestWithOneTabAndContextualCueing() {
contextual_cueing_features_.InitWithFeaturesAndParameters(
{{features::kGlic,
{
{"glic-default-hotkey", "Ctrl+G"},
{features::kGlicPreLoadingTimeMs.name, "20"},
{features::kGlicMinLoadingTimeMs.name, "40"},
}},
{features::kGlicApiActivationGating, {}},
{contextual_cueing::kGlicZeroStateSuggestions, {}},
{mojom::features::kZeroStateSuggestionsV2, {}}},
{
features::kGlicWarming,
});
}
void SetUpBrowserContextKeyedServices(
content::BrowserContext* browser_context) override {
mock_cueing_service_ = static_cast<
testing::NiceMock<contextual_cueing::MockContextualCueingService>*>(
contextual_cueing::ContextualCueingServiceFactory::GetInstance()
->SetTestingFactoryAndUse(
browser_context,
base::BindRepeating([](content::BrowserContext* context)
-> std::unique_ptr<KeyedService> {
return std::make_unique<testing::NiceMock<
contextual_cueing::MockContextualCueingService>>();
})));
GlicApiTestWithOneTab::SetUpBrowserContextKeyedServices(browser_context);
}
void TearDownOnMainThread() override {
mock_cueing_service_ = nullptr;
GlicApiTestWithOneTab::TearDownOnMainThread();
}
contextual_cueing::MockContextualCueingService* mock_cueing_service() {
return mock_cueing_service_.get();
}
private:
base::CallbackListSubscription active_instance_subscription_;
raw_ptr<testing::NiceMock<contextual_cueing::MockContextualCueingService>>
mock_cueing_service_;
base::test::ScopedFeatureList contextual_cueing_features_;
};
class GlicApiTestWithFastTimeout : public GlicApiTest {
public:
GlicApiTestWithFastTimeout() {
features2_.InitWithFeaturesAndParameters(
{{
features::kGlic,
{
#if defined(SLOW_BINARY)
{features::kGlicMaxLoadingTimeMs.name, "6000"},
#else
{features::kGlicMaxLoadingTimeMs.name, "3000"},
#endif
},
}},
{});
}
private:
base::test::ScopedFeatureList features2_;
};
class GlicApiTestWithGeminiActOnWebPolicy : public GlicApiTestWithOneTab {
public:
GlicApiTestWithGeminiActOnWebPolicy() {
scoped_feature_list_.InitAndEnableFeatureWithParameters(
features::kGlicActor,
{{features::kGlicActorEnterprisePrefDefault.name,
features::kGlicActorEnterprisePrefDefault.GetName(
features::GlicActorEnterprisePrefDefault::kDisabledByDefault)}});
}
~GlicApiTestWithGeminiActOnWebPolicy() override = default;
void SetUpInProcessBrowserTestFixture() override {
GlicApiTestWithOneTab::SetUpInProcessBrowserTestFixture();
policy_provider_.SetDefaultReturns(
true,
true);
policy::BrowserPolicyConnector::SetPolicyProviderForTesting(
&policy_provider_);
}
void SetUpOnMainThread() override {
GlicApiTestWithOneTab::SetUpOnMainThread();
policy_provider_.SetupPolicyServiceForPolicyUpdates(
browser()->profile()->GetProfilePolicyConnector()->policy_service());
actor::ActorKeyedService::Get(browser()->profile())
->GetPolicyChecker()
.set_account_eligible_for_actuation_for_testing(true);
}
void TearDownOnMainThread() override {
policy_provider_.SetupPolicyServiceForPolicyUpdates(nullptr);
GlicApiTestWithOneTab::TearDownOnMainThread();
}
void UpdateGeminiActOnWebPolicy(
glic::prefs::GlicActuationOnWebPolicyState value) {
policy::PolicyMap policies;
policies.Set(policy::key::kGeminiActOnWebSettings,
policy::POLICY_LEVEL_MANDATORY, policy::POLICY_SCOPE_USER,
policy::POLICY_SOURCE_ENTERPRISE_DEFAULT,
base::Value(base::to_underlying(value)), nullptr);
policy_provider_.UpdateChromePolicy(policies);
}
private:
::testing::NiceMock<policy::MockConfigurationPolicyProvider> policy_provider_;
base::test::ScopedFeatureList scoped_feature_list_;
};
class GlicApiTestHibernateAllOnMemoryPressure : public GlicApiTest {
public:
GlicApiTestHibernateAllOnMemoryPressure() {
feature_list_.InitAndEnableFeatureWithParameters(
kGlicHibernateAllOnMemoryPressure, {{"aggressive", "false"}});
}
private:
base::test::ScopedFeatureList feature_list_;
};
class GlicApiTestHibernateAllAggressiveOnMemoryPressure : public GlicApiTest {
public:
GlicApiTestHibernateAllAggressiveOnMemoryPressure() {
feature_list_.InitAndEnableFeatureWithParameters(
kGlicHibernateAllOnMemoryPressure, {{"aggressive", "true"}});
}
private:
base::test::ScopedFeatureList feature_list_;
};
class GlicApiTestHibernateOnMemoryUsage : public GlicApiTest {
public:
GlicApiTestHibernateOnMemoryUsage() {
feature_list_.InitAndEnableFeatureWithParameters(
kGlicHibernateOnMemoryUsage,
{{"threshold_mb", "1"}, {"polling_interval", "500ms"}});
}
private:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testDoNothing) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testFailureForCapturedApiTestError) {
const std::string expected_failure =
"Failed at step #1 (single or first) due to (captured error): "
"Error: Non-throwing test error";
ExecuteJsTest(
{.should_fail = true, .should_fail_with_error = expected_failure});
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, MAYBE(testAllTestsAreRegistered)) {
AssertAllTestsRegistered(GetTestSuiteNames());
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testLoadWhileWindowClosed) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone),
RegisterConversation("test-id"), CloseGlic());
ExecuteJsTest();
WaitForWebUiState(mojom::WebUiState::kReady);
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testInitializeFailsWindowClosed) {
base::HistogramTester histogram_tester;
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone),
RegisterConversation("test-id"), CloseGlic());
ExecuteJsTest();
WaitForWebUiState(mojom::WebUiState::kError);
histogram_tester.ExpectUniqueSample(
"Glic.Host.WebClientState.OnDestroy",
2 , 1);
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testInitializeFailsWindowOpen) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
ExecuteJsTest({
.params = base::Value(base::Value::Dict().Set("failWith", "error")),
});
WaitForWebUiState(mojom::WebUiState::kError);
RunTestSequence(CloseGlic(), OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kNone));
ExecuteJsTest({
.params = base::Value(base::Value::Dict().Set("failWith", "none")),
});
WaitForWebUiState(mojom::WebUiState::kReady);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithDefaultTabContextDisabled,
testDefaultTabContextApiIsUndefinedWhenFeatureDisabled) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithDefaultTabContextEnabled,
testGetDefaultTabContextPermissionState) {
NavigateTabAndOpenGlic();
ExecuteJsTest();
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kGlicDefaultTabContextEnabled, false);
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithDefaultTabContextEnabled, testPinOnBind) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Pin on bind is a multi-instance behavior";
}
NavigateTabAndOpenGlic();
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithDefaultTabContextEnabled,
testNoPinOnBindWhenSettingOff) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Pin on bind is a multi-instance behavior";
}
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kGlicDefaultTabContextEnabled, false);
NavigateTabAndOpenGlic();
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithWebActuationSettingDisabled,
testWebActuationSettingIsUndefinedWhenFeatureDisabled) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithWebActuationSettingEnabled,
testGetWebActuationSetting) {
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kGlicUserEnabledActuationOnWeb, false);
ExecuteJsTest();
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kGlicUserEnabledActuationOnWeb, true);
ContinueJsTest();
}
#if defined(SLOW_BINARY)
#define MAYBE_testReload DISABLED_testReload
#else
#define MAYBE_testReload testReload
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTest, MAYBE_testReload) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
WebUIStateListener listener(GetHost());
ExecuteJsTest({
.params = base::Value(
base::Value::Dict().Set("failWith", "reloadAfterInitialize")),
});
listener.WaitForWebUiState(mojom::WebUiState::kReady);
listener.WaitForWebUiState(mojom::WebUiState::kBeginLoad);
ExecuteJsTest({
.params = base::Value(base::Value::Dict().Set("failWith", "none")),
});
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testReloadWebUi) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
WebUIStateListener listener(GetHost());
ExecuteJsTest();
listener.WaitForWebUiState(mojom::WebUiState::kReady);
ReloadGlicWebui();
listener.WaitForWebUiState(mojom::WebUiState::kUninitialized);
ExecuteJsTest();
ASSERT_TRUE(base::test::RunUntil(
[&]() { return GetHost()->GetPageHandlersForTesting().size() == 1; }));
ASSERT_TRUE(GetHost()->GetPrimaryPageHandlerForTesting());
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testSorryPageBeforeInitialize) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
WebUIStateListener listener(GetHost());
ExecuteJsTest({
.params = base::Value(base::Value::Dict().Set(
"failWith", "navigateToSorryPageBeforeInitialize")),
});
listener.WaitForWebUiState(mojom::WebUiState::kGuestError);
RunTestSequence(CheckControllerShowing(true));
ASSERT_EQ(true,
content::EvalJs(FindGlicGuestMainFrame(),
std::string("(()=>{window.location = '") +
GetGuestURL().spec() + "'; return true;})()"));
listener.WaitForWebUiState(mojom::WebUiState::kBeginLoad);
ExecuteJsTest({
.params = base::Value(base::Value::Dict().Set("failWith", "none")),
});
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testSorryPageAfterInitialize) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
WebUIStateListener listener(GetHost());
ExecuteJsTest({
.params = base::Value(base::Value::Dict().Set(
"failWith", "navigateToSorryPageAfterInitialize")),
});
listener.WaitForWebUiState(mojom::WebUiState::kGuestError);
RunTestSequence(CheckControllerShowing(true));
ASSERT_EQ(true,
content::EvalJs(FindGlicGuestMainFrame(),
std::string("(()=>{window.location = '") +
GetGuestURL().spec() + "'; return true;})()"));
listener.WaitForWebUiState(mojom::WebUiState::kBeginLoad);
ExecuteJsTest({
.params = base::Value(base::Value::Dict().Set("failWith", "none")),
});
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testInitializeFailsAfterReload) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
WebUIStateListener listener(GetHost());
ExecuteJsTest({
.params = base::Value(
base::Value::Dict().Set("failWith", "reloadAfterInitialize")),
});
listener.WaitForWebUiState(mojom::WebUiState::kReady);
listener.WaitForWebUiState(mojom::WebUiState::kBeginLoad);
ExecuteJsTest({
.params = base::Value(base::Value::Dict().Set("failWith", "error")),
});
listener.WaitForWebUiState(mojom::WebUiState::kError);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithFastTimeout, testNoClientCreated) {
#if defined(SLOW_BINARY)
GTEST_SKIP() << "skip timeout test for slow binary";
#else
base::HistogramTester histogram_tester;
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
WebUIStateListener listener(GetHost());
ExecuteJsTest();
listener.WaitForWebUiState(mojom::WebUiState::kError);
EXPECT_GT(histogram_tester.GetBucketCount(
"Glic.Host.WebClientState.OnDestroy", 0 ),
0);
#endif
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithFastTimeout, testNoBootstrap) {
#if defined(SLOW_BINARY)
GTEST_SKIP() << "skip timeout test for slow binary";
#else
base::HistogramTester histogram_tester;
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
WebUIStateListener listener(GetHost());
ExecuteJsTest();
listener.WaitForWebUiState(mojom::WebUiState::kError);
EXPECT_GT(histogram_tester.GetBucketCount(
"Glic.Host.WebClientState.OnDestroy", 0 ),
0);
#endif
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithFastTimeout, testInitializeTimesOut) {
#if defined(SLOW_BINARY)
GTEST_SKIP() << "skip timeout test for slow binary";
#else
base::HistogramTester histogram_tester;
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
WebUIStateListener listener(GetHost());
ExecuteJsTest({
.params = base::Value(base::Value::Dict().Set("failWith", "timeout")),
});
listener.WaitForWebUiState(mojom::WebUiState::kError);
EXPECT_GT(
histogram_tester.GetBucketCount("Glic.Host.WebClientState.OnDestroy",
3 ),
0);
#endif
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testRequestHeader) {
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
const GURL cross_origin_rpc_url =
embedded_test_server()->GetURL("b.com", "/fake-rpc/cors");
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"rpcUrls", base::Value::List()
.Append("/fake-rpc")
.Append(cross_origin_rpc_url.spec())))});
auto request_header_matcher = testing::AllOf(
Contains(Pair("x-glic", "1")),
Contains(
Pair("x-glic-chrome-channel",
testing::AnyOf("unknown", "canary", "dev", "beta", "stable"))),
Contains(
Pair("x-glic-chrome-version", version_info::GetVersionNumber())));
auto find_request = [&](std::string_view path) {
const auto it = std::ranges::find_if(
embedded_test_server_requests_, [&](const auto& request) {
return request.GetURL().GetPath() == path &&
request.method == net::test_server::METHOD_GET;
});
return it == embedded_test_server_requests_.end() ? nullptr : &(*it);
};
auto* main_request = find_request(GetGuestURL().GetPath());
ASSERT_TRUE(main_request);
EXPECT_THAT(main_request->headers, request_header_matcher);
auto* rpc_request = find_request("/fake-rpc");
ASSERT_TRUE(rpc_request);
EXPECT_THAT(rpc_request->headers, request_header_matcher);
auto* cross_origin_rpc_request = find_request("/fake-rpc/cors");
ASSERT_TRUE(cross_origin_rpc_request);
EXPECT_THAT(cross_origin_rpc_request->headers, request_header_matcher);
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCreateTab) {
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
CheckTabCount(1));
ExecuteJsTest();
RunTestSequence(CheckTabCount(2));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCreateTabFailsWithUnsupportedScheme) {
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
CheckTabCount(1));
ExecuteJsTest();
RunTestSequence(CheckTabCount(1));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCreateTabInBackground) {
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
CheckTabCount(1));
ExecuteJsTest();
RunTestSequence(CheckTabCount(2));
tabs::TabInterface* active_tab =
InProcessBrowserTest::browser()->tab_strip_model()->GetActiveTab();
ASSERT_THAT(active_tab->GetContents()->GetURL().spec(),
testing::EndsWith("#foreground"));
ContinueJsTest();
RunTestSequence(CheckTabCount(3));
active_tab =
InProcessBrowserTest::browser()->tab_strip_model()->GetActiveTab();
ASSERT_THAT(active_tab->GetContents()->GetURL().spec(),
testing::EndsWith("#foreground"));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCreateTabByClickingOnLink) {
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
CheckTabCount(1));
TrackGlicInstanceWithId(GetGlicInstance()->id());
content::RenderFrameHost* guest_frame = FindGlicGuestMainFrame();
ASSERT_TRUE(guest_frame);
ExecuteJsTest();
ASSERT_TRUE(base::test::RunUntil([&]() {
return InProcessBrowserTest::browser()->tab_strip_model()->GetTabCount() ==
2;
})) << "Timed out waiting for tab count to increase. Tab count = "
<< InProcessBrowserTest::browser()->tab_strip_model()->GetTabCount();
ASSERT_EQ(guest_frame, FindGlicGuestMainFrame());
AudioDucker* audio_ducker =
AudioDucker::GetForPage(FindGlicGuestMainFrame()->GetPage());
ASSERT_TRUE(audio_ducker);
ASSERT_EQ(audio_ducker->GetAudioDuckingState(),
AudioDucker::AudioDuckingState::kDucking);
ContinueJsTest();
ASSERT_TRUE(base::test::RunUntil([&]() {
return audio_ducker->GetAudioDuckingState() ==
AudioDucker::AudioDuckingState::kNoDucking;
}));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testPopupOpens) {
browser_activator().SetMode(BrowserActivator::Mode::kFirst);
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
CheckPopupCount(0));
ExecuteJsTest();
RunTestSequence(CheckPopupCount(1));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCreateTabByClickingOnLinkDaisyChains) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Test only supported with multi-instance on";
}
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
CheckTabCount(1));
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCreateTabFailsIfNotActive) {
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testOpenGlicSettingsPage) {
ExecuteJsTest();
RunTestSequence(
InstrumentTab(kSettingsTab),
WaitForWebContentsReady(
kSettingsTab, chrome::GetSettingsUrl(chrome::kGlicSettingsSubpage)));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testOpenPasswordManagerSettingsPage) {
DEFINE_LOCAL_ELEMENT_IDENTIFIER_VALUE(kPasswordManagerTab);
RunTestSequence(
InstrumentNextTab(kPasswordManagerTab), Do([this]() { ExecuteJsTest(); }),
WaitForWebContentsReady(kPasswordManagerTab,
GURL(GetGooglePasswordManagerSubPageURLStr())));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetPanelStateAttached) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Attached only supported with multi-instance.";
}
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetPanelStateAttachedHidden) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Attached only supported with multi-instance.";
}
ExecuteJsTest();
ASSERT_TRUE(AddTabAtIndex(1, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
browser()->tab_strip_model()->ActivateTabAt(1);
ContinueJsTest();
browser()->tab_strip_model()->ActivateTabAt(0);
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testDetachPanel) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Attached only supported with multi-instance.";
}
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testCanAttachPanelSidePanel) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Attached only supported with multi-instance.";
}
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testCanAttachPanelDetached) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Attached only supported with multi-instance.";
}
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testCanAttachPanelDetachedTabClosed) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Attached only supported with multi-instance.";
}
TrackGlicInstanceWithId(GetGlicInstance()->id());
ExecuteJsTest();
auto* tab = browser()->tab_strip_model()->GetActiveTab();
ASSERT_TRUE(tab);
ASSERT_TRUE(AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
tab->Close();
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testAttachPanel) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Attached only supported with multi-instance.";
}
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testMultiplePanelsDetachedAndFloating) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Attached only supported with multi-instance.";
}
RunTestSequence(InstrumentTab(kFirstTab),
NavigateWebContents(kFirstTab, page_url()));
ASSERT_TRUE(AddTabAtIndex(1, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
browser()->tab_strip_model()->ActivateTabAt(0);
ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("first")});
TrackGlicInstanceWithTabIndex(1);
browser()->tab_strip_model()->ActivateTabAt(1);
RunTestSequence(InstrumentTab(kSecondTab),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("second")});
TrackGlicInstanceWithTabIndex(0);
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testThereCanOnlyBeOneFloaty) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Attached only supported with multi-instance.";
}
RunTestSequence(InstrumentTab(kFirstTab),
NavigateWebContents(kFirstTab, page_url()));
ASSERT_TRUE(AddTabAtIndex(1, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
browser()->tab_strip_model()->ActivateTabAt(0);
ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
GlicInstanceImpl* tab0_instance = GetGlicInstanceImpl();
ExecuteJsTest({.params = base::Value("first")});
ASSERT_EQ(mojom::PanelStateKind::kDetached,
tab0_instance->GetPanelState().kind);
TrackGlicInstanceWithTabIndex(1);
browser()->tab_strip_model()->ActivateTabAt(1);
RunTestSequence(InstrumentTab(kSecondTab),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("second")});
GlicInstanceImpl* tab1_instance = GetGlicInstanceImpl();
TrackGlicInstanceWithTabIndex(0);
ContinueJsTest();
ASSERT_EQ(mojom::PanelStateKind::kDetached,
tab1_instance->GetPanelState().kind);
ASSERT_EQ(mojom::PanelStateKind::kHidden,
tab0_instance->GetPanelState().kind);
}
IN_PROC_BROWSER_TEST_P(GlicApiTest,
testSwitchConversationToOldConversationNewInstance) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Multi-instance only";
}
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest();
histogram_tester->ExpectBucketCount(
"Glic.Interaction.SwitchConversationTarget",
GlicSwitchConversationTarget::kSwitchedToNewInstance, 1);
}
IN_PROC_BROWSER_TEST_P(GlicApiTest,
testSwitchConversationToNewConversationNewInstance) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Multi-instance only";
}
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest();
histogram_tester->ExpectBucketCount(
"Glic.Interaction.SwitchConversationTarget",
GlicSwitchConversationTarget::kStartNewConversation, 1);
}
IN_PROC_BROWSER_TEST_P(GlicApiTest,
testSwitchConversationToLastActiveConversation) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Multi-instance only";
}
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("step1")});
ASSERT_TRUE(AddTabAtIndex(1, page_url(), ui::PAGE_TRANSITION_TYPED));
browser()->tab_strip_model()->ActivateTabAt(1);
TrackGlicInstanceWithTabIndex(1);
RunTestSequence(InstrumentTab(kSecondTab),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("step2")});
ASSERT_TRUE(base::test::RunUntil([&]() {
return histogram_tester->GetBucketCount(
"Glic.Interaction.SwitchConversationTarget",
GlicSwitchConversationTarget::kSwitchedToLastActive) == 1;
}));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest,
testSwitchConversationToOldConversationInOldInstance) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Multi-instance only";
}
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("step1")});
ASSERT_TRUE(AddTabAtIndex(1, page_url(), ui::PAGE_TRANSITION_TYPED));
browser()->tab_strip_model()->ActivateTabAt(1);
TrackGlicInstanceWithTabIndex(1);
RunTestSequence(InstrumentTab(kSecondTab),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("step2")});
ASSERT_TRUE(base::test::RunUntil([&]() {
return histogram_tester->GetBucketCount(
"Glic.Interaction.SwitchConversationTarget",
GlicSwitchConversationTarget::kSwitchedToNewInstance) == 1;
}));
ASSERT_TRUE(AddTabAtIndex(1, page_url(), ui::PAGE_TRANSITION_TYPED));
browser()->tab_strip_model()->ActivateTabAt(1);
RunTestSequence(InstrumentTab(kThirdTab),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("step3")});
ASSERT_TRUE(base::test::RunUntil([&]() {
return histogram_tester->GetBucketCount(
"Glic.Interaction.SwitchConversationTarget",
GlicSwitchConversationTarget::kSwitchedToExistingInstance) == 1;
}));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testTabSwitchDoesNotLogActivationMetric) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "This test requires multi-instance mode.";
}
RunTestSequence(InstrumentTab(kFirstTab),
NavigateWebContents(kFirstTab, page_url()),
OpenGlicWindow(GlicWindowMode::kAttached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("first")});
ASSERT_TRUE(AddTabAtIndex(1, page_url(), ui::PAGE_TRANSITION_TYPED));
TrackGlicInstanceWithTabIndex(1);
browser()->tab_strip_model()->ActivateTabAt(1);
RunTestSequence(InstrumentTab(kSecondTab),
OpenGlicWindow(GlicWindowMode::kAttached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("second")});
ASSERT_TRUE(base::test::RunUntil([&]() {
return GetService()->window_controller().GetInstances().size() == 1u;
}));
ASSERT_EQ("A", GetGlicInstanceImpl()->conversation_id());
browser()->tab_strip_model()->ActivateTabAt(0);
TrackGlicInstanceWithTabIndex(0);
histogram_tester->ExpectTotalCount("Glic.Instance.TimeSinceLastActive", 1);
browser()->tab_strip_model()->ActivateTabAt(1);
TrackGlicInstanceWithTabIndex(1);
histogram_tester->ExpectTotalCount("Glic.Instance.TimeSinceLastActive", 1);
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testDetachDoesNotLogActivationMetric) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "This test requires multi-instance mode.";
}
RunTestSequence(InstrumentTab(kFirstTab),
NavigateWebContents(kFirstTab, page_url()),
OpenGlicWindow(GlicWindowMode::kAttached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("registerAndDetach")});
TrackFloatingGlicInstance();
ASSERT_EQ("A", GetGlicInstanceImpl()->conversation_id());
histogram_tester->ExpectTotalCount("Glic.Instance.TimeSinceLastActive", 0);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testClosePanel) {
ExecuteJsTest();
RunTestSequence(WaitForHide(kGlicViewElementId));
}
class GlicApiTestRuntimeFeatureOff : public GlicApiTestWithOneTab {
public:
GlicApiTestRuntimeFeatureOff() {
with_feature_off_.InitAndDisableFeature(
mojom::features::kGlicAppendModelQualityClientId);
}
private:
base::test::ScopedFeatureList with_feature_off_;
};
IN_PROC_BROWSER_TEST_P(GlicApiTestRuntimeFeatureOff,
testErrorShownOnMojoPipeError) {
ExecuteJsTest();
auto* web_contents = FindGlicWebUIContents();
const char* script = R"js(
(()=>{
const appController = appRouter.glicController;
if (!appController.webview.host.handler.getModelQualityClientId) {
return "Method not found";
}
appController.webview.host.handler.getModelQualityClientId();
return "Method called";
})()
)js";
auto result = content::EvalJs(web_contents->GetPrimaryMainFrame(), script);
ASSERT_EQ("Method called", result.ExtractString());
WaitForWebUiState(mojom::WebUiState::kError);
histogram_tester->ExpectUniqueSample("Glic.Host.WebClientState.OnDestroy",
9 , 1);
RunTestSequence(
ClickWebElement(TargetWebContents::kGlicWebUi, "#reload", false));
WaitForWebUiState(mojom::WebUiState::kReady);
ExecuteJsTest();
}
#if !BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testShowProfilePicker) {
base::test::TestFuture<void> profile_picker_opened;
ProfilePicker::AddOnProfilePickerOpenedCallbackForTesting(
profile_picker_opened.GetCallback());
ExecuteJsTest();
ASSERT_TRUE(profile_picker_opened.Wait());
}
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testPanelActive) {
browser_activator().SetMode(BrowserActivator::Mode::kFirst);
TrackGlicInstanceWithId(GetGlicInstance()->id());
ExecuteJsTest();
NavigateParams params(browser()->profile(), GURL("about:blank"),
ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
params.disposition = WindowOpenDisposition::NEW_WINDOW;
base::WeakPtr<content::NavigationHandle> navigation_handle =
Navigate(¶ms);
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testIsBrowserOpen) {
browser_activator().SetMode(BrowserActivator::Mode::kFirst);
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
TrackGlicInstanceWithId(GetGlicInstance()->id());
ExecuteJsTest();
CreateIncognitoBrowser();
CloseBrowserAsynchronously(browser());
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testEnableDragResize) {
SKIP_TEST_FOR_MULTI_INSTANCE();
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest();
RunTestSequence(WaitForCanResizeEnabled(true));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testDisableDragResize) {
SKIP_TEST_FOR_MULTI_INSTANCE();
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
WaitForCanResizeEnabled(true));
ExecuteJsTest();
RunTestSequence(WaitForCanResizeEnabled(false));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testInitiallyNotResizable) {
SKIP_TEST_FOR_MULTI_INSTANCE();
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest();
RunTestSequence(WaitForCanResizeEnabled(false));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithMqlsIdGetterEnabled,
testGetModelQualityClientIdFeatureEnabled) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithMqlsIdGetterDisabled,
testGetModelQualityClientIdFeatureDisabled) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTabAndContextualCueing,
MAYBE(testGetZeroStateSuggestionsForFocusedTabApi)) {
EXPECT_CALL(*mock_cueing_service(),
GetContextualGlicZeroStateSuggestionsForFocusedTab(_, _, _, _))
.Times(1);
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(
GlicApiTestWithOneTabAndContextualCueing,
MAYBE(testGetZeroStateSuggestionsForFocusedTabFailsWhenHidden)) {
EXPECT_CALL(*mock_cueing_service(),
GetContextualGlicZeroStateSuggestionsForFocusedTab(_, _, _, _))
.Times(0);
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTabAndContextualCueing,
MAYBE(testGetZeroStateSuggestionsApi)) {
if (GetParam().multi_instance) {
EXPECT_CALL(
*mock_cueing_service(),
GetContextualGlicZeroStateSuggestionsForPinnedTabs(_, _, _, _, _))
.Times(testing::AtLeast(1));
} else {
EXPECT_CALL(*mock_cueing_service(),
GetContextualGlicZeroStateSuggestionsForFocusedTab(_, _, _, _))
.Times(1);
}
ExecuteJsTest();
}
#if BUILDFLAG(IS_CHROMEOS) || (BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER))
#define MAYBE_testGetZeroStateSuggestionsMultipleNavigations \
DISABLED_testGetZeroStateSuggestionsMultipleNavigations
#else
#define MAYBE_testGetZeroStateSuggestionsMultipleNavigations \
testGetZeroStateSuggestionsMultipleNavigations
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTabAndContextualCueing,
MAYBE_testGetZeroStateSuggestionsMultipleNavigations) {
SKIP_TEST_FOR_MULTI_INSTANCE();
EXPECT_CALL(*mock_cueing_service(),
GetContextualGlicZeroStateSuggestionsForFocusedTab(_, _, _, _))
.Times(1);
ExecuteJsTest();
std::vector<std::string> suggestions = {"suggestion1", "suggestion2",
"suggestion3"};
EXPECT_CALL(*mock_cueing_service(),
GetContextualGlicZeroStateSuggestionsForFocusedTab(_, _, _, _))
.WillRepeatedly(RunOnceCallbackRepeatedly<3>(suggestions));
RunTestSequence(NavigateWebContents(
kFirstTab, InProcessBrowserTest::embedded_test_server()->GetURL(
"/scrollable_page_with_content.html")));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTabAndContextualCueing,
MAYBE(testGetZeroStateSuggestionsFailsWhenHidden)) {
SKIP_TEST_FOR_MULTI_INSTANCE();
EXPECT_CALL(*mock_cueing_service(),
GetContextualGlicZeroStateSuggestionsForFocusedTab(_, _, _, _))
.Times(1);
ExecuteJsTest();
testing::Mock::VerifyAndClearExpectations(mock_cueing_service());
EXPECT_CALL(*mock_cueing_service(),
GetContextualGlicZeroStateSuggestionsForFocusedTab(_, _, _, _))
.Times(0);
RunTestSequence(NavigateWebContents(
kFirstTab, InProcessBrowserTest::embedded_test_server()->GetURL(
"/scrollable_page_with_content.html")));
ContinueJsTest();
}
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_MAC) || BUILDFLAG(IS_CHROMEOS) || \
(BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER))
#define MAYBE_testDeferredFocusedTabStateAtCreation \
DISABLED_testDeferredFocusedTabStateAtCreation
#else
#define MAYBE_testDeferredFocusedTabStateAtCreation \
testDeferredFocusedTabStateAtCreation
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTabAndPreloading,
MAYBE_testDeferredFocusedTabStateAtCreation) {
RunTestSequence(NavigateWebContents(
kFirstTab, InProcessBrowserTest::embedded_test_server()->GetURL(
"/scrollable_page_with_content.html")));
ExecuteJsTest();
RunTestSequence(ToggleGlicWindow(GlicWindowMode::kDetached),
CheckControllerShowing(true));
ContinueJsTest();
}
#if BUILDFLAG(IS_LINUX)
#define MAYBE_testNoExtractionWhileHidden DISABLED_testNoExtractionWhileHidden
#else
#define MAYBE_testNoExtractionWhileHidden testNoExtractionWhileHidden
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTabAndPreloading,
MAYBE_testNoExtractionWhileHidden) {
ExecuteJsTest();
int expected_count_hidden = 1;
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
expected_count_hidden = 0;
#endif
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromFocusedTab",
GlicRequestEvent::kRequestReceivedWhileHidden, expected_count_hidden);
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromFocusedTab",
GlicRequestEvent::kRequestHandlerException, 1);
histogram_tester->ExpectTotalCount("Glic.Api.RequestCounts.GetContextFromTab",
0);
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ContinueJsTest();
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromFocusedTab",
GlicRequestEvent::kRequestReceivedWhileHidden, expected_count_hidden);
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromFocusedTab",
GlicRequestEvent::kRequestHandlerException, 1);
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromTab",
GlicRequestEvent::kRequestReceivedWhileHidden, 0);
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromTab",
GlicRequestEvent::kRequestHandlerException, 0);
RunTestSequence(CloseGlic());
ContinueJsTest();
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromFocusedTab",
GlicRequestEvent::kRequestReceivedWhileHidden, ++expected_count_hidden);
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromFocusedTab",
GlicRequestEvent::kRequestHandlerException, 2);
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromTab",
GlicRequestEvent::kRequestReceivedWhileHidden, 1);
histogram_tester->ExpectBucketCount(
"Glic.Api.RequestCounts.GetContextFromTab",
GlicRequestEvent::kRequestHandlerException, 1);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetFocusedTabStateV2) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetFocusedTabStateV2WithNavigation) {
ExecuteJsTest();
RunTestSequence(NavigateWebContents(
kFirstTab, InProcessBrowserTest::embedded_test_server()->GetURL(
"/scrollable_page_with_content.html")));
ContinueJsTest();
RunTestSequence(AddInstrumentedTabAndOpenSidePanel(
kSecondTab, InProcessBrowserTest::embedded_test_server()->GetURL(
"/glic/browser_tests/test.html")));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetFocusedTabStateV2WithNavigationWhenInactive) {
SKIP_TEST_FOR_MULTI_INSTANCE();
TrackGlicInstanceWithId(GetGlicInstance()->id());
ExecuteJsTest();
RunTestSequence(NavigateWebContents(
kFirstTab, InProcessBrowserTest::embedded_test_server()->GetURL(
"/scrollable_page_with_content.html")));
RunTestSequence(
AddInstrumentedTab(kSecondTab,
InProcessBrowserTest::embedded_test_server()->GetURL(
"/glic/browser_tests/test.html")),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testGetFocusedTabStateV2BrowserClosed) {
SKIP_TEST_FOR_MULTI_INSTANCE();
browser_activator().SetMode(BrowserActivator::Mode::kFirst);
TrackFloatingGlicInstance();
RunTestSequence(OpenGlicFloatingWindow(GlicInstrumentMode::kHostAndContents));
CreateIncognitoBrowser();
CloseBrowserAsynchronously(browser());
ExecuteJsTest({.wait_for_guest = false});
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetContextFromFocusedTabWithoutPermission) {
SKIP_TEST_FOR_MULTI_INSTANCE();
ExecuteJsTest();
EXPECT_THAT(
histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromFocusedTab.Error"),
UnorderedElementsAre(Pair(
"Glic.Api.GetContextFromFocusedTab.Error.Text",
BucketsAre(Bucket(GlicGetContextFromTabError::
kPermissionDeniedContextPermissionNotEnabled,
1)))));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetContextFromPinnedTabWithoutPermission) {
ExecuteJsTest();
EXPECT_THAT(histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromTab.Error"),
testing::IsEmpty());
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetContextFromFocusedTabWithNoRequestedData) {
ExecuteJsTest();
EXPECT_THAT(histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromFocusedTab.Error"),
testing::IsEmpty());
}
#if BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER)
#define MAYBE_testGetContextFromFocusedTabWithAllRequestedData \
DISABLED_testGetContextFromFocusedTabWithAllRequestedData
#else
#define MAYBE_testGetContextFromFocusedTabWithAllRequestedData \
testGetContextFromFocusedTabWithAllRequestedData
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
MAYBE_testGetContextFromFocusedTabWithAllRequestedData) {
ExecuteJsTest();
EXPECT_THAT(histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromFocusedTab.Error"),
testing::IsEmpty());
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetContextForActorFromTabWithoutPermission) {
ExecuteJsTest();
EXPECT_THAT(histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextForActorFromTab.Error"),
testing::IsEmpty());
}
#if BUILDFLAG(ENABLE_PDF)
#define MAYBE_testGetContextFromFocusedTabWithPdfFile \
testGetContextFromFocusedTabWithPdfFile
#else
#define MAYBE_testGetContextFromFocusedTabWithPdfFile \
DISABLED_testGetContextFromFocusedTabWithPdfFile
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
MAYBE_testGetContextFromFocusedTabWithPdfFile) {
RunTestSequence(NavigateWebContents(
kFirstTab,
InProcessBrowserTest::embedded_test_server()->GetURL("/pdf/test.pdf")));
ExecuteJsTest();
EXPECT_THAT(histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromFocusedTab.Error"),
testing::IsEmpty());
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetContextFromFocusedTabWithUnFocusablePage) {
RunTestSequence(NavigateWebContents(kFirstTab, chrome::GetSettingsUrl("")));
ExecuteJsTest();
EXPECT_THAT(histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromFocusedTab.Error"),
UnorderedElementsAre(Pair(
"Glic.Api.GetContextFromFocusedTab.Error.Text",
BucketsAre(Bucket(
GlicGetContextFromTabError::kPermissionDenied, 1)))));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, DISABLED_testCaptureScreenshot) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testPermissionAccess) {
SKIP_TEST_FOR_MULTI_INSTANCE();
ExecuteJsTest();
histogram_tester->ExpectUniqueSample(
"Glic.Sharing.ActiveTabSharingState.OnTabContextPermissionGranted",
ActiveTabSharingState::kActiveTabIsShared, 1);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testClosedCaptioning) {
ExecuteJsTest();
}
#if !BUILDFLAG(IS_CHROMEOS)
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetUserProfileInfo) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetUserProfileInfoDoesNotDeferWhenInactive) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testSignInPauseState) {
ExecuteJsTest({.expect_guest_frame_destroyed = false});
auto* const identity_manager =
IdentityManagerFactory::GetForProfile(browser()->profile());
signin::SetInvalidRefreshTokenForPrimaryAccount(identity_manager);
ASSERT_TRUE(base::test::RunUntil(
[&]() { return FindGlicGuestMainFrame() == nullptr; }));
WaitForWebUiState(mojom::WebUiState::kSignIn);
}
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testRefreshSignInCookies) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testActuationOnWebSetting) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testSetContextAccessIndicator) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testSetAudioDucking) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetDisplayMedia) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testJournal) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, DISABLED_testMetrics) {
browser()->profile()->GetPrefs()->SetBoolean(
prefs::kGlicClosedCaptioningEnabled, true);
ExecuteJsTest();
sleepWithRunLoop(base::Milliseconds(100));
histogram_tester->ExpectUniqueSample(
"Glic.Sharing.ActiveTabSharingState.OnUserInputSubmitted",
ActiveTabSharingState::kTabContextPermissionNotGranted, 1);
histogram_tester->ExpectUniqueSample("Glic.Response.ClosedCaptionsShown",
true, 1);
EXPECT_EQ(1, user_action_tester->GetActionCount("GlicContextUploadStarted"));
EXPECT_EQ(1,
user_action_tester->GetActionCount("GlicContextUploadCompleted"));
EXPECT_EQ(1, user_action_tester->GetActionCount("GlicReactionModelled"));
EXPECT_EQ(1, user_action_tester->GetActionCount("GlicResponseStopByUser"));
histogram_tester->ExpectTotalCount("Glic.FirstReaction.Text.Modelled.Time",
1);
histogram_tester->ExpectTotalCount("Glic.TabContext.UploadTime", 1);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testScrollToFindsText) {
SKIP_TEST_FOR_MULTI_INSTANCE();
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"documentId", GetDocumentIdForTab(kFirstTab)))});
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testScrollToFindsTextNoTabContextPermission) {
SKIP_TEST_FOR_MULTI_INSTANCE();
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"documentId", GetDocumentIdForTab(kFirstTab)))});
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testScrollToFailsWhenInactive) {
SKIP_TEST_FOR_MULTI_INSTANCE();
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"documentId", GetDocumentIdForTab(kFirstTab)))});
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testScrollToNoMatchFound) {
SKIP_TEST_FOR_MULTI_INSTANCE();
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"documentId", GetDocumentIdForTab(kFirstTab)))});
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testSetSyntheticExperimentState) {
ExecuteJsTest();
ASSERT_TRUE(base::test::RunUntil([]() {
std::vector<variations::ActiveGroupId> trials =
g_browser_process->metrics_service()
->GetSyntheticTrialRegistry()
->GetCurrentSyntheticFieldTrialsForTest();
variations::ActiveGroupId expected =
variations::MakeActiveGroupId("TestTrial", "Enabled");
return std::ranges::any_of(trials, [&](const auto& trial) {
return trial.name == expected.name && trial.group == expected.group;
});
}));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testSetSyntheticExperimentStateMultiProfile) {
ExecuteJsTest();
ASSERT_TRUE(base::test::RunUntil([]() {
std::vector<variations::ActiveGroupId> trials =
g_browser_process->metrics_service()
->GetSyntheticTrialRegistry()
->GetCurrentSyntheticFieldTrialsForTest();
variations::ActiveGroupId expected =
variations::MakeActiveGroupId("TestTrial", "MultiProfileDetected");
return std::ranges::any_of(trials, [&](const auto& trial) {
return trial.name == expected.name && trial.group == expected.group;
});
}));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCloseAndOpenWhileOpening) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
ExecuteJsTest();
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testNotifyPanelWillOpenIsCalledOnce) {
ExecuteJsTest();
if (!GetParam().multi_instance) {
histogram_tester->ExpectUniqueSample(
"Glic.Sharing.ActiveTabSharingState.OnPanelOpenAndReady",
ActiveTabSharingState::kTabContextPermissionNotGranted, 1);
}
}
IN_PROC_BROWSER_TEST_P(GlicApiTest,
testPanelWillOpenHasRecentlyActiveConversations) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Only supported with multi-instance.";
}
RunTestSequence(InstrumentTab(kFirstTab),
NavigateWebContents(kFirstTab, page_url()),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("instance1")});
ASSERT_TRUE(AddTabAtIndex(1, page_url(), ui::PAGE_TRANSITION_TYPED));
TrackGlicInstanceWithTabIndex(1);
RunTestSequence(InstrumentTab(kSecondTab),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("instance2")});
ASSERT_TRUE(AddTabAtIndex(2, page_url(), ui::PAGE_TRANSITION_TYPED));
TrackGlicInstanceWithTabIndex(2);
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("instance3")});
browser()->tab_strip_model()->ActivateTabAt(0);
browser()->tab_strip_model()->ActivateTabAt(2);
browser()->tab_strip_model()->ActivateTabAt(1);
ASSERT_TRUE(AddTabAtIndex(3, page_url(), ui::PAGE_TRANSITION_TYPED));
TrackGlicInstanceWithTabIndex(3);
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("instance4")});
ASSERT_TRUE(AddTabAtIndex(4, page_url(), ui::PAGE_TRANSITION_TYPED));
TrackGlicInstanceWithTabIndex(4);
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("verify")});
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetOsHotkeyState) {
ExecuteJsTest();
g_browser_process->local_state()->SetString(prefs::kGlicLauncherHotkey,
"Ctrl+Shift+1");
ContinueJsTest();
g_browser_process->local_state()->SetString(prefs::kGlicLauncherHotkey, "");
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testSetWindowDraggableAreas) {
TODO_SKIP_BROKEN_MULTI_INSTANCE_TEST();
ExecuteJsTest();
const int x = 10;
const int y = 20;
const int width = 30;
const int height = 40;
RunTestSequence(
CheckPointIsWithinDraggableArea(gfx::Point(x, y), true),
CheckPointIsWithinDraggableArea(gfx::Point(x + width - 1, y), true),
CheckPointIsWithinDraggableArea(gfx::Point(x, y + height - 1), true),
CheckPointIsWithinDraggableArea(gfx::Point(x + width - 1, y + height - 1),
true),
CheckPointIsWithinDraggableArea(gfx::Point(x - 1, y), false),
CheckPointIsWithinDraggableArea(gfx::Point(x, y - 1), false),
CheckPointIsWithinDraggableArea(gfx::Point(x + width, y), false),
CheckPointIsWithinDraggableArea(gfx::Point(x, y + height), false));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testSetWindowDraggableAreasDefault) {
TODO_SKIP_BROKEN_MULTI_INSTANCE_TEST();
const int x = 0;
const int y = 0;
const int width = 400;
const int height = 80;
ExecuteJsTest();
RunTestSequence(
CheckPointIsWithinDraggableArea(gfx::Point(x, y), true),
CheckPointIsWithinDraggableArea(gfx::Point(x + width - 1, y), true),
CheckPointIsWithinDraggableArea(gfx::Point(x, y + height - 1), true),
CheckPointIsWithinDraggableArea(gfx::Point(x + width - 1, y + height - 1),
true),
CheckPointIsWithinDraggableArea(gfx::Point(x - 1, y), false),
CheckPointIsWithinDraggableArea(gfx::Point(x, y - 1), false),
CheckPointIsWithinDraggableArea(gfx::Point(x + width, y), false),
CheckPointIsWithinDraggableArea(gfx::Point(x, y + height), false));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testSetMinimumWidgetSize) {
NavigateTabAndOpenGlicFloating();
ExecuteJsTest();
ASSERT_TRUE(step_data()->is_dict());
const auto& min_size = step_data()->GetDict();
const int width = min_size.FindInt("width").value();
const int height = min_size.FindInt("height").value();
auto expected_size = glic::GlicWidget::GetInitialSize();
expected_size.SetToMax(gfx::Size(width, height));
EXPECT_EQ(GetGlicWidget()->GetMinimumSize(), expected_size);
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testManualResizeChanged) {
NavigateTabAndOpenGlicFloating();
GetGlicWidget()->OnNativeWidgetUserResizeStarted();
ExecuteJsTest();
GetGlicWidget()->OnNativeWidgetUserResizeEnded();
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testResizeWindowTooSmall) {
NavigateTabAndOpenGlicFloating();
gfx::Size expected_size = GlicWidget::GetInitialSize();
GlicWidget* glic_widget = static_cast<GlicWidget*>(GetGlicWidget());
ASSERT_TRUE(glic_widget);
ExecuteJsTest();
gfx::Rect final_widget_bounds = glic_widget->GetWindowBoundsInScreen();
ASSERT_EQ(expected_size,
glic_widget->WidgetToVisibleBounds(final_widget_bounds).size());
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testResizeWindowTooLarge) {
NavigateTabAndOpenGlicFloating();
ExecuteJsTest();
gfx::Rect display_bounds =
display::Screen::Get()->GetPrimaryDisplay().work_area();
GlicWidget* glic_widget = static_cast<GlicWidget*>(GetGlicWidget());
ASSERT_TRUE(glic_widget);
gfx::Rect final_widget_bounds = glic_widget->GetWindowBoundsInScreen();
ASSERT_TRUE(display_bounds.Contains(final_widget_bounds));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testResizeWindowWithinBounds) {
NavigateTabAndOpenGlicFloating();
gfx::Size expected_size = gfx::Size(800, 700);
ExecuteJsTest(
{.params = base::Value(base::Value::Dict()
.Set("width", expected_size.width())
.Set("height", expected_size.height()))});
GlicWidget* glic_widget = static_cast<GlicWidget*>(GetGlicWidget());
gfx::Rect final_widget_bounds = glic_widget->GetWindowBoundsInScreen();
ASSERT_EQ(expected_size,
glic_widget->WidgetToVisibleBounds(final_widget_bounds).size());
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testDaisyChainRecursiveAndInput) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Only supported with multi-instance.";
}
RunTestSequence(InstrumentTab(kFirstTab),
NavigateWebContents(kFirstTab, page_url()),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("createTab")});
auto* tab_strip = browser()->tab_strip_model();
ASSERT_TRUE(base::test::RunUntil([&]() { return tab_strip->count() == 2; }));
tab_strip->ActivateTabAt(1);
TrackGlicInstanceWithTabIndex(1);
WaitForAndInstrumentGlic(GlicInstrumentMode::kHostAndContents);
histogram_tester->ExpectTotalCount(
"Glic.Instance.FirstActionInDaisyChainPanel", 0);
ExecuteJsTest({.params = base::Value("createTab")});
ASSERT_TRUE(base::test::RunUntil([&]() { return tab_strip->count() == 3; }));
tab_strip->ActivateTabAt(2);
ASSERT_TRUE(base::test::RunUntil([&]() {
return histogram_tester->GetBucketCount(
"Glic.Instance.FirstActionInDaisyChainPanel",
DaisyChainFirstAction::kRecursiveDaisyChain) == 1;
}));
TrackGlicInstanceWithTabIndex(2);
WaitForAndInstrumentGlic(GlicInstrumentMode::kHostAndContents);
ExecuteJsTest({.params = base::Value("inputSubmitted")});
ASSERT_TRUE(base::test::RunUntil([&]() {
return histogram_tester->GetBucketCount(
"Glic.Instance.FirstActionInDaisyChainPanel",
DaisyChainFirstAction::kInputSubmitted) == 1;
}));
}
class GlicApiTestSystemSettingsTest : public GlicApiTestWithOneTab {
public:
GlicApiTestSystemSettingsTest() {
system_permission_settings::SetInstanceForTesting(&mock_platform_handle);
}
~GlicApiTestSystemSettingsTest() override {
system_permission_settings::SetInstanceForTesting(nullptr);
}
testing::NiceMock<system_permission_settings::MockPlatformHandle>
mock_platform_handle;
};
IN_PROC_BROWSER_TEST_P(GlicApiTestSystemSettingsTest,
testOpenOsMediaPermissionSettings) {
base::test::TestFuture<void> signal;
EXPECT_CALL(
mock_platform_handle,
OpenSystemSettings(testing::_, ContentSettingsType::MEDIASTREAM_MIC))
.WillOnce(base::test::InvokeFuture(signal));
ExecuteJsTest();
EXPECT_TRUE(signal.Wait());
}
IN_PROC_BROWSER_TEST_P(GlicApiTestSystemSettingsTest,
testOpenOsGeoPermissionSettings) {
base::test::TestFuture<void> signal;
EXPECT_CALL(mock_platform_handle,
OpenSystemSettings(testing::_, ContentSettingsType::GEOLOCATION))
.WillOnce(base::test::InvokeFuture(signal));
ExecuteJsTest();
EXPECT_TRUE(signal.Wait());
}
IN_PROC_BROWSER_TEST_P(GlicApiTestSystemSettingsTest,
testGetOsMicrophonePermissionStatusAllowed) {
EXPECT_CALL(mock_platform_handle,
IsAllowed(ContentSettingsType::MEDIASTREAM_MIC))
.WillOnce(testing::Return(true));
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestSystemSettingsTest,
testGetOsMicrophonePermissionStatusNotAllowed) {
EXPECT_CALL(mock_platform_handle,
IsAllowed(ContentSettingsType::MEDIASTREAM_MIC))
.WillOnce(testing::Return(false));
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testNavigateToDifferentClientPage) {
base::HistogramTester histogram_tester;
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
WebUIStateListener listener(GetHost());
listener.WaitForWebUiState(mojom::WebUiState::kReady);
ExecuteJsTest({.params = base::Value(0)});
listener.WaitForWebUiState(mojom::WebUiState::kBeginLoad);
listener.WaitForWebUiState(mojom::WebUiState::kReady);
ExecuteJsTest({.params = base::Value(1)});
histogram_tester.ExpectUniqueSample("Glic.Host.WebClientState.OnCommit",
6 , 1);
histogram_tester.ExpectUniqueSample("Glic.Host.WebClientState.OnDestroy",
0 , 1);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithFastTimeout, testNavigateToAboutBlank) {
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
WebUIStateListener listener(GetHost());
listener.WaitForWebUiState(mojom::WebUiState::kReady);
ExecuteJsTest();
listener.WaitForWebUiState(mojom::WebUiState::kError);
}
#if BUILDFLAG(IS_MAC)
#define MAYBE_testNavigateToBadPage DISABLED_testNavigateToBadPage
#else
#define MAYBE_testNavigateToBadPage testNavigateToBadPage
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithFastTimeout,
MAYBE_testNavigateToBadPage) {
#if defined(SLOW_BINARY)
GTEST_SKIP() << "skip timeout test for slow binary";
#else
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
RegisterConversation("test-id"));
WebUIStateListener listener(GetHost());
listener.WaitForWebUiState(mojom::WebUiState::kReady);
ExecuteJsTest({.params = base::Value(0)});
listener.WaitForWebUiState(mojom::WebUiState::kBeginLoad);
listener.WaitForWebUiState(mojom::WebUiState::kError);
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value(1)});
#endif
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCallingApiWhileHiddenRecordsMetrics) {
RunTestSequence(
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
ExecuteJsTest();
RunTestSequence(CloseGlic());
base::HistogramTester histogram_tester;
ContinueJsTest();
histogram_tester.ExpectBucketCount("Glic.Api.RequestCounts.CreateTab",
GlicRequestEvent::kRequestReceived, 1);
histogram_tester.ExpectBucketCount(
"Glic.Api.RequestCounts.CreateTab",
GlicRequestEvent::kRequestReceivedWhileHidden, 1);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testPinTabs) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testUnpinTabsWhileClosing) {
NavigateTabAndOpenGlicFloating();
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testPinTabsWithTwoTabs) {
NavigateTabAndOpenGlicFloating();
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest();
browser()->tab_strip_model()->SelectPreviousTab();
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testPinTabsFailsWhenDoesnotExist) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest,
testPinTabsStatePersistWhenClosePanelAndReopen) {
NavigateTabAndOpenGlicFloating();
const int tab_id =
GetTabId(browser()->tab_strip_model()->GetActiveWebContents());
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"tabId", base::NumberToString(tab_id)))});
RunTestSequence(OpenGlicFloatingWindow());
ContinueJsTest();
}
#if BUILDFLAG(IS_LINUX)
#define MAYBE_testPinTabsStatePersistWhenClientRestarts \
DISABLED_testPinTabsStatePersistWhenClientRestarts
#else
#define MAYBE_testPinTabsStatePersistWhenClientRestarts \
testPinTabsStatePersistWhenClientRestarts
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTest,
MAYBE_testPinTabsStatePersistWhenClientRestarts) {
NavigateTabAndOpenGlicFloating();
const int tab_id =
GetTabId(browser()->tab_strip_model()->GetActiveWebContents());
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest(
{.params = base::Value(base::Value::Dict()
.Set("tabId", base::NumberToString(tab_id))
.Set("isFirstRun", true))});
WebUIStateListener listener(GetHost());
ReloadGlicWebui();
listener.WaitForWebUiState(mojom::WebUiState::kUninitialized);
ExecuteJsTest(
{.params = base::Value(base::Value::Dict().Set("isFirstRun", false))});
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testPinTabsFailsWhenIncognitoWindow) {
browser_activator().SetMode(BrowserActivator::Mode::kFirst);
NavigateTabAndOpenGlicFloating();
auto* incognito = CreateIncognitoBrowser();
const GURL page_url = InProcessBrowserTest::embedded_test_server()->GetURL(
"/glic/browser_tests/test.html");
RunTestSequence(
AddInstrumentedTab(kSecondTab, page_url, std::nullopt, incognito));
const int incognito_tab_id =
GetTabId(incognito->tab_strip_model()->GetActiveWebContents());
ExecuteJsTest(
{.params = base::Value(base::Value::Dict().Set(
"incognitoTabId", base::NumberToString(incognito_tab_id)))});
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testUnpinTabsFailsWhenNotPinned) {
NavigateTabAndOpenGlicFloating();
const int tab_id =
GetTabId(browser()->tab_strip_model()->GetActiveWebContents());
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"tabId", base::NumberToString(tab_id)))});
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testUnpinAllTabs) {
NavigateTabAndOpenGlicFloating();
const int tab_id =
GetTabId(browser()->tab_strip_model()->GetActiveWebContents());
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"tabId", base::NumberToString(tab_id)))});
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testPinTabsHaveNoEffectOnFocusedTab) {
SKIP_TEST_FOR_MULTI_INSTANCE();
const int tab_id =
GetTabId(browser()->tab_strip_model()->GetActiveWebContents());
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"tabId", base::NumberToString(tab_id)))});
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testUnpinTabsThatNavigateInBackground) {
TODO_SKIP_BROKEN_MULTI_INSTANCE_TEST();
ASSERT_TRUE(embedded_https_test_server().Start());
RunTestSequence(
InstrumentTab(kFirstTab),
NavigateWebContents(kFirstTab, embedded_https_test_server().GetURL(
"a.com", "/test_data/page.html?one")),
AddInstrumentedTab(kSecondTab, embedded_https_test_server().GetURL(
"a.com", "/test_data/page.html?two")));
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest();
RunTestSequence(
NavigateWebContents(kSecondTab,
embedded_https_test_server().GetURL(
"b.com", "/test_data/page.html?changedTwo")));
EXPECT_EQ(1,
user_action_tester->GetActionCount("Glic.PinnedTab.OriginChanged"));
EXPECT_EQ(1, user_action_tester->GetActionCount(
"Glic.PinnedTab.OriginChanged.Unpinned"));
RunTestSequence(
NavigateWebContents(kFirstTab,
embedded_https_test_server().GetURL(
"a.com", "/test_data/page.html?sameOrigin")),
ToggleGlicWindow(GlicWindowMode::kDetached),
NavigateWebContents(kFirstTab,
embedded_https_test_server().GetURL(
"b.com", "/test_data/page.html?changedOne")));
EXPECT_EQ(2,
user_action_tester->GetActionCount("Glic.PinnedTab.OriginChanged"));
EXPECT_EQ(1, user_action_tester->GetActionCount(
"Glic.PinnedTab.OriginChanged.Unpinned"));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest,
DISABLED_testTabDataUpdateOnUrlChangeForPinnedTab) {
NavigateTabAndOpenGlicFloating();
const int tab_id =
GetTabId(browser()->tab_strip_model()->GetActiveWebContents());
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"tabId", base::NumberToString(tab_id)))});
GURL new_url = embedded_test_server()->GetURL(
"/glic/browser_tests/test.html?changed=true");
RunTestSequence(NavigateWebContents(kFirstTab, new_url));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest,
DISABLED_testTabDataUpdateOnFaviconChangeForPinnedTab) {
NavigateTabAndOpenGlicFloating();
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents);
const int tab_id = GetTabId(web_contents);
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"tabId", base::NumberToString(tab_id)))});
const char* script =
"var link = document.createElement('link');"
"link.rel = 'icon';"
"link.href= '../../../glic/youtube_favicon_16x16.png';"
"document.head.appendChild(link);";
ASSERT_TRUE(content::ExecJs(web_contents, script));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetContextFromTabIgnorePermissionWhenPinned) {
ExecuteJsTest();
EXPECT_THAT(
histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromTab.Error"),
UnorderedElementsAre(Pair(
"Glic.Api.GetContextFromTab.Error.Text",
BucketsAre(Bucket(GlicGetContextFromTabError::
kPermissionDeniedContextPermissionNotEnabled,
1)))));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetContextFromTabFailDifferentlyBasedOnPermission) {
TODO_SKIP_BROKEN_MULTI_INSTANCE_TEST();
const int tab_id =
GetTabId(browser()->tab_strip_model()->GetActiveWebContents());
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"tabId", base::NumberToString(tab_id)))});
EXPECT_THAT(
histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromTab.Error"),
UnorderedElementsAre(
Pair("Glic.Api.GetContextFromTab.Error.Text",
BucketsAre(
Bucket(GlicGetContextFromTabError::
kPermissionDeniedContextPermissionNotEnabled,
1),
Bucket(GlicGetContextFromTabError::kPermissionDenied, 1)))));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetContextFromTabFailsIfNotPinned) {
TODO_SKIP_BROKEN_MULTI_INSTANCE_TEST();
TrackGlicInstanceWithId(GetGlicInstance()->id());
const int tab_id =
GetTabId(browser()->tab_strip_model()->GetActiveWebContents());
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest({.params = base::Value(base::Value::Dict().Set(
"tabId", base::NumberToString(tab_id)))});
EXPECT_THAT(
histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromTab.Error"),
UnorderedElementsAre(Pair(
"Glic.Api.GetContextFromTab.Error.Text",
BucketsAre(Bucket(GlicGetContextFromTabError::
kPermissionDeniedContextPermissionNotEnabled,
1)))));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
DISABLED_testGetContextFromTabFailsIfDoesNotExist) {
ExecuteJsTest();
if (GetParam().multi_instance) {
return;
}
EXPECT_THAT(
histogram_tester->GetAllSamplesForPrefix(
"Glic.Api.GetContextFromTab.Error"),
UnorderedElementsAre(Pair(
"Glic.Api.GetContextFromTab.Error.Text",
BucketsAre(Bucket(GlicGetContextFromTabError::kTabNotFound, 1)))));
}
IN_PROC_BROWSER_TEST_F(GlicApiTestWithOneTab,
DISABLED_testFetchInactiveTabScreenshot) {
SKIP_TEST_FOR_MULTI_INSTANCE();
RunTestSequence(AddInstrumentedTab(kSecondTab, page_url()));
ExecuteJsTest();
browser()->tab_strip_model()->SelectPreviousTab();
ContinueJsTest();
}
#if (BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN) && defined(ADDRESS_SANITIZER))
#define MAYBE_testFetchInactiveTabScreenshotWhileMinimized \
DISABLED_testFetchInactiveTabScreenshotWhileMinimized
#else
#define MAYBE_testFetchInactiveTabScreenshotWhileMinimized \
testFetchInactiveTabScreenshotWhileMinimized
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
MAYBE_testFetchInactiveTabScreenshotWhileMinimized) {
TODO_SKIP_BROKEN_MULTI_INSTANCE_TEST();
RunTestSequence(AddInstrumentedTabAndOpenSidePanel(kSecondTab, page_url()));
bool can_fetch_screenshot = BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC);
ExecuteJsTest({.params = base::Value(can_fetch_screenshot)});
browser()->tab_strip_model()->SelectPreviousTab();
browser()->window()->Minimize();
ContinueJsTest();
}
class GlicApiTestUserStatusCheckTest : public GlicApiTestWithOneTab {
protected:
void SetUpOnMainThread() override {
GlicApiTestWithOneTab::SetUpOnMainThread();
GetService()->enabling().SetUserStatusFetchOverrideForTest(
base::BindRepeating(&GlicApiTestUserStatusCheckTest::UserStatusFetch,
base::Unretained(this)));
}
void UserStatusFetch(
base::OnceCallback<void(const CachedUserStatus&)> callback) {
user_status_fetch_count_++;
base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE, base::BindOnce(std::move(callback), user_status_));
}
CachedUserStatus user_status_;
unsigned int user_status_fetch_count_ = 0;
};
void UpdatePrimaryAccountToBeManaged(Profile* profile) {
signin::IdentityManager* identity_manager =
IdentityManagerFactory::GetForProfile(profile);
CoreAccountInfo core_account_info =
identity_manager->GetPrimaryAccountInfo(signin::ConsentLevel::kSignin);
AccountInfo account_info =
identity_manager->FindExtendedAccountInfo(core_account_info);
account_info.hosted_domain = gaia::ExtractDomainName(account_info.email);
signin::UpdateAccountInfoForAccount(identity_manager, account_info);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestUserStatusCheckTest,
testMaybeRefreshUserStatus) {
Profile* profile = browser()->profile();
policy::ScopedManagementServiceOverrideForTesting platform_management(
policy::ManagementServiceFactory::GetForProfile(profile),
policy::EnterpriseManagementAuthority::CLOUD);
UpdatePrimaryAccountToBeManaged(profile);
ASSERT_FALSE(GlicEnabling::EnablementForProfile(profile).DisallowedByAdmin());
user_status_.user_status_code = UserStatusCode::DISABLED_BY_ADMIN;
ExecuteJsTest();
ASSERT_TRUE(base::test::RunUntil([&]() {
return GlicEnabling::EnablementForProfile(profile).DisallowedByAdmin();
}));
EXPECT_GE(user_status_fetch_count_, 1u);
}
IN_PROC_BROWSER_TEST_P(GlicApiTestUserStatusCheckTest,
testMaybeRefreshUserStatusThrottled) {
Profile* profile = browser()->profile();
policy::ScopedManagementServiceOverrideForTesting platform_management(
policy::ManagementServiceFactory::GetForProfile(profile),
policy::EnterpriseManagementAuthority::CLOUD);
UpdatePrimaryAccountToBeManaged(profile);
ASSERT_FALSE(GlicEnabling::EnablementForProfile(profile).DisallowedByAdmin());
user_status_.user_status_code = UserStatusCode::ENABLED;
ExecuteJsTest();
ASSERT_TRUE(base::test::RunUntil([&]() {
return user_status_fetch_count_ >= 2;
})) << "There should be at least two fetches (initial and delayed)";
{
base::RunLoop loop;
base::SequencedTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, loop.QuitClosure(), base::Seconds(5));
loop.Run();
}
EXPECT_LT(user_status_fetch_count_, 5u)
<< "We should not send most of the fetches";
}
#if defined(SLOW_BINARY)
#define MAYBE_GlicApiTestWithOneTabMoreDebounceDelay \
DISABLED_GlicApiTestWithOneTabMoreDebounceDelay
#else
#define MAYBE_GlicApiTestWithOneTabMoreDebounceDelay \
GlicApiTestWithOneTabMoreDebounceDelay
#endif
class MAYBE_GlicApiTestWithOneTabMoreDebounceDelay
: public GlicApiTestWithOneTab {
public:
MAYBE_GlicApiTestWithOneTabMoreDebounceDelay() {
features2_.InitWithFeaturesAndParameters(
{{
features::kGlicTabFocusDataDedupDebounce,
{
{features::kGlicTabFocusDataDebounceDelayMs.name, "1000"},
},
}},
{});
}
private:
base::test::ScopedFeatureList features2_;
};
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#define MAYBE_testSingleFocusedTabUpdatesOnTabEvents \
testSingleFocusedTabUpdatesOnTabEvents
#else
#define MAYBE_testSingleFocusedTabUpdatesOnTabEvents \
DISABLED_testSingleFocusedTabUpdatesOnTabEvents
#endif
IN_PROC_BROWSER_TEST_P(MAYBE_GlicApiTestWithOneTabMoreDebounceDelay,
MAYBE_testSingleFocusedTabUpdatesOnTabEvents) {
SKIP_TEST_FOR_MULTI_INSTANCE();
ExecuteJsTest();
RunTestSequence(NavigateWebContents(
kFirstTab, InProcessBrowserTest::embedded_test_server()->GetURL(
"/scrollable_page_with_content.html")));
ContinueJsTest();
RunTestSequence(AddInstrumentedTab(
kSecondTab, InProcessBrowserTest::embedded_test_server()->GetURL(
"/glic/browser_tests/test.html")));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetPinCandidatesSingleTab) {
if (GetParam().multi_instance) {
GetGlicInstanceImpl()->sharing_manager().UnpinAllTabs();
}
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetPinCandidatesWithPanelClosed) {
ExecuteJsTest();
RunTestSequence(AddInstrumentedTab(
kSecondTab,
embedded_test_server()->GetURL("/glic/browser_tests/test.html")));
ContinueJsTest();
RunTestSequence(ToggleGlicWindow(GlicWindowMode::kDetached));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testSendsViewChangeRequestOnTaskIconOrGlicButtonToggle) {
TODO_SKIP_BROKEN_MULTI_INSTANCE_TEST();
CurrentViewListener listener(GetHost());
listener.WaitForCurrentView(mojom::CurrentView::kConversation);
StartTaskAndShowActorTaskIcon();
ExecuteJsTest();
RunTestSequence(ToggleGlicWindowFromSource(
GlicWindowMode::kDetached, kGlicActorTaskIconElementId,
mojom::InvocationSource::kActorTaskIcon));
ContinueJsTest();
listener.WaitForCurrentView(mojom::CurrentView::kActuation);
RunTestSequence(ToggleGlicWindowFromSource(
GlicWindowMode::kDetached, kGlicButtonElementId,
mojom::InvocationSource::kTopChromeButton));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testRemoveBlankInstanceOnClose) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Only supported in multi-instance mode.";
}
RunTestSequence(
InstrumentTab(kFirstTab),
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
ASSERT_EQ(1u, GetService()->window_controller().GetInstances().size());
ExecuteJsTest();
ASSERT_TRUE(base::test::RunUntil([&]() {
return GetService()->window_controller().GetInstances().size() == 0u;
}));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testSwitchConversationToExistingInstance) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Only supported in multi-instance mode.";
}
ExecuteJsTest({.params = base::Value("first")});
ASSERT_TRUE(AddTabAtIndex(1, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
browser()->tab_strip_model()->ActivateTabAt(1);
TrackGlicInstanceWithTabIndex(1);
RunTestSequence(InstrumentTab(kSecondTab),
OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ExecuteJsTest({.params = base::Value("second")});
ASSERT_TRUE(base::test::RunUntil([&]() {
return GetService()->window_controller().GetInstances().size() == 1u;
}));
ASSERT_EQ("id_hello", GetGlicInstanceImpl()->conversation_id());
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCaptureRegion) {
ASSERT_TRUE(AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ASSERT_TRUE(base::test::RunUntil([&]() {
return GetService()->sharing_manager().GetFocusedTabData().focus();
}));
base::RunLoop run_loop;
region_capture_controller().SetOnCaptureRegionForTesting(
run_loop.QuitClosure());
ExecuteJsTest();
run_loop.Run();
region_capture_controller().OnRegionSelected({10, 20, 30, 40});
ContinueJsTest();
ASSERT_TRUE(base::test::RunUntil([&]() {
return !region_capture_controller().IsCaptureRegionInProgressForTesting();
}));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCaptureRegionMultiple) {
ASSERT_TRUE(AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ASSERT_TRUE(base::test::RunUntil([&]() {
return GetService()->sharing_manager().GetFocusedTabData().focus();
}));
base::RunLoop run_loop;
region_capture_controller().SetOnCaptureRegionForTesting(
run_loop.QuitClosure());
ExecuteJsTest();
run_loop.Run();
region_capture_controller().OnRegionSelected({10, 20, 30, 40});
ContinueJsTest();
region_capture_controller().OnRegionSelected({50, 60, 70, 80});
ContinueJsTest();
ASSERT_TRUE(base::test::RunUntil([&]() {
return !region_capture_controller().IsCaptureRegionInProgressForTesting();
}));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCaptureRegionCancelBrowser) {
ASSERT_TRUE(AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ASSERT_TRUE(base::test::RunUntil([&]() {
return GetService()->sharing_manager().GetFocusedTabData().focus();
}));
base::RunLoop run_loop;
region_capture_controller().SetOnCaptureRegionForTesting(
run_loop.QuitClosure());
ExecuteJsTest();
run_loop.Run();
region_capture_controller().CancelCaptureRegion();
ContinueJsTest();
ASSERT_TRUE(base::test::RunUntil([&]() {
return !region_capture_controller().IsCaptureRegionInProgressForTesting();
}));
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCaptureRegionNoFocus) {
browser_activator().SetMode(BrowserActivator::Mode::kFirst);
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
TrackGlicInstanceWithId(GetGlicInstance()->id());
ExecuteJsTest();
CreateIncognitoBrowser();
CloseBrowserAsynchronously(browser());
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testCaptureRegionCalledTwice) {
ASSERT_TRUE(AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents));
ASSERT_TRUE(base::test::RunUntil([&]() {
return GetService()->sharing_manager().GetFocusedTabData().focus();
}));
base::RunLoop run_loop;
int capture_region_calls = 0;
region_capture_controller().SetOnCaptureRegionForTesting(
base::BindLambdaForTesting([&]() {
capture_region_calls++;
if (capture_region_calls == 2) {
run_loop.Quit();
}
}));
ExecuteJsTest();
run_loop.Run();
region_capture_controller().OnRegionSelected({10, 20, 30, 40});
ContinueJsTest();
ASSERT_TRUE(base::test::RunUntil([&]() {
return !region_capture_controller().IsCaptureRegionInProgressForTesting();
}));
}
IN_PROC_BROWSER_TEST_P(GlicApiTestHibernateAllOnMemoryPressure,
testHibernateAllOnMemoryPressure) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Only supported in multi-instance mode.";
}
GetInstanceCoordinator().SetWarmingEnabledForTesting(true);
GlicInstanceImpl* instance1 = OpenGlicInNewTabAndGetInstance(0, kFirstTab);
GlicInstanceImpl* instance2 = OpenGlicInNewTabAndGetInstance(1, kSecondTab);
GlicInstanceImpl* instance3 = OpenGlicInNewTabAndGetInstance(2, kThirdTab);
RunTestSequence(CloseGlic());
ASSERT_TRUE(base::test::RunUntil([&]() { return !instance3->IsShowing(); }));
ASSERT_FALSE(instance3->IsHibernated());
browser()->tab_strip_model()->ActivateTabAt(0);
TrackGlicInstanceWithTabIndex(0);
ASSERT_TRUE(base::test::RunUntil([&]() { return instance1->IsShowing(); }));
ASSERT_TRUE(GetInstanceCoordinator().HasWarmedInstanceForTesting());
base::MemoryPressureListener::NotifyMemoryPressure(
base::MEMORY_PRESSURE_LEVEL_CRITICAL);
ASSERT_TRUE(base::test::RunUntil([&]() {
return instance2->IsHibernated() && instance3->IsHibernated();
}));
ASSERT_FALSE(GetInstanceCoordinator().HasWarmedInstanceForTesting());
ASSERT_TRUE(instance1->IsShowing());
ASSERT_FALSE(instance1->IsHibernated());
}
IN_PROC_BROWSER_TEST_P(GlicApiTestHibernateAllAggressiveOnMemoryPressure,
testHibernateAllAggressiveOnMemoryPressure) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Only supported in multi-instance mode.";
}
GetInstanceCoordinator().SetWarmingEnabledForTesting(true);
GlicInstanceImpl* instance1 = OpenGlicInNewTabAndGetInstance(0, kFirstTab);
ASSERT_TRUE(instance1->IsShowing());
ASSERT_TRUE(GetInstanceCoordinator().HasWarmedInstanceForTesting());
WebUIStateListener listener(&instance1->host());
base::MemoryPressureListener::NotifyMemoryPressure(
base::MEMORY_PRESSURE_LEVEL_CRITICAL);
ASSERT_FALSE(GetInstanceCoordinator().HasWarmedInstanceForTesting());
tabs::TabInterface* tab = browser()->tab_strip_model()->GetTabAtIndex(0);
ASSERT_TRUE(base::test::RunUntil([&]() {
return instance1->IsHibernated() &&
!GlicSidePanelCoordinator::IsGlicSidePanelActive(tab);
}));
ASSERT_FALSE(instance1->IsShowing());
}
IN_PROC_BROWSER_TEST_P(GlicApiTest, testPanelWillOpenBeforeClientReady) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Only supported in multi-instance mode.";
}
RunTestSequence(
InstrumentTab(kFirstTab),
OpenGlicWindow(GlicWindowMode::kDetached, GlicInstrumentMode::kNone));
Host::PanelWillOpenOptions options;
options.conversation_id = "test_conversation_id";
ASSERT_FALSE(GetHost()->IsReady());
GetHost()->PanelWillOpen(mojom::InvocationSource::kTopChromeButton,
std::move(options));
ExecuteJsTest();
}
class GlicGetHostCapabilityApiTest : public GlicApiTestWithOneTab {
public:
GlicGetHostCapabilityApiTest() {
const bool enable_features = GetParam().enable_scroll_to_pdf;
if (enable_features) {
std::vector<base::test::FeatureRefAndParams> enabled_features = {
{features::kGlicScrollTo, {{"glic-scroll-to-pdf", "true"}}},
{features::kGlicPanelResetSizeAndLocationOnOpen, {}}};
scoped_feature_list_.InitWithFeaturesAndParameters(
enabled_features,
{});
} else {
scoped_feature_list_.InitWithFeaturesAndParameters(
{},
{});
}
}
~GlicGetHostCapabilityApiTest() override = default;
private:
base::test::ScopedFeatureList scoped_feature_list_;
};
IN_PROC_BROWSER_TEST_P(GlicGetHostCapabilityApiTest, testGetHostCapabilities) {
const bool enable_features = GetParam().enable_scroll_to_pdf;
if (enable_features) {
#if BUILDFLAG(ENABLE_PDF)
ExecuteJsTest({
.params = base::Value(base::Value::List().Append(
base::to_underlying(mojom::HostCapability::kScrollToPdf))),
});
#else
ExecuteJsTest();
#endif
} else {
ExecuteJsTest();
}
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetPageMetadata) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetPageMetadataInvalidTabId) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetPageMetadataEmptyNames) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
testGetPageMetadataMultipleSubscriptions) {
ExecuteJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetPageMetadataUpdates) {
ExecuteJsTest();
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents);
const char* script =
"document.querySelector('meta[name=\"author\"]').setAttribute('content', "
"'Ruth')";
ASSERT_TRUE(content::ExecJs(web_contents, script));
ContinueJsTest();
}
#if BUILDFLAG(IS_WIN)
#define MAYBE_testGetPageMetadataOnNavigation testGetPageMetadataOnNavigation
#else
#define MAYBE_testGetPageMetadataOnNavigation \
DISABLED_testGetPageMetadataOnNavigation
#endif
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
MAYBE_testGetPageMetadataOnNavigation) {
ExecuteJsTest();
RunTestSequence(NavigateWebContents(
kFirstTab,
InProcessBrowserTest::embedded_test_server()->GetURL("/title1.html")));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testGetPageMetadataTabDestroyed) {
SKIP_TEST_FOR_MULTI_INSTANCE();
ExecuteJsTest();
content::WebContents* web_contents_to_close =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(AddTabAtIndex(0, GURL("about:blank"), ui::PAGE_TRANSITION_TYPED));
browser()->tab_strip_model()->CloseWebContentsAt(
browser()->tab_strip_model()->GetIndexOfWebContents(
web_contents_to_close),
CLOSE_NONE);
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab, testAdditionalContext) {
ExecuteJsTest();
auto context = mojom::AdditionalContext::New();
std::vector<mojom::AdditionalContextPartPtr> parts;
{
auto context_data = mojom::ContextData::New();
context_data->mime_type = "text/plain";
context_data->data =
mojo_base::BigBuffer(std::vector<uint8_t>{'t', 'e', 's', 't'});
parts.push_back(
mojom::AdditionalContextPart::NewData(std::move(context_data)));
}
{
auto screenshot = mojom::Screenshot::New();
screenshot->width_pixels = 10;
screenshot->height_pixels = 20;
screenshot->mime_type = "image/png";
screenshot->data = std::vector<uint8_t>{1, 2, 3, 4};
screenshot->origin_annotations = mojom::ImageOriginAnnotations::New();
parts.push_back(
mojom::AdditionalContextPart::NewScreenshot(std::move(screenshot)));
}
auto* const element =
ui::ElementTracker::GetElementTracker()->GetElementInAnyContext(
kFirstTab);
auto* web_contents = AsInstrumentedWebContents(element)->web_contents();
context->name = "part with everything";
context->tab_id = GetTabId(web_contents);
context->origin = url::Origin::Create(web_contents->GetLastCommittedURL());
context->frameUrl = web_contents->GetLastCommittedURL();
{
auto web_page_data = mojom::WebPageData::New();
web_page_data->main_document = mojom::DocumentData::New();
web_page_data->main_document->origin =
url::Origin::Create(context->frameUrl.value());
web_page_data->main_document->inner_text = "some inner text";
web_page_data->main_document->inner_text_truncated = false;
parts.push_back(
mojom::AdditionalContextPart::NewWebPageData(std::move(web_page_data)));
}
{
parts.push_back(mojom::AdditionalContextPart::NewAnnotatedPageData(
mojom::AnnotatedPageData::New()));
}
{
auto pdf_data = mojom::PdfDocumentData::New();
pdf_data->origin = url::Origin::Create(context->frameUrl.value());
pdf_data->size_limit_exceeded = false;
pdf_data->pdf_data = std::vector<uint8_t>{'p', 'd', 'f'};
parts.push_back(
mojom::AdditionalContextPart::NewPdfDocumentData(std::move(pdf_data)));
}
{
auto tab_data = mojom::TabData::New();
tab_data->tab_id = 1;
tab_data->window_id = 2;
tab_data->url = GURL("https://google.com");
auto tab_context = mojom::TabContext::New();
tab_context->tab_data = std::move(tab_data);
parts.push_back(
mojom::AdditionalContextPart::NewTabContext(std::move(tab_context)));
}
context->parts = std::move(parts);
GetService()->SendAdditionalContext(tabs::TabHandle(GetTabId(web_contents)),
std::move(context));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithOneTab,
DISABLED_testGetPageMetadataWebContentsChanged) {
ExecuteJsTest();
content::WebContents* web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(web_contents);
resource_coordinator::TabLifecycleUnitExternal::FromWebContents(web_contents)
->DiscardTab(::mojom::LifecycleUnitDiscardReason::PROACTIVE);
ASSERT_TRUE(
base::test::RunUntil([&]() { return web_contents->WasDiscarded(); }));
browser()->tab_strip_model()->ActivateTabAt(
browser()->tab_strip_model()->active_index());
content::WebContents* new_web_contents =
browser()->tab_strip_model()->GetActiveWebContents();
ASSERT_TRUE(new_web_contents);
ASSERT_TRUE(content::WaitForLoadStop(new_web_contents));
const char* script =
"document.querySelector('meta[name=\"author\"]').setAttribute('content', "
"'Ruth')";
ASSERT_TRUE(content::ExecJs(new_web_contents, script));
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestWithGeminiActOnWebPolicy,
testNotifyActOnWebCapabilityChanged) {
policy::ScopedManagementServiceOverrideForTesting
scoped_management_service_override(
policy::ManagementServiceFactory::GetForProfile(GetProfile()),
policy::EnterpriseManagementAuthority::CLOUD);
UpdateGeminiActOnWebPolicy(
glic::prefs::GlicActuationOnWebPolicyState::kEnabled);
ExecuteJsTest();
UpdateGeminiActOnWebPolicy(
glic::prefs::GlicActuationOnWebPolicyState::kDisabled);
ContinueJsTest();
}
IN_PROC_BROWSER_TEST_P(GlicApiTestHibernateOnMemoryUsage,
testHibernateOnMemoryUsage) {
if (!GetParam().multi_instance) {
GTEST_SKIP() << "Only supported in multi-instance mode.";
}
RunTestSequence(OpenGlicWindow(GlicWindowMode::kDetached,
GlicInstrumentMode::kHostAndContents),
RegisterConversation("test_id"));
GlicInstanceImpl* instance = GetGlicInstanceImpl();
base::HistogramTester histogram_tester;
RunTestSequence(CloseGlic());
ASSERT_TRUE(base::test::RunUntil([&]() { return instance->IsHibernated(); }));
histogram_tester.ExpectTotalCount("Glic.Instance.MemoryUsageAtThreshold", 1);
}
INSTANTIATE_TEST_SUITE_P(
,
GlicGetHostCapabilityApiTest,
testing::Values(TestParams{}, TestParams{.enable_scroll_to_pdf = true}),
&WithTestParams::PrintTestVariant);
auto DefaultTestParamSet() {
return testing::Values(TestParams{.multi_instance = false},
TestParams{.multi_instance = true});
}
INSTANTIATE_TEST_SUITE_P(
,
GlicApiTestWithOneTab,
#if defined(SLOW_BINARY) || BUILDFLAG(IS_CHROMEOS)
testing::Values(TestParams{.multi_instance = false}),
#else
DefaultTestParamSet(),
#endif
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(
,
GlicApiTest,
#if BUILDFLAG(IS_CHROMEOS)
testing::Values(TestParams{.multi_instance = false}),
#else
DefaultTestParamSet(),
#endif
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestWithDefaultTabContextEnabled,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestWithDefaultTabContextDisabled,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestWithMqlsIdGetterEnabled,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestWithMqlsIdGetterDisabled,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(
,
GlicApiTestWithOneTabAndPreloading,
testing::Values(TestParams{.multi_instance = false}),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestWithOneTabAndContextualCueing,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestWithFastTimeout,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestRuntimeFeatureOff,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestSystemSettingsTest,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestUserStatusCheckTest,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
MAYBE_GlicApiTestWithOneTabMoreDebounceDelay,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestWithWebActuationSettingDisabled,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestWithWebActuationSettingEnabled,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestWithGeminiActOnWebPolicy,
DefaultTestParamSet(),
&WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestHibernateAllOnMemoryPressure,
DefaultTestParamSet(),
WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestHibernateAllAggressiveOnMemoryPressure,
DefaultTestParamSet(),
WithTestParams::PrintTestVariant);
INSTANTIATE_TEST_SUITE_P(,
GlicApiTestHibernateOnMemoryUsage,
DefaultTestParamSet(),
WithTestParams::PrintTestVariant);
}
}