#include "base/test/test_future.h"
#include "chrome/browser/actor/actor_test_util.h"
#include "chrome/browser/actor/tools/tool_request.h"
#include "chrome/browser/actor/tools/tools_test_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
#include "chrome/common/actor.mojom.h"
#include "chrome/test/base/test_browser_window.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "third_party/blink/public/common/page/page_zoom.h"
using base::test::TestFuture;
using content::EvalJs;
using content::ExecJs;
using content::GetDOMNodeId;
namespace actor {
namespace {
class ActorScrollToolBrowserTest : public ActorToolsTest {
public:
ActorScrollToolBrowserTest() = default;
~ActorScrollToolBrowserTest() override = default;
void SetUpOnMainThread() override {
ActorToolsTest::SetUpOnMainThread();
ASSERT_TRUE(embedded_test_server()->Start());
ASSERT_TRUE(embedded_https_test_server().Start());
}
};
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest,
ScrollTool_FailOnInvalidNodeID) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
float scroll_offset_y = 50;
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), kNonExistentContentNodeId,
0, scroll_offset_y);
ActResultFuture result_fail;
actor_task().Act(ToRequestList(action), result_fail.GetCallback());
ExpectErrorResult(result_fail, mojom::ActionResultCode::kInvalidDomNodeId);
EXPECT_EQ(0, EvalJs(web_contents(), "window.scrollY"));
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest,
ScrollTool_ScrollPageVertical) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset_y = 50;
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), std::nullopt,
0, scroll_offset_y);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(scroll_offset_y, EvalJs(web_contents(), "window.scrollY"));
}
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), std::nullopt,
0, scroll_offset_y);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(2 * scroll_offset_y, EvalJs(web_contents(), "window.scrollY"));
}
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest,
ScrollTool_ScrollPageHorizontal) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset_x = 50;
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(),
std::nullopt, scroll_offset_x,
0);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(scroll_offset_x, EvalJs(web_contents(), "window.scrollX"));
}
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(),
std::nullopt, scroll_offset_x,
0);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(2 * scroll_offset_x, EvalJs(web_contents(), "window.scrollX"));
}
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest, ScrollTool_ScrollElement) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset_x = 50;
int scroll_offset_y = 80;
int scroller = GetDOMNodeId(*main_frame(), "#scroller").value();
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller, scroll_offset_x,
0);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(scroll_offset_x,
EvalJs(web_contents(),
"document.getElementById('scroller').scrollLeft"));
}
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_y);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(scroll_offset_y,
EvalJs(web_contents(),
"document.getElementById('scroller').scrollTop"));
}
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest, ScrollTool_NonScrollable) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset_y = 80;
int scroller = GetDOMNodeId(*main_frame(), "#nonscroll").value();
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_y);
ActResultFuture result;
actor_task().Act(ToRequestList(action), result.GetCallback());
ExpectErrorResult(result,
mojom::ActionResultCode::kScrollTargetNotUserScrollable);
EXPECT_EQ(0, EvalJs(web_contents(),
"document.getElementById('nonscroll').scrollTop"));
EXPECT_EQ(0, EvalJs(web_contents(), "window.scrollY"));
}
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest,
ScrollTool_OffscreenScrollable) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
ASSERT_EQ(0, EvalJs(web_contents(), "window.scrollY"));
int scroll_offset_y = 80;
int scroller = GetDOMNodeId(*main_frame(), "#offscreenscroller").value();
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_y);
ActResultFuture result;
actor_task().Act(ToRequestList(action), result.GetCallback());
ExpectOkResult(result);
EXPECT_EQ(scroll_offset_y,
EvalJs(web_contents(),
"document.getElementById('offscreenscroller').scrollTop"));
EXPECT_GT(EvalJs(web_contents(), "window.scrollY"), 0);
}
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest, ScrollTool_OneAxisScroller) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset = 80;
int scroller = GetDOMNodeId(*main_frame(), "#horizontalscroller").value();
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset);
ActResultFuture result;
actor_task().Act(ToRequestList(action), result.GetCallback());
ExpectErrorResult(result,
mojom::ActionResultCode::kScrollTargetNotUserScrollable);
EXPECT_EQ(
0, EvalJs(web_contents(),
"document.getElementById('horizontalscroller').scrollTop"));
EXPECT_EQ(0, EvalJs(web_contents(), "window.scrollY"));
}
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller, scroll_offset,
0);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(
scroll_offset,
EvalJs(web_contents(),
"document.getElementById('horizontalscroller').scrollLeft"));
}
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest, ScrollTool_BrowserZoom) {
double level = blink::ZoomFactorToZoomLevel(1.5);
browser()->profile()->GetZoomLevelPrefs()->SetDefaultZoomLevelPref(level);
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset_dips = 60;
int expected_offset_css = 40;
int scroller = GetDOMNodeId(*main_frame(), "#scroller").value();
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_dips);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(expected_offset_css,
EvalJs(web_contents(),
"document.getElementById('scroller').scrollTop"));
}
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest, ScrollTool_CSSZoom) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset_dips = 60;
int expected_offset_css = 120;
int scroller = GetDOMNodeId(*main_frame(), "#zoomedscroller").value();
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_dips);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(expected_offset_css,
EvalJs(web_contents(),
"document.getElementById('zoomedscroller').scrollTop"));
}
}
class ActorToolsTestDSF2 : public ActorScrollToolBrowserTest {
public:
ActorToolsTestDSF2() = default;
explicit ActorToolsTestDSF2(const ActorToolsTestDSF2&) = delete;
ActorToolsTestDSF2& operator=(const ActorToolsTestDSF2&) = delete;
~ActorToolsTestDSF2() override = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
ActorToolsTest::SetUpCommandLine(command_line);
command_line->RemoveSwitch(switches::kForceDeviceScaleFactor);
command_line->AppendSwitchASCII(switches::kForceDeviceScaleFactor, "2");
}
};
IN_PROC_BROWSER_TEST_F(ActorToolsTestDSF2, ScrollTool_ScrollDSF) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset_dips = 40;
int expected_offset_css = 40;
int scroller = GetDOMNodeId(*main_frame(), "#scroller").value();
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_dips);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(expected_offset_css,
EvalJs(web_contents(),
"document.getElementById('scroller').scrollTop"));
}
}
IN_PROC_BROWSER_TEST_F(ActorToolsTestDSF2, ScrollTool_BrowserZoom) {
double level = blink::ZoomFactorToZoomLevel(1.5);
browser()->profile()->GetZoomLevelPrefs()->SetDefaultZoomLevelPref(level);
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset_dips = 60;
int expected_offset_css = 40;
int scroller = GetDOMNodeId(*main_frame(), "#scroller").value();
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_dips);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(expected_offset_css,
EvalJs(web_contents(),
"document.getElementById('scroller').scrollTop"));
}
}
IN_PROC_BROWSER_TEST_F(ActorToolsTestDSF2, ScrollTool_CSSZoom) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
int scroll_offset_dips = 60;
int expected_offset_css = 120;
int scroller = GetDOMNodeId(*main_frame(), "#zoomedscroller").value();
{
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_dips);
ActResultFuture result_success;
actor_task().Act(ToRequestList(action), result_success.GetCallback());
ExpectOkResult(result_success);
EXPECT_EQ(expected_offset_css,
EvalJs(web_contents(),
"document.getElementById('zoomedscroller').scrollTop"));
}
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest,
ScrollTool_ZeroIdTargetsViewport) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
constexpr int kViewportId = 0;
float scroll_offset_y = 50;
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), kViewportId,
0, scroll_offset_y);
ActResultFuture result;
actor_task().Act(ToRequestList(action), result.GetCallback());
ExpectOkResult(result);
EXPECT_FLOAT_EQ(scroll_offset_y,
EvalJs(web_contents(), "window.scrollY").ExtractDouble());
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest,
ScrollTool_SmoothScrollSucceeds) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
float scroll_offset_y = 300;
int scroller = GetDOMNodeId(*main_frame(), "#smoothscroller").value();
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_y);
ActResultFuture result;
actor_task().Act(ToRequestList(action), result.GetCallback());
ExpectOkResult(result);
}
IN_PROC_BROWSER_TEST_F(ActorScrollToolBrowserTest,
ScrollTool_SmoothScrollAtExtent) {
const GURL url =
embedded_test_server()->GetURL("/actor/scrollable_page.html");
ASSERT_TRUE(content::NavigateToURL(web_contents(), url));
ASSERT_TRUE(ExecJs(web_contents(),
"document.querySelector('#smoothscroller').scrollTo({top:"
"10000, behavior:'instant'})"));
float scroll_offset_y = 300;
int scroller = GetDOMNodeId(*main_frame(), "#smoothscroller").value();
std::unique_ptr<ToolRequest> action =
MakeScrollRequest(*main_frame(), scroller,
0, scroll_offset_y);
ActResultFuture result;
actor_task().Act(ToRequestList(action), result.GetCallback());
ExpectErrorResult(result, mojom::ActionResultCode::kScrollOffsetDidNotChange);
}
}
}