#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/json/json_reader.h"
#include "base/location.h"
#include "base/path_service.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/test/trace_event_analyzer.h"
#include "build/build_config.h"
#include "build/chromeos_buildflags.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/tracing_controller.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "content/public/test/browser_test.h"
#include "extensions/browser/api/automation_internal/automation_event_router.h"
#include "extensions/common/api/automation_internal.h"
#include "extensions/common/switches.h"
#include "extensions/test/extension_test_message_listener.h"
#include "extensions/test/test_extension_dir.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/public/common/features.h"
#include "ui/accessibility/accessibility_switches.h"
#include "ui/accessibility/ax_node.h"
#include "ui/accessibility/ax_serializable_tree.h"
#include "ui/accessibility/ax_tree.h"
#include "ui/accessibility/ax_tree_serializer.h"
#include "ui/accessibility/ax_updates_and_events.h"
#include "ui/accessibility/tree_generator.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/display/display_switches.h"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/public/cpp/accelerators.h"
#include "ash/public/cpp/test/shell_test_api.h"
#include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h"
#include "ui/accessibility/ax_action_handler_registry.h"
#include "ui/display/manager/display_manager.h"
#include "ui/display/screen.h"
#include "ui/display/test/display_manager_test_api.h"
#endif
namespace extensions {
namespace {
constexpr char kManifestStub[] = …;
constexpr char kPersistentBackground[] = …;
constexpr char kServiceWorkerBackground[] = …;
constexpr char kPermissionsDefault[] = …;
#if BUILDFLAG(IS_CHROMEOS) || !defined(USE_AURA)
constexpr char kPermissionsWindows[] = R"(["windows"])";
#endif
static constexpr char kCommonScript[] = …;
}
ContextType;
class AutomationApiTest : public ExtensionApiTest { … };
class AutomationApiTestWithContextType
: public AutomationApiTest,
public testing::WithParamInterface<ContextType> { … };
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
class AutomationApiCanvasTest : public AutomationApiTestWithContextType { … };
#if defined(USE_AURA)
namespace {
static const char kDomain[] = …;
static const char kGotTree[] = …;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType,
TestRendererAccessibilityEnabled) { … }
IN_PROC_BROWSER_TEST_F(AutomationApiTest, ServiceWorker) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, SanityCheck) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, ImageLabels) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, Events) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, Actions) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, Location) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, Location2) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, BoundsForRange) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, LineStartOffsets) { … }
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#define MAYBE_ImageData …
#else
#define MAYBE_ImageData …
#endif
IN_PROC_BROWSER_TEST_P(AutomationApiCanvasTest, MAYBE_ImageData) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, TableProperties) { … }
#if BUILDFLAG(IS_MAC) || BUILDFLAG(IS_WIN)
#define MAYBE_CloseTab …
#else
#define MAYBE_CloseTab …
#endif
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, MAYBE_CloseTab) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, Find) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, Attributes) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, ReverseRelations) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, TreeChange) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, TreeChangeIndirect) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, DocumentSelection) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, HitTest) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, WordBoundaries) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, SentenceBoundaries) { … }
class AutomationApiTestWithLanguageDetection
: public AutomationApiTestWithContextType { … };
INSTANTIATE_TEST_SUITE_P(…);
INSTANTIATE_TEST_SUITE_P(…);
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithLanguageDetection,
DetectedLanguage) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType,
IgnoredNodesNotReturned) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, ForceLayout) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, Intents) { … }
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, EnumValidity) { … }
#endif
#if !defined(USE_AURA)
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, DesktopNotSupported) {
ASSERT_TRUE(CreateExtensionAndRunTest("desktop/desktop_not_supported.js",
kPermissionsWindows))
<< message_;
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
class AutomationApiFencedFrameTest : public AutomationApiTest {
protected:
AutomationApiFencedFrameTest() {
feature_list_.InitWithFeaturesAndParameters(
{{blink::features::kFencedFrames, {}},
{features::kPrivacySandboxAdsAPIsOverride, {}},
{blink::features::kFencedFramesAPIChanges, {}},
{blink::features::kFencedFramesDefaultMode, {}}},
{features::kSpareRendererForSitePerProcess});
}
~AutomationApiFencedFrameTest() override = default;
public:
base::test::ScopedFeatureList feature_list_;
};
IN_PROC_BROWSER_TEST_F(AutomationApiFencedFrameTest, DesktopFindInFencedframe) {
StartEmbeddedTestServer();
ASSERT_TRUE(RunExtensionTest("automation/tests/desktop/fencedframe",
{.extension_url = "focus_fencedframe.html"}))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, Desktop) {
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/desktop.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, DesktopInitialFocus) {
ASSERT_TRUE(CreateExtensionAndRunTest("desktop/initial_focus.js",
kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, DesktopFocusWeb) {
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/focus_web.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, DesktopFocusIframe) {
StartEmbeddedTestServer();
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/focus_iframe.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, DesktopHitTestIframe) {
StartEmbeddedTestServer();
ASSERT_TRUE(CreateExtensionAndRunTest("desktop/hit_test_iframe.js",
kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, DesktopFocusViews) {
AutomationManagerAura::GetInstance()->Enable();
ash::AcceleratorController::Get()->PerformActionIfEnabled(
ash::AcceleratorAction::kFocusShelf, {});
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/focus_views.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType,
DesktopGetNextTextMatch) {
StartEmbeddedTestServer();
ASSERT_TRUE(CreateExtensionAndRunTest("desktop/get_next_text_match.js",
kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_F(AutomationApiTest, LocationInWebView) {
StartEmbeddedTestServer();
ASSERT_TRUE(RunExtensionTest("automation/tests/webview",
{.launch_as_platform_app = true}))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, DesktopActions) {
AutomationManagerAura::GetInstance()->Enable();
ash::AcceleratorController::Get()->PerformActionIfEnabled(
ash::AcceleratorAction::kFocusShelf, {});
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/actions.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType,
DesktopHitTestOneDisplay) {
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/hit_test.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType,
DesktopHitTestPrimaryDisplay) {
ash::ShellTestApi shell_test_api;
display::test::DisplayManagerTestApi(shell_test_api.display_manager())
.UpdateDisplay("800x750,801+0-800x750");
ASSERT_EQ(2u, shell_test_api.display_manager()->GetNumDisplays());
display::test::DisplayManagerTestApi display_manager_test_api(
shell_test_api.display_manager());
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/hit_test.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType,
DesktopHitTestSecondaryDisplay) {
ash::ShellTestApi shell_test_api;
display::test::DisplayManagerTestApi(shell_test_api.display_manager())
.UpdateDisplay("800x750,801+0-800x750");
ASSERT_EQ(2u, shell_test_api.display_manager()->GetNumDisplays());
display::test::DisplayManagerTestApi display_manager_test_api(
shell_test_api.display_manager());
display::Screen* screen = display::Screen::GetScreen();
int64_t display2 = display_manager_test_api.GetSecondaryDisplay().id();
screen->SetDisplayForNewWindows(display2);
CreateBrowser(browser()->profile());
CloseBrowserSynchronously(browser());
SelectFirstBrowser();
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/hit_test.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, DesktopLoadTabs) {
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/load_tabs.js", kPermissionsWindows))
<< message_;
}
class AutomationApiTestWithDeviceScaleFactor
: public AutomationApiTestWithContextType {
protected:
void SetUpCommandLine(base::CommandLine* command_line) override {
AutomationApiTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(::switches::kForceDeviceScaleFactor, "2.0");
}
};
INSTANTIATE_TEST_SUITE_P(PersistentBackground,
AutomationApiTestWithDeviceScaleFactor,
::testing::Values(ContextType::kPersistentBackground));
INSTANTIATE_TEST_SUITE_P(ServiceWorker,
AutomationApiTestWithDeviceScaleFactor,
::testing::Values(ContextType::kServiceWorker));
using AutomationApiPlatformAppTestWithDeviceScaleFactor =
AutomationApiTestWithDeviceScaleFactor;
INSTANTIATE_TEST_SUITE_P(PlatformApp,
AutomationApiPlatformAppTestWithDeviceScaleFactor,
::testing::Values(ContextType::kNone));
IN_PROC_BROWSER_TEST_P(AutomationApiPlatformAppTestWithDeviceScaleFactor,
LocationScaled) {
StartEmbeddedTestServer();
ASSERT_TRUE(RunExtensionTest("automation/tests/location_scaled",
{.launch_as_platform_app = true}))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithDeviceScaleFactor, HitTest) {
StartEmbeddedTestServer();
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/hit_test.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, Position) {
StartEmbeddedTestServer();
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/position.js", kPermissionsWindows))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, AccessibilityFocus) {
StartEmbeddedTestServer();
ASSERT_TRUE(CreateExtensionAndRunTest("tabs/accessibility_focus.js"))
<< message_;
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType,
DISABLED_TextareaAppendPerf) {
StartEmbeddedTestServer();
{
base::RunLoop wait_for_tracing;
content::TracingController::GetInstance()->StartTracing(
base::trace_event::TraceConfig(
R"({"included_categories": ["accessibility"])"),
wait_for_tracing.QuitClosure());
wait_for_tracing.Run();
}
ASSERT_TRUE(CreateExtensionAndRunTest("tabs/textarea_append_perf.js"))
<< message_;
base::test::TestFuture<std::unique_ptr<std::string>> stop_tracing_future;
content::TracingController::GetInstance()->StopTracing(
content::TracingController::CreateStringEndpoint(
stop_tracing_future.GetCallback()));
std::optional<base::Value> trace_data =
base::JSONReader::Read(*stop_tracing_future.Take());
ASSERT_TRUE(trace_data && trace_data->is_dict());
const base::Value::List* trace_events =
trace_data->GetDict().FindList("traceEvents");
ASSERT_TRUE(trace_events);
int renderer_total_dur = 0;
int automation_total_dur = 0;
for (const base::Value& event : *trace_events) {
const std::string* cat = event.GetDict().FindString("cat");
if (!cat || *cat != "accessibility")
continue;
const std::string* name = event.GetDict().FindString("name");
if (!name)
continue;
std::optional<int> dur = event.GetDict().FindInt("dur");
if (!dur)
continue;
if (*name == "AutomationAXTreeWrapper::OnAccessibilityEvents")
automation_total_dur += *dur;
else if (*name == "RenderAccessibilityImpl::SendPendingAccessibilityEvents")
renderer_total_dur += *dur;
}
ASSERT_GT(automation_total_dur, 0);
ASSERT_GT(renderer_total_dur, 0);
LOG(INFO) << "Total duration in automation: " << automation_total_dur;
LOG(INFO) << "Total duration in renderer: " << renderer_total_dur;
ASSERT_LT(automation_total_dur, renderer_total_dur * 2);
}
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType, IframeNav) {
StartEmbeddedTestServer();
ASSERT_TRUE(
CreateExtensionAndRunTest("desktop/iframenav.js", kPermissionsWindows))
<< message_;
}
#if BUILDFLAG(IS_CHROMEOS) && defined(MEMORY_SANITIZER)
#define MAYBE_AddRemoveEventListeners …
#else
#define MAYBE_AddRemoveEventListeners …
#endif
IN_PROC_BROWSER_TEST_F(AutomationApiTest, MAYBE_AddRemoveEventListeners) {
StartEmbeddedTestServer();
ASSERT_TRUE(
RunExtensionTest("automation/tests/desktop",
{.extension_url = "add_remove_event_listeners.html"}))
<< message_;
}
class AutomationApiTestWithMockedSourceRenderer
: public AutomationApiTestWithContextType,
public ui::AXActionHandlerObserver {
protected:
void InterceptAXActions() {
ui::AXActionHandlerRegistry* registry =
ui::AXActionHandlerRegistry ::GetInstance();
ASSERT_TRUE(registry);
registry->AddObserver(this);
}
private:
void PerformAction(const ui::AXActionData& action_data) override {
extensions::AutomationEventRouter* router =
extensions::AutomationEventRouter::GetInstance();
ASSERT_TRUE(router);
EXPECT_EQ(action_data.action, ax::mojom::Action::kScrollBackward);
router->DispatchActionResult(action_data, true);
}
};
INSTANTIATE_TEST_SUITE_P(PersistentBackground,
AutomationApiTestWithMockedSourceRenderer,
::testing::Values(ContextType::kPersistentBackground));
INSTANTIATE_TEST_SUITE_P(ServiceWorker,
AutomationApiTestWithMockedSourceRenderer,
::testing::Values(ContextType::kServiceWorker));
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithMockedSourceRenderer,
ActionResult) {
StartEmbeddedTestServer();
InterceptAXActions();
ASSERT_TRUE(CreateExtensionAndRunTest("desktop/action_result.js",
kPermissionsWindows))
<< message_;
}
#endif
#if BUILDFLAG(IS_CHROMEOS)
#if BUILDFLAG(IS_CHROMEOS_LACROS)
#define MAYBE_HitTestMultipleWindows …
#else
#define MAYBE_HitTestMultipleWindows …
#endif
IN_PROC_BROWSER_TEST_P(AutomationApiTestWithContextType,
MAYBE_HitTestMultipleWindows) {
StartEmbeddedTestServer();
ASSERT_TRUE(CreateExtensionAndRunTest("desktop/hit_test_multiple_windows.js",
kPermissionsWindows))
<< message_;
}
#endif
}