|  | // Copyright 2020 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "base/test/scoped_feature_list.h" | 
|  | #include "base/test/test_timeouts.h" | 
|  | #include "content/browser/renderer_host/render_widget_host_impl.h" | 
|  | #include "content/public/browser/render_view_host.h" | 
|  | #include "content/public/browser/web_contents.h" | 
|  | #include "content/public/common/content_features.h" | 
|  | #include "content/public/common/content_switches.h" | 
|  | #include "content/public/test/browser_test.h" | 
|  | #include "content/public/test/browser_test_utils.h" | 
|  | #include "content/public/test/content_browser_test.h" | 
|  | #include "content/public/test/content_browser_test_utils.h" | 
|  | #include "content/public/test/hit_test_region_observer.h" | 
|  | #include "content/public/test/test_navigation_observer.h" | 
|  | #include "content/shell/browser/shell.h" | 
|  | #include "net/dns/mock_host_resolver.h" | 
|  | #include "net/test/embedded_test_server/controllable_http_response.h" | 
|  | #include "net/test/embedded_test_server/embedded_test_server.h" | 
|  | #include "url/gurl.h" | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | class TextFragmentAnchorBrowserTest : public ContentBrowserTest { | 
|  | public: | 
|  | TextFragmentAnchorBrowserTest() { | 
|  | feature_list_.InitAndEnableFeature(features::kDocumentPolicy); | 
|  | } | 
|  |  | 
|  | protected: | 
|  | void SetUpOnMainThread() override { | 
|  | host_resolver()->AddRule("*", "127.0.0.1"); | 
|  | } | 
|  |  | 
|  | void SetUpCommandLine(base::CommandLine* command_line) override { | 
|  | ContentBrowserTest::SetUpCommandLine(command_line); | 
|  | command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures, | 
|  | "TextFragmentIdentifiers"); | 
|  | } | 
|  |  | 
|  | // Simulates a click on the middle of the DOM element with the given |id|. | 
|  | void ClickElementWithId(WebContents* web_contents, const std::string& id) { | 
|  | // Get the center coordinates of the DOM element. | 
|  | const int x = EvalJs(web_contents, | 
|  | JsReplace("const bounds = " | 
|  | "document.getElementById($1)." | 
|  | "getBoundingClientRect();" | 
|  | "Math.floor(bounds.left + bounds.width / 2)", | 
|  | id)) | 
|  | .ExtractInt(); | 
|  | const int y = EvalJs(web_contents, | 
|  | JsReplace("const bounds = " | 
|  | "document.getElementById($1)." | 
|  | "getBoundingClientRect();" | 
|  | "Math.floor(bounds.top + bounds.height / 2)", | 
|  | id)) | 
|  | .ExtractInt(); | 
|  |  | 
|  | SimulateMouseClickAt(web_contents, 0, blink::WebMouseEvent::Button::kLeft, | 
|  | gfx::Point(x, y)); | 
|  | } | 
|  |  | 
|  | void WaitForPageLoad(WebContents* contents) { | 
|  | EXPECT_TRUE(WaitForLoadStop(contents)); | 
|  | EXPECT_TRUE(WaitForRenderFrameReady(contents->GetMainFrame())); | 
|  | } | 
|  |  | 
|  | RenderWidgetHostImpl* GetWidgetHost() { | 
|  | return RenderWidgetHostImpl::From( | 
|  | shell()->web_contents()->GetRenderViewHost()->GetWidget()); | 
|  | } | 
|  |  | 
|  | base::test::ScopedFeatureList feature_list_; | 
|  | }; | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, EnabledOnUserNavigation) { | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url(embedded_test_server()->GetURL("/target_text_link.html")); | 
|  | GURL target_text_url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#:~:text=text")); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  |  | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | TestNavigationObserver observer(main_contents); | 
|  | RenderFrameSubmissionObserver frame_observer(main_contents); | 
|  |  | 
|  | // We need to wait until hit test data is available. | 
|  | HitTestRegionObserver hittest_observer(GetWidgetHost()->GetFrameSinkId()); | 
|  | hittest_observer.WaitForHitTestData(); | 
|  |  | 
|  | ClickElementWithId(main_contents, "link"); | 
|  | observer.Wait(); | 
|  | EXPECT_EQ(target_text_url, main_contents->GetLastCommittedURL()); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  | frame_observer.WaitForScrollOffsetAtTop( | 
|  | /*expected_scroll_offset_at_top=*/false); | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  | EXPECT_EQ(true, EvalJs(main_contents, "did_scroll;")); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, | 
|  | EnabledOnBrowserNavigation) { | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#:~:text=text")); | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | RenderFrameSubmissionObserver frame_observer(main_contents); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  | frame_observer.WaitForScrollOffsetAtTop( | 
|  | /*expected_scroll_offset_at_top=*/false); | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  | EXPECT_EQ(true, EvalJs(main_contents, "did_scroll;")); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, | 
|  | EnabledOnUserGestureScriptNavigation) { | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url(embedded_test_server()->GetURL("/empty.html")); | 
|  | GURL target_text_url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#:~:text=text")); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  |  | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | TestNavigationObserver observer(main_contents); | 
|  | RenderFrameSubmissionObserver frame_observer(main_contents); | 
|  |  | 
|  | // ExecuteScript executes with a user gesture | 
|  | EXPECT_TRUE(ExecuteScript(main_contents, | 
|  | "location = '" + target_text_url.spec() + "';")); | 
|  | observer.Wait(); | 
|  | EXPECT_EQ(target_text_url, main_contents->GetLastCommittedURL()); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  | frame_observer.WaitForScrollOffsetAtTop( | 
|  | /*expected_scroll_offset_at_top=*/false); | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  | EXPECT_EQ(true, EvalJs(main_contents, "did_scroll;")); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, | 
|  | DisabledOnScriptNavigation) { | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url(embedded_test_server()->GetURL("/empty.html")); | 
|  | GURL target_text_url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#:~:text=text")); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  |  | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | TestNavigationObserver observer(main_contents); | 
|  | EXPECT_TRUE(ExecuteScriptWithoutUserGesture( | 
|  | main_contents, "location = '" + target_text_url.spec() + "';")); | 
|  | observer.Wait(); | 
|  | EXPECT_EQ(target_text_url, main_contents->GetLastCommittedURL()); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  |  | 
|  | // Wait a short amount of time to ensure the page does not scroll. | 
|  | base::RunLoop run_loop; | 
|  | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 
|  | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); | 
|  | run_loop.Run(); | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  | EXPECT_EQ(false, EvalJs(main_contents, "did_scroll;")); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, | 
|  | DisabledOnScriptHistoryNavigation) { | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL target_text_url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#:~:text=text")); | 
|  | GURL url(embedded_test_server()->GetURL("/empty.html")); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), target_text_url)); | 
|  |  | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | RenderFrameSubmissionObserver frame_observer(main_contents); | 
|  | frame_observer.WaitForScrollOffsetAtTop(false); | 
|  |  | 
|  | // Scroll the page back to top so scroll restoration does not scroll the | 
|  | // target back into view. | 
|  | EXPECT_TRUE(ExecuteScript(main_contents, "window.scrollTo(0, 0)")); | 
|  | frame_observer.WaitForScrollOffsetAtTop(true); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  |  | 
|  | TestNavigationObserver observer(main_contents); | 
|  | EXPECT_TRUE(ExecuteScriptWithoutUserGesture(main_contents, "history.back()")); | 
|  | observer.Wait(); | 
|  | EXPECT_EQ(target_text_url, main_contents->GetLastCommittedURL()); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  |  | 
|  | // Wait a short amount of time to ensure the page does not scroll. | 
|  | base::RunLoop run_loop; | 
|  | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 
|  | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); | 
|  | run_loop.Run(); | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  |  | 
|  | // Note: we use a scroll handler in the page to check whether any scrolls | 
|  | // happened at all, rather than checking the current scroll offset. This is | 
|  | // to ensure that if the offset is reset back to the top for other reasons | 
|  | // (e.g. history restoration) we still fail this test. See | 
|  | // https://crbug.com/1042986 for why this matters. | 
|  | EXPECT_EQ(false, EvalJs(main_contents, "did_scroll;")); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, | 
|  | EnabledOnSameDocumentBrowserNavigation) { | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#:~:text=text")); | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | RenderFrameSubmissionObserver frame_observer(main_contents); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  | frame_observer.WaitForScrollOffsetAtTop(false); | 
|  |  | 
|  | // Scroll the page back to top. Make sure we reset the |did_scroll| variable | 
|  | // we'll use below to ensure the same-document navigation invokes the text | 
|  | // fragment. | 
|  | EXPECT_TRUE(ExecuteScript(main_contents, "window.scrollTo(0, 0)")); | 
|  | frame_observer.WaitForScrollOffsetAtTop(true); | 
|  | EXPECT_TRUE(ExecJs(main_contents, "did_scroll = false;")); | 
|  |  | 
|  | // Perform a same-document browser initiated navigation | 
|  | GURL same_doc_url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#:~:text=some")); | 
|  | EXPECT_TRUE(NavigateToURL(shell(), same_doc_url)); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  | frame_observer.WaitForScrollOffsetAtTop( | 
|  | /*expected_scroll_offset_at_top=*/false); | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  | EXPECT_EQ(true, EvalJs(main_contents, "did_scroll;")); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, | 
|  | DisabledOnSameDocumentScriptNavigation) { | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url( | 
|  | embedded_test_server()->GetURL("/scrollable_page_with_content.html")); | 
|  | GURL target_text_url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#:~:text=some")); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  |  | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | TestNavigationObserver observer(main_contents); | 
|  | EXPECT_TRUE(ExecuteScriptWithoutUserGesture( | 
|  | main_contents, "location = '" + target_text_url.spec() + "';")); | 
|  | observer.Wait(); | 
|  | EXPECT_EQ(target_text_url, main_contents->GetLastCommittedURL()); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  |  | 
|  | // Wait a short amount of time to ensure the page does not scroll. | 
|  | base::RunLoop run_loop; | 
|  | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 
|  | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); | 
|  | run_loop.Run(); | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  | EXPECT_EQ(false, EvalJs(main_contents, "did_scroll;")); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, EnabledByDocumentPolicy) { | 
|  | net::test_server::ControllableHttpResponse response(embedded_test_server(), | 
|  | "/target.html"); | 
|  |  | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url(embedded_test_server()->GetURL("/target.html#:~:text=text")); | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | RenderFrameSubmissionObserver frame_observer(main_contents); | 
|  |  | 
|  | // Load the target document | 
|  | TestNavigationManager navigation_manager(main_contents, url); | 
|  | shell()->LoadURL(url); | 
|  |  | 
|  | // Start navigation | 
|  | EXPECT_TRUE(navigation_manager.WaitForRequestStart()); | 
|  | navigation_manager.ResumeNavigation(); | 
|  |  | 
|  | // Send Document-Policy header | 
|  | response.WaitForRequest(); | 
|  | response.Send( | 
|  | "HTTP/1.1 200 OK\r\n" | 
|  | "Content-Type: text/html; charset=utf-8\r\n" | 
|  | "Document-Policy: no-force-load-at-top\r\n" | 
|  | "\r\n" | 
|  | "<script>" | 
|  | "  let did_scroll = false;" | 
|  | "  window.addEventListener('scroll', () => {" | 
|  | "    did_scroll = true;" | 
|  | "  });" | 
|  | "</script>" | 
|  | "<p style='position: absolute; top: 10000px;'>Some text</p>"); | 
|  | response.Done(); | 
|  |  | 
|  | EXPECT_TRUE(navigation_manager.WaitForResponse()); | 
|  | navigation_manager.ResumeNavigation(); | 
|  | navigation_manager.WaitForNavigationFinished(); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  | frame_observer.WaitForScrollOffsetAtTop( | 
|  | /*expected_scroll_offset_at_top=*/false); | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  | EXPECT_EQ(true, EvalJs(main_contents, "did_scroll;")); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, | 
|  | DisabledByDocumentPolicy) { | 
|  | net::test_server::ControllableHttpResponse response(embedded_test_server(), | 
|  | "/target.html"); | 
|  |  | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url(embedded_test_server()->GetURL("/target.html#:~:text=text")); | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  |  | 
|  | // Load the target document | 
|  | TestNavigationManager navigation_manager(main_contents, url); | 
|  | shell()->LoadURL(url); | 
|  |  | 
|  | // Start navigation | 
|  | EXPECT_TRUE(navigation_manager.WaitForRequestStart()); | 
|  | navigation_manager.ResumeNavigation(); | 
|  |  | 
|  | // Send Document-Policy header | 
|  | response.WaitForRequest(); | 
|  | response.Send( | 
|  | "HTTP/1.1 200 OK\r\n" | 
|  | "Content-Type: text/html; charset=utf-8\r\n" | 
|  | "Document-Policy: force-load-at-top\r\n" | 
|  | "\r\n" | 
|  | "<script>" | 
|  | "  let did_scroll = false;" | 
|  | "  window.addEventListener('scroll', () => {" | 
|  | "    did_scroll = true;" | 
|  | "  });" | 
|  | "</script>" | 
|  | "<p style='position: absolute; top: 10000px;'>Some text</p>"); | 
|  | response.Done(); | 
|  |  | 
|  | EXPECT_TRUE(navigation_manager.WaitForResponse()); | 
|  | navigation_manager.ResumeNavigation(); | 
|  | navigation_manager.WaitForNavigationFinished(); | 
|  |  | 
|  | WaitForPageLoad(main_contents); | 
|  | // Wait a short amount of time to ensure the page does not scroll. | 
|  | base::RunLoop run_loop; | 
|  | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 
|  | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); | 
|  | run_loop.Run(); | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  | EXPECT_EQ(false, EvalJs(main_contents, "did_scroll;")); | 
|  | } | 
|  |  | 
|  | class ForceLoadAtTopBrowserTest : public TextFragmentAnchorBrowserTest { | 
|  | protected: | 
|  | void SetUpOnMainThread() override { | 
|  | TextFragmentAnchorBrowserTest::SetUpOnMainThread(); | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | } | 
|  | void SetUpCommandLine(base::CommandLine* command_line) override { | 
|  | TextFragmentAnchorBrowserTest::SetUpCommandLine(command_line); | 
|  | command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures, | 
|  | "ForceLoadAtTop"); | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Test that scroll restoration is disabled with ForceLoadAtTop | 
|  | IN_PROC_BROWSER_TEST_F(ForceLoadAtTopBrowserTest, ScrollRestorationDisabled) { | 
|  | GURL url( | 
|  | embedded_test_server()->GetURL("/scrollable_page_with_content.html")); | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | RenderFrameSubmissionObserver frame_observer(main_contents); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  | EXPECT_TRUE(WaitForRenderFrameReady(main_contents->GetMainFrame())); | 
|  |  | 
|  | // Scroll down the page a bit | 
|  | EXPECT_TRUE(ExecuteScript(main_contents, "window.scrollTo(0, 1000)")); | 
|  | frame_observer.WaitForScrollOffsetAtTop(false); | 
|  |  | 
|  | // Navigate away | 
|  | EXPECT_TRUE(ExecuteScript(main_contents, "window.location = 'about:blank'")); | 
|  | EXPECT_TRUE(WaitForLoadStop(main_contents)); | 
|  | EXPECT_TRUE(WaitForRenderFrameReady(main_contents->GetMainFrame())); | 
|  |  | 
|  | // Navigate back | 
|  | EXPECT_TRUE(ExecuteScript(main_contents, "history.back()")); | 
|  | EXPECT_TRUE(WaitForLoadStop(main_contents)); | 
|  | EXPECT_TRUE(WaitForRenderFrameReady(main_contents->GetMainFrame())); | 
|  |  | 
|  | // Wait a short amount of time to ensure the page does not scroll. | 
|  | base::RunLoop run_loop; | 
|  | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 
|  | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); | 
|  | run_loop.Run(); | 
|  | RunUntilInputProcessed(RenderWidgetHostImpl::From( | 
|  | main_contents->GetRenderViewHost()->GetWidget())); | 
|  | EXPECT_TRUE(main_contents->GetMainFrame()->GetView()->IsScrollOffsetAtTop()); | 
|  | } | 
|  |  | 
|  | // Test that element fragment anchor scrolling is disabled with ForceLoadAtTop | 
|  | IN_PROC_BROWSER_TEST_F(ForceLoadAtTopBrowserTest, FragmentAnchorDisabled) { | 
|  | GURL url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#text")); | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  | EXPECT_TRUE(WaitForRenderFrameReady(main_contents->GetMainFrame())); | 
|  |  | 
|  | // Wait a short amount of time to ensure the page does not scroll. | 
|  | base::RunLoop run_loop; | 
|  | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 
|  | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); | 
|  | run_loop.Run(); | 
|  | RunUntilInputProcessed(RenderWidgetHostImpl::From( | 
|  | main_contents->GetRenderViewHost()->GetWidget())); | 
|  | EXPECT_TRUE(main_contents->GetMainFrame()->GetView()->IsScrollOffsetAtTop()); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(ForceLoadAtTopBrowserTest, SameDocumentNavigation) { | 
|  | GURL url( | 
|  | embedded_test_server()->GetURL("/scrollable_page_with_content.html")); | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  | EXPECT_TRUE(WaitForRenderFrameReady(main_contents->GetMainFrame())); | 
|  | EXPECT_TRUE(main_contents->GetMainFrame()->GetView()->IsScrollOffsetAtTop()); | 
|  |  | 
|  | ClickElementWithId(main_contents, "link"); | 
|  |  | 
|  | RunUntilInputProcessed(GetWidgetHost()); | 
|  | EXPECT_FALSE(main_contents->GetMainFrame()->GetView()->IsScrollOffsetAtTop()); | 
|  | } | 
|  |  | 
|  | IN_PROC_BROWSER_TEST_F(ForceLoadAtTopBrowserTest, TextFragmentAnchorDisabled) { | 
|  | GURL url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_content.html#:~:text=text")); | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | RenderFrameSubmissionObserver frame_observer(main_contents); | 
|  |  | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  | EXPECT_TRUE(WaitForRenderFrameReady(main_contents->GetMainFrame())); | 
|  |  | 
|  | // Wait a short amount of time to ensure the page does not scroll. | 
|  | base::RunLoop run_loop; | 
|  | base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 
|  | FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); | 
|  | run_loop.Run(); | 
|  | RunUntilInputProcessed(RenderWidgetHostImpl::From( | 
|  | main_contents->GetRenderViewHost()->GetWidget())); | 
|  | EXPECT_TRUE(main_contents->GetMainFrame()->GetView()->IsScrollOffsetAtTop()); | 
|  | } | 
|  |  | 
|  | // Test that Tab key press puts focus from the start of selection. | 
|  | IN_PROC_BROWSER_TEST_F(TextFragmentAnchorBrowserTest, TabFocus) { | 
|  | ASSERT_TRUE(embedded_test_server()->Start()); | 
|  | GURL url(embedded_test_server()->GetURL( | 
|  | "/scrollable_page_with_anchor.html#:~:text=text")); | 
|  | WebContents* main_contents = shell()->web_contents(); | 
|  | RenderFrameSubmissionObserver frame_observer(main_contents); | 
|  | EXPECT_TRUE(NavigateToURL(shell(), url)); | 
|  | WaitForPageLoad(main_contents); | 
|  | frame_observer.WaitForScrollOffsetAtTop( | 
|  | /*expected_scroll_offset_at_top=*/false); | 
|  |  | 
|  | DOMMessageQueue msg_queue; | 
|  | SimulateKeyPress(main_contents, ui::DomKey::TAB, ui::DomCode::TAB, | 
|  | ui::VKEY_TAB, false, false, false, false); | 
|  |  | 
|  | // Wait for focus to happen. | 
|  | std::string message; | 
|  | EXPECT_TRUE(msg_queue.WaitForMessage(&message)); | 
|  | EXPECT_EQ("\"FocusDone2\"", message); | 
|  | } | 
|  |  | 
|  | }  // namespace content |