| // Copyright 2023 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/chained_back_navigation_tracker.h" |
| |
| #include "base/test/bind.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/test/base/in_process_browser_test.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/test/browser_test.h" |
| #include "content/public/test/navigation_simulator.h" |
| #include "net/dns/mock_host_resolver.h" |
| |
| namespace chrome { |
| |
| class ChainedBackNavigationTrackerBrowserTest : public InProcessBrowserTest { |
| public: |
| ChainedBackNavigationTrackerBrowserTest() = default; |
| |
| ChainedBackNavigationTrackerBrowserTest( |
| const ChainedBackNavigationTrackerBrowserTest&) = delete; |
| ChainedBackNavigationTrackerBrowserTest& operator=( |
| const ChainedBackNavigationTrackerBrowserTest&) = delete; |
| |
| ~ChainedBackNavigationTrackerBrowserTest() override = default; |
| |
| void SetUpOnMainThread() override { |
| host_resolver()->AddRule("*", "127.0.0.1"); |
| } |
| |
| protected: |
| content::WebContents* web_contents() const { |
| return browser()->tab_strip_model()->GetActiveWebContents(); |
| } |
| |
| const uint32_t min_navigation_cnt_ = |
| ChainedBackNavigationTracker::kMinimumChainedBackNavigationLength; |
| const int64_t max_navigation_interval_ = ChainedBackNavigationTracker:: |
| kMaxChainedBackNavigationIntervalInMilliseconds; |
| }; |
| |
| IN_PROC_BROWSER_TEST_F(ChainedBackNavigationTrackerBrowserTest, |
| SubframeBackNavigationIsCountedAsChained) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL url_a1 = embedded_test_server()->GetURL("a1.com", "/title1.html"); |
| GURL url_a2 = embedded_test_server()->GetURL("a2.com", "/title1.html"); |
| GURL url_b = embedded_test_server()->GetURL("b.com", "/title1.html"); |
| GURL url_c = embedded_test_server()->GetURL("c.com", "/title1.html"); |
| |
| ASSERT_TRUE(content::NavigateToURL(web_contents(), url_a1)); |
| ASSERT_TRUE(content::NavigateToURL(web_contents(), url_a2)); |
| |
| ChainedBackNavigationTracker::CreateForWebContents(web_contents()); |
| ChainedBackNavigationTracker* tracker = |
| ChainedBackNavigationTracker::FromWebContents(web_contents()); |
| ASSERT_TRUE(tracker); |
| |
| // The main frame back navigation should increment the count by 1. |
| ASSERT_TRUE(content::HistoryGoBack(web_contents())); |
| ASSERT_EQ(url_a1, web_contents()->GetLastCommittedURL()); |
| ASSERT_EQ(1u, tracker->chained_back_navigation_count_); |
| |
| // Create a subframe and append it to the document. |
| ASSERT_TRUE( |
| ExecJs(web_contents(), |
| content::JsReplace("let frame = document.createElement('iframe');" |
| "frame.src = $1;" |
| "document.body.appendChild(frame);", |
| url_b))); |
| ASSERT_TRUE(content::WaitForLoadStop(web_contents())); |
| content::RenderFrameHost* subframe_host = |
| ChildFrameAt(web_contents()->GetPrimaryMainFrame(), 0); |
| |
| // Navigate the subframe away, the chained back navigation count should be |
| // reset to 0. |
| ASSERT_TRUE(content::ExecJs( |
| subframe_host, content::JsReplace("window.location.href = $1;", url_c))); |
| ASSERT_TRUE(content::WaitForLoadStop(web_contents())); |
| ASSERT_EQ(0u, tracker->chained_back_navigation_count_); |
| |
| // The sub frame back navigation should increment the count by 1. |
| ASSERT_TRUE(content::HistoryGoBack(web_contents())); |
| ASSERT_EQ(1u, tracker->chained_back_navigation_count_); |
| } |
| |
| IN_PROC_BROWSER_TEST_F(ChainedBackNavigationTrackerBrowserTest, |
| RendererInitiatedBackNavigationIsNotCountedAsChained) { |
| ASSERT_TRUE(embedded_test_server()->Start()); |
| GURL url_a = embedded_test_server()->GetURL("a.com", "/title1.html"); |
| GURL url_b = embedded_test_server()->GetURL("b.com", "/title1.html"); |
| GURL url_c = embedded_test_server()->GetURL("c.com", "/title1.html"); |
| GURL url_d = embedded_test_server()->GetURL("d.com", "/title1.html"); |
| |
| ASSERT_TRUE(content::NavigateToURL(web_contents(), url_a)); |
| ASSERT_TRUE(content::NavigateToURL(web_contents(), url_b)); |
| ASSERT_TRUE(content::NavigateToURL(web_contents(), url_c)); |
| ASSERT_TRUE(content::NavigateToURL(web_contents(), url_d)); |
| |
| ChainedBackNavigationTracker::CreateForWebContents(web_contents()); |
| ChainedBackNavigationTracker* tracker = |
| ChainedBackNavigationTracker::FromWebContents(web_contents()); |
| ASSERT_TRUE(tracker); |
| |
| // No back navigation is performed yet, the chain length should not be |
| // updated. |
| ASSERT_EQ(0u, tracker->chained_back_navigation_count_); |
| |
| // The back navigation is renderer initiated, it should not increment the |
| // chain length. |
| ASSERT_TRUE(content::ExecJs(web_contents(), "window.history.back();")); |
| ASSERT_TRUE(content::WaitForLoadStop(web_contents())); |
| ASSERT_EQ(url_c, web_contents()->GetLastCommittedURL()); |
| ASSERT_EQ(0u, tracker->chained_back_navigation_count_); |
| |
| // The back navigation is browser initiated, it should increment the chain |
| // length. |
| ASSERT_TRUE(content::HistoryGoBack(web_contents())); |
| ASSERT_EQ(url_b, web_contents()->GetLastCommittedURL()); |
| ASSERT_EQ(1u, tracker->chained_back_navigation_count_); |
| |
| // The back navigation is renderer initiated, it should reset the chain |
| // length. |
| ASSERT_TRUE(content::ExecJs(web_contents(), "window.history.back();")); |
| ASSERT_TRUE(content::WaitForLoadStop(web_contents())); |
| ASSERT_EQ(url_a, web_contents()->GetLastCommittedURL()); |
| ASSERT_EQ(0u, tracker->chained_back_navigation_count_); |
| } |
| |
| } // namespace chrome |