Files
brave-core/browser/speedreader/speedreader_browsertest.cc
T

1198 lines
46 KiB
C++

/* Copyright (c) 2020 The Brave Authors. All rights reserved.
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <string_view>
#include "base/command_line.h"
#include "base/functional/bind.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/escape.h"
#include "base/strings/string_util.h"
#include "base/test/bind.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time.h"
#include "brave/app/brave_command_ids.h"
#include "brave/browser/speedreader/page_distiller.h"
#include "brave/browser/speedreader/speedreader_service_factory.h"
#include "brave/browser/speedreader/speedreader_tab_helper.h"
#include "brave/browser/ui/browser_commands.h"
#include "brave/browser/ui/page_action/brave_page_action_icon_type.h"
#include "brave/browser/ui/tabs/features.h"
#include "brave/browser/ui/views/frame/brave_browser_view.h"
#include "brave/browser/ui/views/split_view/split_view.h"
#include "brave/browser/ui/views/split_view/split_view_location_bar.h"
#include "brave/browser/ui/webui/speedreader/speedreader_toolbar_data_handler_impl.h"
#include "brave/components/ai_chat/core/common/features.h"
#include "brave/components/brave_wallet/browser/brave_wallet_utils.h"
#include "brave/components/constants/brave_paths.h"
#include "brave/components/speedreader/common/features.h"
#include "brave/components/speedreader/common/speedreader.mojom.h"
#include "brave/components/speedreader/common/speedreader_toolbar.mojom.h"
#include "brave/components/speedreader/speedreader_service.h"
#include "brave/components/speedreader/speedreader_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_command_controller.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
#include "chrome/browser/ui/views/page_action/page_action_icon_view.h"
#include "chrome/browser/ui/views/side_panel/side_panel_ui.h"
#include "chrome/common/chrome_isolated_world_ids.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/language/core/browser/language_prefs.h"
#include "components/network_session_configurator/common/network_switches.h"
#include "content/public/browser/reload_type.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "net/dns/mock_host_resolver.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
#include "services/network/public/cpp/network_switches.h"
#include "ui/events/base_event_utils.h"
constexpr char kTestHost[] = "a.test";
constexpr char kTestPageSimple[] = "/simple.html";
constexpr char kTestPageReadable[] = "/speedreader/article/guardian.html";
constexpr char kTestEsPageReadable[] = "/speedreader/article/es.html";
constexpr char kTestPageReadableOnUnreadablePath[] =
"/speedreader/pages/simple.html";
constexpr char kTestPageRedirect[] = "/articles/redirect_me.html";
constexpr char kTestXml[] = "/speedreader/article/rss.xml";
constexpr char kTestTtsSimple[] = "/speedreader/article/simple.html";
constexpr char kTestTtsTags[] = "/speedreader/article/tags.html";
constexpr char kTestTtsStructure[] = "/speedreader/article/structure.html";
constexpr char kTestErrorPage[] =
"/speedreader/article/page_not_reachable.html";
constexpr char kTestCSPHtmlPage[] = "/speedreader/article/csp_html.html";
constexpr char kTestCSPHttpPage[] = "/speedreader/article/csp_http.html";
constexpr char kTestCSPHackEquivPage[] =
"/speedreader/article/csp_hack_equiv.html";
constexpr char kTestCSPHackCharsetPage[] =
"/speedreader/article/csp_hack_charset.html";
constexpr char kTestCSPOrderPage1[] = "/speedreader/article/csp_order_1.html";
constexpr char kTestCSPOrderPage2[] = "/speedreader/article/csp_order_2.html";
constexpr char kTestCSPInBodyPage[] = "/speedreader/article/csp_in_body.html";
class SpeedReaderBrowserTest : public InProcessBrowserTest {
public:
SpeedReaderBrowserTest()
: https_server_(net::EmbeddedTestServer::TYPE_HTTPS) {
feature_list_.InitWithFeaturesAndParameters(
{{speedreader::kSpeedreaderFeature,
{{speedreader::kSpeedreaderTTS.name, "true"}}},
{ai_chat::features::kAIChat, {{}}},
{tabs::features::kBraveSplitView, {{}}}},
{});
}
SpeedReaderBrowserTest(const SpeedReaderBrowserTest&) = delete;
SpeedReaderBrowserTest& operator=(const SpeedReaderBrowserTest&) = delete;
~SpeedReaderBrowserTest() override = default;
void SetUp() override {
https_server_.SetSSLConfig(net::EmbeddedTestServer::CERT_TEST_NAMES);
ASSERT_TRUE(https_server_.InitializeAndListen());
InProcessBrowserTest::SetUp();
}
void SetUpOnMainThread() override {
auto redirector = [](const net::test_server::HttpRequest& request)
-> std::unique_ptr<net::test_server::HttpResponse> {
if (request.GetURL().path_piece() != kTestPageRedirect) {
return nullptr;
}
const std::string dest =
base::UnescapeBinaryURLComponent(request.GetURL().query_piece());
auto http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_MOVED_PERMANENTLY);
http_response->AddCustomHeader("Location", dest);
http_response->AddCustomHeader("Access-Control-Allow-Origin", "*");
http_response->set_content_type("text/html");
return http_response;
};
https_server_.RegisterDefaultHandler(base::BindRepeating(redirector));
https_server_.ServeFilesFromDirectory(
base::PathService::CheckedGet(brave::DIR_TEST_DATA));
https_server_.StartAcceptingConnections();
host_resolver()->AddRule("*", "127.0.0.1");
}
void SetUpCommandLine(base::CommandLine* command_line) override {
InProcessBrowserTest::SetUpCommandLine(command_line);
command_line->AppendSwitchASCII(
network::switches::kHostResolverRules,
"MAP *:443 " + https_server_.host_port_pair().ToString());
}
content::WebContents* ActiveWebContents() {
return browser()->tab_strip_model()->GetActiveWebContents();
}
speedreader::SpeedreaderTabHelper* tab_helper() {
return speedreader::SpeedreaderTabHelper::FromWebContents(
ActiveWebContents());
}
speedreader::SpeedreaderService* speedreader_service() {
return speedreader::SpeedreaderServiceFactory::GetForBrowserContext(
browser()->profile());
}
void NonBlockingDelay(base::TimeDelta delay) {
base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE, run_loop.QuitWhenIdleClosure(), delay);
run_loop.Run();
}
PageActionIconView* GetReaderButton() {
return BrowserView::GetBrowserViewForBrowser(browser())
->toolbar_button_provider()
->GetPageActionIconView(brave::kSpeedreaderPageActionIconType);
}
void WaitDistilled(speedreader::SpeedreaderTabHelper* th = nullptr) {
if (!th) {
th = tab_helper();
}
while (!speedreader::DistillStates::IsDistilled(th->PageDistillState())) {
NonBlockingDelay(base::Milliseconds(10));
}
content::WaitForLoadStop(ActiveWebContents());
}
void WaitDistillable(speedreader::SpeedreaderTabHelper* th = nullptr) {
if (!th) {
th = tab_helper();
}
while (!speedreader::DistillStates::IsDistillable(th->PageDistillState())) {
NonBlockingDelay(base::Milliseconds(10));
}
content::WaitForLoadStop(ActiveWebContents());
}
void WaitOriginal(speedreader::SpeedreaderTabHelper* th = nullptr) {
if (!th) {
th = tab_helper();
}
while (
!speedreader::DistillStates::IsViewOriginal(th->PageDistillState())) {
NonBlockingDelay(base::Milliseconds(10));
}
content::WaitForLoadStop(ActiveWebContents());
}
void ClickReaderButton() {
const auto was_distilled = speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState());
browser()->command_controller()->ExecuteCommand(
IDC_SPEEDREADER_ICON_ONCLICK);
if (!was_distilled) {
WaitDistilled();
} else {
WaitDistillable();
}
content::WaitForLoadStop(ActiveWebContents());
}
void WaitToolbarVisibility(ReaderModeToolbarView* toolbar, bool visible) {
while (toolbar->GetVisible() != visible) {
NonBlockingDelay(base::Milliseconds(10));
}
if (visible) {
while (toolbar->height() != toolbar->GetPreferredSize().height()) {
NonBlockingDelay(base::Milliseconds(10));
}
}
}
void ClickInView(views::View* clickable_view) {
clickable_view->OnMousePressed(
ui::MouseEvent(ui::EventType::kMousePressed, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
clickable_view->OnMouseReleased(ui::MouseEvent(
ui::EventType::kMouseReleased, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON, 0));
}
void ClickInWebContents(content::WebContents* web_contents) {
blink::WebMouseEvent mouse_event(
blink::WebInputEvent::Type::kMouseDown,
blink::WebInputEvent::kNoModifiers,
blink::WebInputEvent::GetStaticTimeStampForTests());
mouse_event.button = blink::WebMouseEvent::Button::kLeft;
mouse_event.SetPositionInWidget(0, 0);
mouse_event.click_count = 1;
web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
mouse_event);
mouse_event.SetType(blink::WebInputEvent::Type::kMouseUp);
web_contents->GetRenderViewHost()->GetWidget()->ForwardMouseEvent(
mouse_event);
}
void ToggleSpeedreader() {
speedreader_service()->EnableForAllSites(
!speedreader_service()->IsEnabledForAllSites());
}
void DisableSpeedreader() { speedreader_service()->EnableForAllSites(false); }
void GoBack(Browser* browser) {
content::TestNavigationObserver observer(ActiveWebContents());
chrome::GoBack(browser, WindowOpenDisposition::CURRENT_TAB);
observer.Wait();
}
void NavigateToPageSynchronously(
std::string_view path,
WindowOpenDisposition disposition =
WindowOpenDisposition::NEW_FOREGROUND_TAB) {
const GURL url = GURL("https://a.test").Resolve(path);
ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
browser(), url, disposition,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
}
protected:
base::test::ScopedFeatureList feature_list_;
net::EmbeddedTestServer https_server_;
base::HistogramTester histogram_tester_;
};
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, PRE_RestoreSpeedreaderPage) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageReadable,
WindowOpenDisposition::CURRENT_TAB);
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, RestoreSpeedreaderPage) {
browser()->tab_strip_model()->ActivateTabAt(0);
WaitDistilled();
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, NavigationNostickTest) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageSimple);
EXPECT_FALSE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
NavigateToPageSynchronously(kTestPageReadable,
WindowOpenDisposition::CURRENT_TAB);
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
// Ensure distill state doesn't stick when we back-navigate from a readable
// page to a non-readable one.
GoBack(browser());
EXPECT_FALSE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, DisableSiteWorks) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageReadable);
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
speedreader_service()->EnableForSite(ActiveWebContents(), false);
EXPECT_TRUE(WaitForLoadStop(ActiveWebContents()));
EXPECT_FALSE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
}
// I assume that the periodic fails of this test are related to issues/36355, I
// need to deal with it before turning it back. Other tests cover the
// scenario in this one, so a temporary disabling will not affect the health
// check of the feature.
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, DISABLED_SmokeTest) {
// Solana web3.js console warning will interfere with console observer
brave_wallet::SetDefaultSolanaWallet(
browser()->profile()->GetPrefs(),
brave_wallet::mojom::DefaultWallet::None);
const std::string kGetContentLength = "document.body.innerHTML.length";
// Check that disabled speedreader doesn't affect the page.
EXPECT_FALSE(speedreader_service()->IsEnabledForAllSites());
NavigateToPageSynchronously(kTestPageReadable,
WindowOpenDisposition::CURRENT_TAB);
const auto first_load_page_length =
content::EvalJs(ActiveWebContents(), kGetContentLength,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractInt();
EXPECT_LT(83000, first_load_page_length);
ToggleSpeedreader();
EXPECT_TRUE(speedreader_service()->IsEnabledForAllSites());
content::WebContentsConsoleObserver console_observer(ActiveWebContents());
console_observer.SetFilter(base::BindLambdaForTesting(
[](const content::WebContentsConsoleObserver::Message& message) {
return message.log_level == blink::mojom::ConsoleMessageLevel::kError;
}));
NavigateToPageSynchronously(kTestPageReadable,
WindowOpenDisposition::CURRENT_TAB);
const std::string kGetStyleLength =
"document.getElementById('brave_speedreader_style').innerHTML.length";
const std::string kGetFontsExists =
"!!(document.getElementById('atkinson_hyperligible_font') && "
"document.getElementById('open_dyslexic_font'))";
const std::string kCheckReferrer =
R"js(document.querySelector('meta[name="referrer"]')
.getAttribute('content') === 'no-referrer')js";
const std::string kCheckResources =
"JSON.stringify(speedreaderData) == '{\"minutesText\":\"min. "
"read\",\"playButtonTitle\":\"Play/"
"Pause\",\"showOriginalLinkText\":\"View "
"original\",\"ttsEnabled\":true}'";
// Check that the document became much smaller and that non-empty
// speedreader style is injected.
EXPECT_LT(0, content::EvalJs(ActiveWebContents(), kGetStyleLength,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractInt());
EXPECT_TRUE(content::EvalJs(ActiveWebContents(), kGetFontsExists,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool());
EXPECT_TRUE(content::EvalJs(ActiveWebContents(), kCheckReferrer,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool());
EXPECT_TRUE(content::EvalJs(ActiveWebContents(), kCheckResources,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool());
const auto speedreaded_length =
content::EvalJs(ActiveWebContents(), kGetContentLength,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractInt();
EXPECT_GT(17750, speedreaded_length);
EXPECT_TRUE(console_observer.messages().empty());
ToggleSpeedreader();
EXPECT_FALSE(speedreader_service()->IsEnabledForAllSites());
NavigateToPageSynchronously(kTestPageReadable);
auto second_load_page_length =
content::EvalJs(ActiveWebContents(), kGetContentLength,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractInt();
if (second_load_page_length == 1) {
// TODO(issues/36355): Sometimes browser failed to load this page.
ActiveWebContents()->GetController().Reload(content::ReloadType::NORMAL,
false);
content::WaitForLoadStop(ActiveWebContents());
second_load_page_length =
content::EvalJs(ActiveWebContents(), kGetContentLength,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractInt();
}
EXPECT_LT(83000, second_load_page_length)
<< " First load length: " << first_load_page_length
<< " speedreaded length: " << speedreaded_length
<< " Second load length: " << second_load_page_length;
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, Redirect) {
ToggleSpeedreader();
const auto redirect_url = https_server_.GetURL(
kTestHost, "/speedreader/rewriter/jsonld_shortest_desc.html");
NavigateToPageSynchronously(kTestPageRedirect + ("?" + redirect_url.spec()));
const std::string kCheckNoStyle =
"!document.getElementById('brave_speedreader_style')";
EXPECT_TRUE(content::EvalJs(ActiveWebContents(), kCheckNoStyle,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool());
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, ClickingOnReaderButton) {
EXPECT_FALSE(speedreader_service()->IsEnabledForAllSites());
NavigateToPageSynchronously(kTestPageReadable);
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_FALSE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
histogram_tester_.ExpectTotalCount(
speedreader::kSpeedreaderPageViewsHistogramName, 0);
ClickReaderButton();
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
EXPECT_TRUE(GetReaderButton()->GetVisible());
histogram_tester_.ExpectTotalCount(
speedreader::kSpeedreaderPageViewsHistogramName, 1);
ClickReaderButton();
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsViewOriginal(
tab_helper()->PageDistillState()));
EXPECT_FALSE(speedreader_service()->IsEnabledForAllSites());
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, OnDemandReader) {
EXPECT_FALSE(speedreader_service()->IsEnabledForAllSites());
NavigateToPageSynchronously(kTestPageReadable);
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistillable(
tab_helper()->PageDistillState()));
// Change content on the page.
static constexpr char kChangeContent[] =
R"js(
document.querySelector('meta[property="og:title"]').content =
'Title was changed by javascript'
)js";
EXPECT_TRUE(content::ExecJs(ActiveWebContents(), kChangeContent,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS));
ClickReaderButton();
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
// Check title on the distilled page.
static constexpr char kCheckContent[] =
R"js(
!!document.getElementById('brave_speedreader_style') &&
(document.title === 'Title was changed by javascript')
)js";
EXPECT_TRUE(content::EvalJs(ActiveWebContents(), kCheckContent,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool());
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, OnDemandReaderEncoding) {
EXPECT_FALSE(speedreader_service()->IsEnabledForAllSites());
NavigateToPageSynchronously(kTestEsPageReadable);
EXPECT_TRUE(GetReaderButton()->GetVisible());
ClickReaderButton();
static constexpr char kCheckText[] =
R"js( document.querySelector('#par-to-check').innerText.length )js";
EXPECT_EQ(92, content::EvalJs(ActiveWebContents(), kCheckText,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractInt());
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, EnableDisableSpeedreaderA) {
EXPECT_FALSE(speedreader_service()->IsEnabledForAllSites());
NavigateToPageSynchronously(kTestPageReadable);
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistillable(
tab_helper()->PageDistillState()));
ToggleSpeedreader();
WaitDistilled();
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
DisableSpeedreader();
WaitOriginal();
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistillable(
tab_helper()->PageDistillState()));
EXPECT_TRUE(speedreader::DistillStates::IsViewOriginal(
tab_helper()->PageDistillState()));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, EnableDisableSpeedreaderB) {
NavigateToPageSynchronously(kTestPageReadable);
ClickReaderButton();
WaitDistilled();
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
ToggleSpeedreader();
WaitDistilled();
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
DisableSpeedreader();
WaitOriginal();
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistillable(
tab_helper()->PageDistillState()));
EXPECT_TRUE(speedreader::DistillStates::IsViewOriginal(
tab_helper()->PageDistillState()));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, TogglingSiteSpeedreader) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageReadable);
for (int i = 0; i < 2; ++i) {
EXPECT_TRUE(WaitForLoadStop(ActiveWebContents()));
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
EXPECT_TRUE(GetReaderButton()->GetVisible());
speedreader_service()->EnableForSite(ActiveWebContents(), false);
EXPECT_TRUE(WaitForLoadStop(ActiveWebContents()));
EXPECT_TRUE(speedreader::DistillStates::IsViewOriginal(
tab_helper()->PageDistillState()));
EXPECT_TRUE(GetReaderButton()->GetVisible());
speedreader_service()->EnableForSite(ActiveWebContents(), true);
EXPECT_TRUE(WaitForLoadStop(ActiveWebContents()));
}
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, ReloadContent) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageReadable);
auto* contents_1 = ActiveWebContents();
NavigateToPageSynchronously(kTestPageReadable);
auto* contents_2 = ActiveWebContents();
auto* tab_helper_1 =
speedreader::SpeedreaderTabHelper::FromWebContents(contents_1);
auto* tab_helper_2 =
speedreader::SpeedreaderTabHelper::FromWebContents(contents_2);
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper_1->PageDistillState()));
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper_2->PageDistillState()));
speedreader_service()->EnableForSite(tab_helper_1->web_contents(), false);
content::WaitForLoadStop(contents_1);
EXPECT_TRUE(speedreader::DistillStates::IsViewOriginal(
tab_helper_1->PageDistillState()));
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper_2->PageDistillState()));
contents_2->GetController().Reload(content::ReloadType::NORMAL, false);
content::WaitForLoadStop(contents_2);
EXPECT_TRUE(speedreader::DistillStates::IsViewOriginal(
tab_helper_1->PageDistillState()));
EXPECT_TRUE(speedreader::DistillStates::IsViewOriginal(
tab_helper_2->PageDistillState()));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, ShowOriginalPage) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageReadable);
auto* web_contents = ActiveWebContents();
static constexpr char kCheckNoApiInMainWorld[] =
R"js(
document.speedreader === undefined
)js";
EXPECT_TRUE(content::EvalJs(web_contents, kCheckNoApiInMainWorld,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS)
.ExtractBool());
static constexpr char kClickLinkAndGetTitle[] =
R"js(
(function() {
// element id is hardcoded in extractor.rs
const link =
document.getElementById('c93e2206-2f31-4ddc-9828-2bb8e8ed940e');
link.click();
return link.innerText
})();
)js";
EXPECT_EQ("View original",
content::EvalJs(web_contents, kClickLinkAndGetTitle,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractString());
content::WaitForLoadStop(web_contents);
auto* tab_helper =
speedreader::SpeedreaderTabHelper::FromWebContents(web_contents);
EXPECT_TRUE(speedreader::DistillStates::IsDistillable(
tab_helper->PageDistillState()));
EXPECT_TRUE(speedreader_service()->IsEnabledForSite(web_contents));
// Click on speedreader button
ClickReaderButton();
content::WaitForLoadStop(web_contents);
EXPECT_TRUE(
speedreader::DistillStates::IsDistilled(tab_helper->PageDistillState()));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, ShowOriginalPageOnUnreadable) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageSimple);
auto* web_contents = ActiveWebContents();
static constexpr char kCheckNoElement[] =
R"js(
document.getElementById('c93e2206-2f31-4ddc-9828-2bb8e8ed940e') == null
)js";
EXPECT_TRUE(content::EvalJs(web_contents, kCheckNoElement,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool());
static constexpr char kCheckNoApi[] =
R"js(
document.speedreader === undefined
)js";
EXPECT_TRUE(content::EvalJs(web_contents, kCheckNoApi,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool());
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, SetDataAttributes) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageReadable);
auto* contents = ActiveWebContents();
// Open second tab
NavigateToPageSynchronously(kTestPageReadable);
auto GetDataAttribute = [](const std::string& attr) {
static constexpr char kGetDataAttribute[] =
R"js(
document.documentElement.getAttribute('$1')
)js";
return base::ReplaceStringPlaceholders(kGetDataAttribute, {attr}, nullptr);
};
EXPECT_EQ(speedreader::mojom::Theme::kNone,
speedreader_service()->GetAppearanceSettings().theme);
EXPECT_EQ(speedreader::mojom::FontFamily::kSans,
speedreader_service()->GetAppearanceSettings().fontFamily);
EXPECT_EQ(speedreader::mojom::FontSize::k100,
speedreader_service()->GetAppearanceSettings().fontSize);
EXPECT_EQ(speedreader::mojom::ColumnWidth::kNarrow,
speedreader_service()->GetAppearanceSettings().columnWidth);
EXPECT_EQ(nullptr, content::EvalJs(contents, GetDataAttribute("data-theme"),
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL));
speedreader_service()->SetAppearanceSettings(
speedreader::mojom::AppearanceSettings(
speedreader::mojom::Theme::kDark, speedreader::mojom::FontSize::k130,
speedreader::mojom::FontFamily::kDyslexic,
speedreader::mojom::ColumnWidth::kWide));
auto EvalAttr = [&](content::WebContents* contents, const std::string& attr) {
return content::EvalJs(contents, GetDataAttribute(attr),
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractString();
};
EXPECT_EQ("dark", EvalAttr(contents, "data-theme"));
EXPECT_EQ("dyslexic", EvalAttr(contents, "data-font-family"));
EXPECT_EQ("130", EvalAttr(contents, "data-font-size"));
EXPECT_EQ("wide", EvalAttr(contents, "data-column-width"));
// Same in the second tab
EXPECT_EQ("dark", EvalAttr(ActiveWebContents(), "data-theme"));
EXPECT_EQ("dyslexic", EvalAttr(ActiveWebContents(), "data-font-family"));
EXPECT_EQ("130", EvalAttr(ActiveWebContents(), "data-font-size"));
EXPECT_EQ("wide", EvalAttr(contents, "data-column-width"));
EXPECT_EQ(speedreader::mojom::Theme::kDark,
speedreader_service()->GetAppearanceSettings().theme);
EXPECT_EQ(speedreader::mojom::FontFamily::kDyslexic,
speedreader_service()->GetAppearanceSettings().fontFamily);
EXPECT_EQ(speedreader::mojom::FontSize::k130,
speedreader_service()->GetAppearanceSettings().fontSize);
EXPECT_EQ(speedreader::mojom::ColumnWidth::kWide,
speedreader_service()->GetAppearanceSettings().columnWidth);
// New page
NavigateToPageSynchronously(kTestPageReadable);
EXPECT_EQ("dark", EvalAttr(ActiveWebContents(), "data-theme"));
EXPECT_EQ("dyslexic", EvalAttr(ActiveWebContents(), "data-font-family"));
EXPECT_EQ("130", EvalAttr(ActiveWebContents(), "data-font-size"));
EXPECT_EQ("wide", EvalAttr(contents, "data-column-width"));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, Toolbar) {
auto GetDataAttribute = [](const std::string& attr) {
static constexpr char kGetDataAttribute[] =
R"js(
document.documentElement.getAttribute('$1')
)js";
return base::ReplaceStringPlaceholders(kGetDataAttribute, {attr}, nullptr);
};
auto WaitAttr = [&](content::WebContents* contents, const std::string& attr,
const std::string& value) {
for (;;) {
NonBlockingDelay(base::Milliseconds(10));
auto eval = content::EvalJs(contents, GetDataAttribute(attr),
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL);
if (!eval.value.is_string() && value.empty()) {
return true;
}
if (eval.ExtractString() == value) {
return true;
}
}
};
auto WaitElement = [&](content::WebContents* contents,
const std::string& elem) {
static constexpr char kWaitElement[] =
R"js(
(!!document.getElementById('$1'))
)js";
for (;;) {
NonBlockingDelay(base::Milliseconds(10));
if (content::EvalJs(
contents,
base::ReplaceStringPlaceholders(kWaitElement, {elem}, nullptr),
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractBool()) {
break;
}
}
};
auto Click = [&](content::WebContents* contents, const std::string& id) {
static constexpr char kClick[] =
R"js(
document.getElementById('$1').click()
)js";
ASSERT_TRUE(content::ExecJs(
contents, base::ReplaceStringPlaceholders(kClick, {id}, nullptr)));
};
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageReadable);
auto* page = ActiveWebContents();
auto* toolbar_view = static_cast<BraveBrowserView*>(browser()->window())
->reader_mode_toolbar_.get();
auto* toolbar = toolbar_view->GetWebContentsForTesting();
WaitElement(toolbar, "appearance");
Click(toolbar, "ai");
auto* side_panel = browser()->GetFeatures().side_panel_ui();
while (side_panel->GetCurrentEntryId() != SidePanelEntryId::kChatUI) {
NonBlockingDelay(base::Milliseconds(10));
}
EXPECT_EQ(SidePanelEntryId::kChatUI, side_panel->GetCurrentEntryId());
Click(toolbar, "ai");
while (side_panel->GetCurrentEntryId().has_value()) {
NonBlockingDelay(base::Milliseconds(10));
}
EXPECT_FALSE(side_panel->GetCurrentEntryId().has_value());
Click(toolbar, "appearance");
{ // change theme
Click(toolbar, "theme-light");
WaitAttr(page, "data-theme", "light");
Click(toolbar, "theme-sepia");
WaitAttr(page, "data-theme", "sepia");
Click(toolbar, "theme-dark");
WaitAttr(page, "data-theme", "dark");
Click(toolbar, "theme-system");
WaitAttr(page, "data-theme", "");
}
{ // change font
Click(toolbar, "font-sans");
WaitAttr(page, "data-font-family", "sans");
Click(toolbar, "font-serif");
WaitAttr(page, "data-font-family", "serif");
Click(toolbar, "font-mono");
WaitAttr(page, "data-font-family", "mono");
Click(toolbar, "font-dyslexic");
WaitAttr(page, "data-font-family", "dyslexic");
}
{ // change font size
WaitAttr(page, "data-font-size", "100");
Click(toolbar, "font-size-decrease");
WaitAttr(page, "data-font-size", "90");
Click(toolbar, "font-size-increase");
WaitAttr(page, "data-font-size", "100");
Click(toolbar, "font-size-increase");
WaitAttr(page, "data-font-size", "110");
}
Click(toolbar, "appearance");
Click(toolbar, "tune");
{
while (!tab_helper()->speedreader_bubble_view()) {
NonBlockingDelay(base::Milliseconds(10));
}
}
Click(toolbar, "tune");
Click(toolbar, "close");
{
WaitOriginal();
EXPECT_FALSE(toolbar_view->GetVisible());
}
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, ToolbarLangs) {
language::LanguagePrefs language_prefs(browser()->profile()->GetPrefs());
language_prefs.SetUserSelectedLanguagesList(
{"en-US", "ja", "en-CA", "fr-CA"});
ToggleSpeedreader();
NavigateToPageSynchronously(kTestPageReadable);
auto* toolbar_view = static_cast<BraveBrowserView*>(browser()->window())
->reader_mode_toolbar_.get();
auto* toolbar = toolbar_view->GetWebContentsForTesting();
static constexpr char kGetLang[] = R"js( navigator.languages.toString() )js";
EXPECT_EQ("en-US,ja,en-CA,fr-CA",
content::EvalJs(toolbar, kGetLang).ExtractString());
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, RSS) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestXml);
EXPECT_FALSE(GetReaderButton()->GetVisible());
const std::string kNoStyleInjected =
R"js(document.getElementById('brave_speedreader_style'))js";
EXPECT_EQ(nullptr, content::EvalJs(ActiveWebContents(), kNoStyleInjected,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, TTS) {
ToggleSpeedreader();
const std::string kCheckTtsParagraphs = R"js(
document.querySelectorAll('[tts-paragraph-index]').length
)js";
const char* pages[] = {kTestTtsSimple, kTestTtsTags, kTestTtsStructure};
for (const auto* page : pages) {
NavigateToPageSynchronously(page);
SCOPED_TRACE(page);
EXPECT_EQ(7, content::EvalJs(ActiveWebContents(), kCheckTtsParagraphs,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL)
.ExtractInt());
}
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, ErrorPage) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestErrorPage,
WindowOpenDisposition::CURRENT_TAB);
EXPECT_TRUE(ActiveWebContents()->GetPrimaryMainFrame()->IsErrorDocument());
EXPECT_FALSE(GetReaderButton()->GetVisible());
// Navigate to the non-automatic distillable page.
NavigateToPageSynchronously(kTestPageReadableOnUnreadablePath,
WindowOpenDisposition::CURRENT_TAB);
EXPECT_TRUE(speedreader::DistillStates::IsViewOriginal(
tab_helper()->PageDistillState()));
WaitDistillable(tab_helper());
EXPECT_TRUE(GetReaderButton()->GetVisible());
GoBack(browser());
NavigateToPageSynchronously(kTestPageReadable,
WindowOpenDisposition::CURRENT_TAB);
WaitDistilled();
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, Csp) {
ToggleSpeedreader();
for (const auto* page : {kTestCSPHackEquivPage, kTestCSPHackCharsetPage,
kTestCSPHtmlPage, kTestCSPHttpPage}) {
SCOPED_TRACE(page);
content::WebContentsConsoleObserver console_observer(ActiveWebContents());
console_observer.SetPattern(
"Refused to load the image 'https://a.test/should_fail.png' because it "
"violates the following Content Security Policy directive: \"img-src "
"'none'\".*");
NavigateToPageSynchronously(page, WindowOpenDisposition::CURRENT_TAB);
static constexpr char kCheckNoMaliciousContent[] = R"js(
!document.getElementById('malicious1') &&
!document.querySelector('meta[http-equiv="undefinedHttpEquiv"]')
)js";
EXPECT_EQ(true,
content::EvalJs(ActiveWebContents(), kCheckNoMaliciousContent,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL));
EXPECT_TRUE(console_observer.Wait());
}
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, CspOrder) {
ToggleSpeedreader();
// base first.
{
content::WebContentsConsoleObserver console_observer(ActiveWebContents());
NavigateToPageSynchronously(kTestCSPOrderPage1,
WindowOpenDisposition::CURRENT_TAB);
EXPECT_TRUE(console_observer.messages().empty());
}
// CSP first.
{
content::WebContentsConsoleObserver console_observer(ActiveWebContents());
console_observer.SetPattern(
"Refused to set the document's base URI to 'https://a.test/' because "
"it violates the following Content Security Policy directive: "
"\"base-uri 'none'\".*");
NavigateToPageSynchronously(kTestCSPOrderPage2,
WindowOpenDisposition::CURRENT_TAB);
EXPECT_TRUE(console_observer.Wait());
}
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, CspInBody) {
ToggleSpeedreader();
NavigateToPageSynchronously(kTestCSPInBodyPage,
WindowOpenDisposition::CURRENT_TAB);
static constexpr char kCheckCsp[] = R"js(
document.querySelectorAll('meta[content="CSP in body"]').length === 0
)js";
EXPECT_EQ(true, content::EvalJs(ActiveWebContents(), kCheckCsp,
content::EXECUTE_SCRIPT_DEFAULT_OPTIONS,
ISOLATED_WORLD_ID_BRAVE_INTERNAL));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, OnDemandReaderEnableForSite) {
EXPECT_FALSE(speedreader_service()->IsEnabledForAllSites());
struct MockObserver : speedreader::PageDistiller::Observer {
MOCK_METHOD(void,
OnPageDistillStateChanged,
(speedreader::PageDistiller::State),
(override));
};
testing::NiceMock<MockObserver> observer;
tab_helper()->speedreader::PageDistiller::AddObserver(&observer);
base::RunLoop run_loop;
ON_CALL(observer, OnPageDistillStateChanged(
speedreader::PageDistiller::State::kDistillable))
.WillByDefault(
testing::InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
NavigateToPageSynchronously(kTestPageReadableOnUnreadablePath,
WindowOpenDisposition::CURRENT_TAB);
run_loop.Run();
tab_helper()->speedreader::PageDistiller::RemoveObserver(&observer);
EXPECT_TRUE(GetReaderButton()->GetVisible());
EXPECT_TRUE(speedreader::DistillStates::IsDistillable(
tab_helper()->PageDistillState()));
ClickReaderButton();
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
// Enable speedreader for site explicitly.
speedreader_service()->EnableForSite(ActiveWebContents(), true);
ActiveWebContents()->GetController().Reload(content::ReloadType::NORMAL,
false);
WaitDistilled();
EXPECT_TRUE(speedreader::DistillStates::IsDistilled(
tab_helper()->PageDistillState()));
// Go to home page.
NavigateToPageSynchronously("/", WindowOpenDisposition::CURRENT_TAB);
EXPECT_TRUE(speedreader::DistillStates::IsViewOriginal(
tab_helper()->PageDistillState()));
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, SplitView) {
ToggleSpeedreader();
brave::NewSplitViewForTab(browser());
auto* browser_view = static_cast<BraveBrowserView*>(browser()->window());
auto* toolbar = browser_view->reader_mode_toolbar();
auto* secondary_toolbar =
browser_view->split_view()->secondary_reader_mode_toolbar();
ASSERT_TRUE(toolbar && secondary_toolbar);
auto* secondary_location_bar_widget =
browser_view->split_view()->secondary_location_bar_widget_.get();
auto* secondary_contents_container =
browser_view->split_view()->secondary_contents_container();
// No toolbars.
EXPECT_FALSE(toolbar->GetVisible());
EXPECT_FALSE(secondary_toolbar->GetVisible());
// Load a distillabe page in first tab.
browser()->tab_strip_model()->ActivateTabAt(0);
NavigateToPageSynchronously(kTestPageReadable,
WindowOpenDisposition::CURRENT_TAB);
WaitToolbarVisibility(toolbar, true);
WaitToolbarVisibility(secondary_toolbar, false);
const auto get_target_secondary_location_bar_origin =
[&secondary_contents_container]() {
gfx::Point target_secondary_location_bar_origin =
secondary_contents_container->GetLocalBounds().origin();
target_secondary_location_bar_origin =
views::View::ConvertPointToScreen(
secondary_contents_container,
target_secondary_location_bar_origin);
target_secondary_location_bar_origin.Offset(
SplitView::kInactiveBorderThickness,
SplitView::kInactiveBorderThickness);
return target_secondary_location_bar_origin;
};
// Change the active tab.
browser()->tab_strip_model()->ActivateTabAt(1);
WaitToolbarVisibility(toolbar, false);
WaitToolbarVisibility(secondary_toolbar, true);
EXPECT_EQ(get_target_secondary_location_bar_origin(),
secondary_location_bar_widget->GetWindowBoundsInScreen().origin());
// Load a distillabe page in second tab.
NavigateToPageSynchronously(kTestPageReadable,
WindowOpenDisposition::CURRENT_TAB);
WaitToolbarVisibility(toolbar, true);
WaitToolbarVisibility(secondary_toolbar, true);
// Check secondary location bar position when changing active tab
// between non split view tab and split view tab.
// Secondary location bar should have same origin with secondary
// contents container.
chrome::AddTabAt(browser(), GURL(), -1, /*foreground*/ true);
WaitToolbarVisibility(toolbar, false);
WaitToolbarVisibility(secondary_toolbar, false);
browser()->tab_strip_model()->ActivateTabAt(0);
WaitToolbarVisibility(toolbar, true);
WaitToolbarVisibility(secondary_toolbar, true);
EXPECT_EQ(get_target_secondary_location_bar_origin(),
secondary_location_bar_widget->GetWindowBoundsInScreen().origin());
browser()->tab_strip_model()->ActivateTabAt(2);
WaitToolbarVisibility(toolbar, false);
WaitToolbarVisibility(secondary_toolbar, false);
browser()->tab_strip_model()->ActivateTabAt(0);
WaitToolbarVisibility(toolbar, true);
WaitToolbarVisibility(secondary_toolbar, true);
EXPECT_EQ(get_target_secondary_location_bar_origin(),
secondary_location_bar_widget->GetWindowBoundsInScreen().origin());
// Second tab is active. Show original content.
browser()->tab_strip_model()->ActivateTabAt(1);
ClickReaderButton();
WaitToolbarVisibility(toolbar, false);
WaitToolbarVisibility(secondary_toolbar, true);
browser()->tab_strip_model()->ActivateTabAt(0);
// First tab is active. Show original content.
ClickReaderButton();
// There are no distilled pages.
WaitToolbarVisibility(toolbar, false);
WaitToolbarVisibility(secondary_toolbar, false);
}
IN_PROC_BROWSER_TEST_F(SpeedReaderBrowserTest, SplitViewClicking) {
ToggleSpeedreader();
brave::NewSplitViewForTab(browser());
auto* browser_view = static_cast<BraveBrowserView*>(browser()->window());
auto* toolbar = browser_view->reader_mode_toolbar();
auto* secondary_toolbar =
browser_view->split_view()->secondary_reader_mode_toolbar();
// No toolbars.
EXPECT_FALSE(toolbar->GetVisible());
EXPECT_FALSE(secondary_toolbar->GetVisible());
// Load a distillabe page in first tab.
browser()->tab_strip_model()->ActivateTabAt(0);
EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
NavigateToPageSynchronously(kTestPageReadable,
WindowOpenDisposition::CURRENT_TAB);
// Check clicking view makes its tab activate.
browser()->tab_strip_model()->ActivateTabAt(1);
EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
WaitToolbarVisibility(toolbar, false);
WaitToolbarVisibility(secondary_toolbar, true);
ClickInView(secondary_toolbar);
WaitToolbarVisibility(toolbar, true);
WaitToolbarVisibility(secondary_toolbar, false);
EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
browser()->tab_strip_model()->ActivateTabAt(1);
EXPECT_EQ(1, browser()->tab_strip_model()->active_index());
WaitToolbarVisibility(toolbar, false);
WaitToolbarVisibility(secondary_toolbar, true);
// Check click event from webview makes its tab activate.
ClickInWebContents(secondary_toolbar->GetWebContentsForTesting());
WaitToolbarVisibility(toolbar, true);
WaitToolbarVisibility(secondary_toolbar, false);
EXPECT_EQ(0, browser()->tab_strip_model()->active_index());
}