| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/actor/tools/tools_test_util.h" |
| |
| #include "base/run_loop.h" |
| #include "base/test/bind.h" |
| #include "base/test/test_timeouts.h" |
| #include "chrome/browser/actor/actor_features.h" |
| #include "chrome/browser/actor/actor_keyed_service.h" |
| #include "chrome/browser/actor/actor_policy_checker.h" |
| #include "chrome/browser/actor/actor_test_util.h" |
| #include "chrome/browser/actor/execution_engine.h" |
| #include "chrome/browser/actor/site_policy.h" |
| #include "chrome/browser/actor/ui/event_dispatcher.h" |
| #include "chrome/browser/glic/glic_pref_names.h" |
| #include "chrome/browser/optimization_guide/browser_test_util.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/ui_features.h" |
| #include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h" |
| #include "chrome/common/buildflags.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/chrome_switches.h" |
| #include "chrome/test/base/chrome_test_utils.h" |
| #include "chrome/test/base/test_browser_window.h" |
| #include "components/optimization_guide/core/filters/optimization_hints_component_update_listener.h" |
| #include "components/tabs/public/tab_interface.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/test/browser_test_utils.h" |
| #include "content/public/test/test_navigation_observer.h" |
| #include "net/dns/mock_host_resolver.h" |
| #include "ui/display/display_switches.h" |
| #include "ui/gfx/geometry/rect_f.h" |
| |
| namespace actor { |
| |
| actor_login::Credential MakeTestCredential( |
| const std::u16string& username, |
| const GURL& url, |
| bool immediately_available_to_login) { |
| actor_login::Credential credential; |
| credential.username = username; |
| // TODO(crbug.com/441231531): Clarify the format. |
| credential.source_site_or_app = |
| base::UTF8ToUTF16(url.GetWithEmptyPath().spec()); |
| credential.request_origin = url::Origin::Create(url); |
| credential.type = actor_login::CredentialType::kPassword; |
| credential.immediatelyAvailableToLogin = immediately_available_to_login; |
| return credential; |
| } |
| |
| MockActorLoginService::MockActorLoginService() = default; |
| |
| MockActorLoginService::~MockActorLoginService() = default; |
| |
| void MockActorLoginService::GetCredentials( |
| tabs::TabInterface* tab, |
| actor_login::CredentialsOrErrorReply callback) { |
| std::move(callback).Run(credentials_); |
| } |
| |
| void MockActorLoginService::AttemptLogin( |
| tabs::TabInterface* tab, |
| const actor_login::Credential& credential, |
| bool should_store_permission, |
| actor_login::LoginStatusResultOrErrorReply callback) { |
| last_credential_used_ = credential; |
| last_permission_was_permanent_ = should_store_permission; |
| std::move(callback).Run(login_status_); |
| } |
| |
| void MockActorLoginService::SetCredentials( |
| const actor_login::CredentialsOrError& credentials) { |
| credentials_ = credentials; |
| } |
| |
| void MockActorLoginService::SetCredential( |
| const actor_login::Credential& credential) { |
| SetCredentials(std::vector{credential}); |
| } |
| |
| void MockActorLoginService::SetLoginStatus( |
| actor_login::LoginStatusResultOrError login_status) { |
| login_status_ = login_status; |
| } |
| |
| const std::optional<actor_login::Credential>& |
| MockActorLoginService::last_credential_used() const { |
| return last_credential_used_; |
| } |
| bool MockActorLoginService::last_permission_was_permanent() const { |
| return last_permission_was_permanent_; |
| } |
| |
| ActorToolsTest::ActorToolsTest() { |
| scoped_feature_list_.InitWithFeatures( |
| /*enabled_features=*/{features::kGlic, features::kTabstripComboButton, |
| features::kGlicActor}, |
| /*disabled_features=*/{features::kGlicWarming, kGlicActionAllowlist}); |
| } |
| |
| ActorToolsTest::~ActorToolsTest() = default; |
| |
| void ActorToolsTest::SetUpOnMainThread() { |
| InProcessBrowserTest::SetUpOnMainThread(); |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| |
| auto* actor_service = ActorKeyedService::Get(browser()->profile()); |
| actor_service->GetPolicyChecker().SetActOnWebForTesting( |
| ShouldForceActOnWeb()); |
| |
| auto execution_engine = CreateExecutionEngine(browser()->profile()); |
| auto event_dispatcher = |
| ui::NewUiEventDispatcher(actor_service->GetActorUiStateManager()); |
| auto actor_task = std::make_unique<ActorTask>(browser()->profile(), |
| std::move(execution_engine), |
| std::move(event_dispatcher)); |
| task_id_ = actor_service->AddActiveTask(std::move(actor_task)); |
| |
| // Optimization guide uses this histogram to signal initialization in tests. |
| optimization_guide::RetryForHistogramUntilCountReached( |
| &histogram_tester_for_init_, |
| "OptimizationGuide.HintsManager.HintCacheInitialized", 1); |
| |
| InitActionBlocklist(browser()->profile()); |
| |
| // Simulate the component loading, as the implementation checks it, but the |
| // actual list is set via the command line. |
| ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); |
| optimization_guide::OptimizationHintsComponentUpdateListener::GetInstance() |
| ->MaybeUpdateHintsComponent( |
| {base::Version("123"), |
| temp_dir_.GetPath().Append(FILE_PATH_LITERAL("dont_care"))}); |
| } |
| |
| void ActorToolsTest::SetUpCommandLine(base::CommandLine* command_line) { |
| InProcessBrowserTest::SetUpCommandLine(command_line); |
| SetUpBlocklist(command_line, "blocked.example.com"); |
| command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "1"); |
| } |
| |
| void ActorToolsTest::TearDownOnMainThread() { |
| // The ActorTask owned ExecutionEngine has a pointer to the profile, which |
| // must be released before the browser is torn down to avoid a dangling |
| // pointer. |
| ActorKeyedService::Get(browser()->profile())->ResetForTesting(); |
| } |
| |
| void ActorToolsTest::GoBack() { |
| content::TestNavigationObserver observer(web_contents()); |
| web_contents()->GetController().GoBack(); |
| observer.Wait(); |
| } |
| |
| void ActorToolsTest::TinyWait() { |
| base::RunLoop run_loop; |
| base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask( |
| FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); |
| run_loop.Run(); |
| } |
| |
| content::WebContents* ActorToolsTest::web_contents() { |
| return chrome_test_utils::GetActiveWebContents(this); |
| } |
| |
| tabs::TabInterface* ActorToolsTest::active_tab() { |
| return tabs::TabInterface::GetFromContents(web_contents()); |
| } |
| |
| content::RenderFrameHost* ActorToolsTest::main_frame() { |
| return web_contents()->GetPrimaryMainFrame(); |
| } |
| |
| ExecutionEngine& ActorToolsTest::execution_engine() { |
| return *actor_task().GetExecutionEngine(); |
| } |
| |
| ActorTask& ActorToolsTest::actor_task() const { |
| CHECK(task_id_); |
| return *ActorKeyedService::Get(browser()->profile())->GetTask(task_id_); |
| } |
| |
| std::unique_ptr<ExecutionEngine> ActorToolsTest::CreateExecutionEngine( |
| Profile* profile) { |
| return std::make_unique<ExecutionEngine>(profile); |
| } |
| |
| bool ActorToolsTest::ShouldForceActOnWeb() { |
| return true; |
| } |
| |
| gfx::RectF GetBoundingClientRect(content::RenderFrameHost& rfh, |
| std::string_view query) { |
| double width = |
| content::EvalJs( |
| &rfh, content::JsReplace( |
| "document.querySelector($1).getBoundingClientRect().width", |
| query)) |
| .ExtractDouble(); |
| double height = |
| content::EvalJs( |
| &rfh, content::JsReplace( |
| "document.querySelector($1).getBoundingClientRect().height", |
| query)) |
| .ExtractDouble(); |
| double x = |
| content::EvalJs( |
| &rfh, |
| content::JsReplace( |
| "document.querySelector($1).getBoundingClientRect().x", query)) |
| .ExtractDouble(); |
| double y = |
| content::EvalJs( |
| &rfh, |
| content::JsReplace( |
| "document.querySelector($1).getBoundingClientRect().y", query)) |
| .ExtractDouble(); |
| |
| return gfx::RectF(x, y, width, height); |
| } |
| |
| std::string DescribePaintStabilityMode(features::ActorPaintStabilityMode mode) { |
| switch (mode) { |
| case features::ActorPaintStabilityMode::kDisabled: |
| return "Disabled"; |
| case features::ActorPaintStabilityMode::kLogOnly: |
| return "LogOnly"; |
| case features::ActorPaintStabilityMode::kEnabled: |
| return "Enabled"; |
| } |
| } |
| |
| } // namespace actor |