diff --git a/browser/brave_ads/tabs/ads_tab_helper.cc b/browser/brave_ads/tabs/ads_tab_helper.cc index c8f6e54a2ed5..afbde124559b 100644 --- a/browser/brave_ads/tabs/ads_tab_helper.cc +++ b/browser/brave_ads/tabs/ads_tab_helper.cc @@ -272,8 +272,7 @@ void AdsTabHelper::MaybeNotifyTabHtmlContentDidChange() { // for Brave Rewards users. However, we must notify that the tab content has // changed with empty HTML to ensure that regular conversions are processed. return ads_service_->NotifyTabHtmlContentDidChange( - /*tab_id=*/session_id_.id(), redirect_chain_, - /*html=*/""); + /*tab_id=*/session_id_.id(), redirect_chain_, /*html=*/""); } // Only utilized for verifiable conversions, which requires the user to have diff --git a/browser/brave_ads/tabs/ads_tab_helper_browsertest.cc b/browser/brave_ads/tabs/ads_tab_helper_browsertest.cc index b01e7d8bf48b..81c2730f9d89 100644 --- a/browser/brave_ads/tabs/ads_tab_helper_browsertest.cc +++ b/browser/brave_ads/tabs/ads_tab_helper_browsertest.cc @@ -5,249 +5,665 @@ #include "brave/browser/brave_ads/tabs/ads_tab_helper.h" +#include "base/check.h" +#include "base/notreached.h" #include "base/path_service.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" #include "base/test/gmock_callback_support.h" +#include "brave/browser/ui/brave_browser_window.h" #include "brave/components/brave_ads/browser/ads_service_mock.h" #include "brave/components/brave_ads/core/public/prefs/pref_names.h" #include "brave/components/brave_rewards/common/pref_names.h" #include "brave/components/constants/brave_paths.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_test_util.h" +#include "chrome/browser/profiles/profiles_state.h" +#include "chrome/browser/sessions/session_restore_test_helper.h" +#include "chrome/browser/sessions/session_restore_test_utils.h" #include "chrome/browser/ssl/cert_verifier_browser_test.h" #include "chrome/browser/ui/browser.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.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/keep_alive_registry/keep_alive_types.h" +#include "components/keep_alive_registry/scoped_keep_alive.h" #include "components/prefs/pref_service.h" +#include "content/public/browser/media_player_id.h" +#include "content/public/browser/navigation_controller.h" +#include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_observer.h" #include "content/public/test/browser_test.h" #include "content/public/test/browser_test_utils.h" #include "content/public/test/content_mock_cert_verifier.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/http/http_status_code.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" -// npm run test -- brave_browser_tests --filter=AdsTabHelperTest* +// npm run test -- brave_browser_tests --filter=BraveAdsTabHelperTest* namespace brave_ads { namespace { -using base::test::RunClosure; -using testing::_; -using testing::IsEmpty; -using testing::Not; +constexpr char kHostName[] = "brave.com"; -constexpr char kUrlDomain[] = "example.com"; -constexpr char kUrlPath[] = "/brave_ads/basic_page.html"; -constexpr char kSinglePageApplicationUrlPath[] = +constexpr char kMultiPageApplicationWebpage[] = + "/brave_ads/multi_page_application.html"; +constexpr char kSinglePageApplicationWebpage[] = "/brave_ads/single_page_application.html"; -constexpr char k500ErrorPagePath[] = "/500_error_page.html"; -constexpr char k404ErrorPagePath[] = "/404_error_page.html"; +constexpr char kAutoplayVideoWebpage[] = "/brave_ads/autoplay_video.html"; +constexpr char kVideoWebpage[] = "/brave_ads/video.html"; -AdsTabHelper* GetActiveAdsTabHelper(Browser* browser) { - auto* web_contents = browser->tab_strip_model()->GetActiveWebContents(); - return AdsTabHelper::FromWebContents(web_contents); +constexpr char kHandleRequestUrlPath[] = "/handle_request"; +constexpr char kHttpStatusCodeQueryKey[] = "http_status_code"; + +class MediaWaiter : public content::WebContentsObserver { + public: + explicit MediaWaiter(content::WebContents* const web_contents) + : WebContentsObserver(web_contents) {} + + void WaitForMediaStartedPlaying() { media_started_playing_run_loop_.Run(); } + + void WaitForMediaDestroyed() { media_destroyed_run_loop_.Run(); } + + void WaitForMediaSessionCreated() { media_session_created_run_loop_.Run(); } + + // content::WebContentsObserver: + void MediaStartedPlaying(const MediaPlayerInfo& /*video_type*/, + const content::MediaPlayerId& id) override { + id_ = id; + media_started_playing_run_loop_.Quit(); + } + + void MediaDestroyed(const content::MediaPlayerId& id) override { + EXPECT_EQ(id, id_); + media_destroyed_run_loop_.Quit(); + } + + void MediaSessionCreated( + content::MediaSession* const /*media_session*/) override { + media_session_created_run_loop_.Quit(); + } + + private: + std::optional id_; + + base::RunLoop media_started_playing_run_loop_; + base::RunLoop media_destroyed_run_loop_; + base::RunLoop media_session_created_run_loop_; +}; + +MATCHER_P(FileName, filename, "") { + return arg.ExtractFileName() == filename; +} + +// Wait for a tab in the browser to fully load, including scripts. +bool WaitForTabToLoad(const Browser* const browser, const int index) { + CHECK(browser); + CHECK_LT(index, browser->tab_strip_model()->count()); + + content::WebContents* const web_contents = + browser->tab_strip_model()->GetWebContentsAt(index); + web_contents->GetController().LoadIfNecessary(); + + return content::WaitForLoadStop(web_contents); +} + +// Wait for all tabs in the browser to fully load, including scripts. +void WaitForTabsToLoad(const Browser* const browser) { + CHECK(browser); + + for (int i = 0; i < browser->tab_strip_model()->count(); ++i) { + EXPECT_TRUE(WaitForTabToLoad(browser, i)); + } } } // namespace -class AdsTabHelperTest : public CertVerifierBrowserTest { +class BraveAdsTabHelperTest : public CertVerifierBrowserTest { public: void SetUpOnMainThread() override { CertVerifierBrowserTest::SetUpOnMainThread(); + mock_cert_verifier()->set_default_result(net::OK); host_resolver()->AddRule("*", "127.0.0.1"); const base::FilePath test_data_dir = base::PathService::CheckedGet(brave::DIR_TEST_DATA); - https_server_.ServeFilesFromDirectory(test_data_dir); - https_server_.RegisterRequestHandler(base::BindRepeating( - &AdsTabHelperTest::HandleRequest, base::Unretained(this))); - ASSERT_TRUE(https_server_.Start()); + https_server().ServeFilesFromDirectory(test_data_dir); + https_server().RegisterRequestHandler(base::BindRepeating( + &BraveAdsTabHelperTest::HandleRequest, base::Unretained(this))); + ASSERT_TRUE(https_server().Start()); - GetActiveAdsTabHelper(browser())->SetAdsServiceForTesting(&ads_service()); + GetActiveAdsTabHelper(browser())->SetAdsServiceForTesting( + &ads_service_mock()); } - PrefService* GetPrefs() { return browser()->profile()->GetPrefs(); } + void TearDownOnMainThread() override { + ASSERT_TRUE(https_server().ShutdownAndWaitUntilComplete()); + + CertVerifierBrowserTest::TearDownOnMainThread(); + } + + PrefService* GetPrefs() const { return browser()->profile()->GetPrefs(); } net::EmbeddedTestServer& https_server() { return https_server_; } - AdsServiceMock& ads_service() { return ads_service_mock_; } + AdsServiceMock& ads_service_mock() { return ads_service_mock_; } + + content::WebContents* GetActiveWebContents( + const Browser* const browser) const { + CHECK(browser); + + return browser->tab_strip_model()->GetActiveWebContents(); + } + + AdsTabHelper* GetActiveAdsTabHelper(const Browser* const browser) const { + CHECK(browser); + + content::WebContents* const web_contents = GetActiveWebContents(browser); + return AdsTabHelper::FromWebContents(web_contents); + } + + void GoBack(const Browser* const browser) const { + CHECK(browser); + + content::NavigationController& navigation_controller = + GetActiveWebContents(browser)->GetController(); + ASSERT_TRUE(navigation_controller.CanGoBack()); + navigation_controller.GoBack(); + } + + void GoForward(const Browser* const browser) const { + CHECK(browser); + + content::NavigationController& navigation_controller = + GetActiveWebContents(browser)->GetController(); + ASSERT_TRUE(navigation_controller.CanGoForward()); + navigation_controller.GoForward(); + } + + void Reload(const Browser* const browser) const { + CHECK(browser); + + GetActiveWebContents(browser)->GetController().Reload( + content::ReloadType::NORMAL, /*check_for_repost=*/false); + } + + void NavigateToURL(Browser* const browser, + const std::string_view relative_url) { + CHECK(browser); + + content::WebContents* const web_contents = GetActiveWebContents(browser); + content::TestNavigationObserver navigation_observer(web_contents); + + const GURL url = https_server().GetURL(kHostName, relative_url); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser, url)); + + // Wait for the tab to load after the navigation. + navigation_observer.WaitForNavigationFinished(); + } + + // Requires `kSinglePageApplicationWebpage` to be loaded. + void SimulateSameDocumentMouseClick() const { + ExecuteJavaScriptForTests( + R"(document.querySelector('[data-navigation-type="same_document"]').click();)"); + + WaitForTabsToLoad(browser()); + } + + void ExecuteJavaScriptForTests(const std::string& javascript) const { + base::RunLoop run_loop; + + content::WebContents* const web_contents = GetActiveWebContents(browser()); + web_contents->GetPrimaryMainFrame()->ExecuteJavaScriptForTests( + base::ASCIIToUTF16(javascript), + base::BindOnce( + [](base::OnceClosure quit_callback, base::Value result) { + std::move(quit_callback).Run(); + }, + run_loop.QuitClosure()), + content::ISOLATED_WORLD_ID_GLOBAL); + + run_loop.Run(); + } + + void ExecuteJavaScriptWithUserGestureForTests( + const std::string& javascript) const { + base::RunLoop run_loop; + + content::WebContents* const web_contents = GetActiveWebContents(browser()); + web_contents->GetPrimaryMainFrame() + ->ExecuteJavaScriptWithUserGestureForTests( + base::ASCIIToUTF16(javascript), + base::BindOnce( + [](base::OnceClosure quit_callback, base::Value result) { + std::move(quit_callback).Run(); + }, + run_loop.QuitClosure()), + content::ISOLATED_WORLD_ID_GLOBAL); + + run_loop.Run(); + } + + void CloseActiveWebContents() const { + content::WebContents* const web_contents = GetActiveWebContents(browser()); + chrome::CloseWebContents(browser(), web_contents, /*add_to_history=*/false); + } + + void RestoreBrowser(const Browser* const browser) { + CHECK(browser); + + SessionRestoreTestHelper session_restore_observer; + chrome::NewEmptyWindow(browser->profile(), + /*should_trigger_session_restore=*/true); + session_restore_observer.Wait(); + + for (const Browser* const new_browser : *BrowserList::GetInstance()) { + GetActiveAdsTabHelper(new_browser) + ->SetAdsServiceForTesting(&ads_service_mock()); + + WaitForTabsToLoad(new_browser); + } + } + + void SimulateHttpStatusCodePage(Browser* const browser, + const int http_status_code) { + CHECK(browser); + + content::WebContents* const web_contents = GetActiveWebContents(browser); + content::TestNavigationObserver navigation_observer(web_contents); + + const std::string http_error_page = + base::StringPrintf("%s?%s=%d", kHandleRequestUrlPath, + kHttpStatusCodeQueryKey, http_status_code); + const GURL url = https_server().GetURL(kHostName, http_error_page); + ASSERT_TRUE(ui_test_utils::NavigateToURL(browser, url)); + + // Wait for the tab to load after the navigation. + navigation_observer.WaitForNavigationFinished(); + } + + std::unique_ptr HandleHttpStatusCodeQueryKey( + const std::string& value) const { + auto http_response = + std::make_unique(); + + int http_status_code_as_int; + EXPECT_TRUE(base::StringToInt(value, &http_status_code_as_int)); + const std::optional http_status_code = + net::TryToGetHttpStatusCode(http_status_code_as_int); + EXPECT_TRUE(http_status_code); + http_response->set_code(*http_status_code); + + http_response->set_content_type("text/html"); + const std::string http_status_code_page = base::StringPrintf( + R"( + + + %s + + )", + http_response->reason().c_str()); + http_response->set_content(http_status_code_page); + + return http_response; + } std::unique_ptr HandleRequest( - const net::test_server::HttpRequest& request) { - if (base::Contains(request.relative_url, k500ErrorPagePath)) { - // Return a 500 error without any content, causing the error page to be - // displayed. - auto response = std::make_unique(); - response->set_code(net::HTTP_INTERNAL_SERVER_ERROR); - return response; + const net::test_server::HttpRequest& http_request) const { + const GURL url = http_request.GetURL(); + if (url.path() != kHandleRequestUrlPath) { + // Do not override the HTTP response. + return nullptr; } - if (base::Contains(request.relative_url, k404ErrorPagePath)) { - // Return a 404 error with HTML content. - auto response = std::make_unique(); - response->set_code(net::HTTP_NOT_FOUND); - response->set_content_type("text/html"); - response->set_content("Not Found"); - return response; + // Handle request. + base::StringPairs key_value_pairs; + base::SplitStringIntoKeyValuePairs(url.query(), '=', '&', &key_value_pairs); + + for (const auto& [key, value] : key_value_pairs) { + if (key == kHttpStatusCodeQueryKey) { + return HandleHttpStatusCodeQueryKey(value); + } } - return nullptr; + NOTREACHED_NORETURN() + << "Query key not found. Unable to handle the request."; + } + + // Requires `kVideoWebpage` to be loaded. Errors are reported in the console + // log under the prefix "An error occurred while trying to load the video:". + void StartVideoPlayback() const { + // Video elements must be executed with a user gesture. + ExecuteJavaScriptWithUserGestureForTests( + R"(document.querySelector('video')?.play();)"); + + WaitForTabsToLoad(browser()); + } + + // Requires `kAutoplayVideoWebpage` or `kVideoWebpage` to be loaded. + void PauseVideoPlayback() const { + ExecuteJavaScriptForTests(R"(document.querySelector('video')?.pause();)"); + + WaitForTabsToLoad(browser()); } private: net::EmbeddedTestServer https_server_{ net::test_server::EmbeddedTestServer::TYPE_HTTPS}; - AdsServiceMock ads_service_mock_{nullptr}; + + AdsServiceMock ads_service_mock_{/*delegate*/ nullptr}; }; -IN_PROC_BROWSER_TEST_F(AdsTabHelperTest, UserHasNotJoinedBraveRewards) { +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, NotifyTabDidChange) { + EXPECT_CALL(ads_service_mock(), NotifyTabDidChange) + .Times(::testing::AnyNumber()); + + EXPECT_CALL(ads_service_mock(), + NotifyTabDidChange( + /*tab_id=*/::testing::_, /*redirect_chain=*/ + ::testing::Contains(FileName("multi_page_application.html")), + /*is_new_navigation=*/true, /*is_restoring=*/false, + /*is_visible=*/true)); + NavigateToURL(browser(), kMultiPageApplicationWebpage); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, NotifyTabDidLoad) { + EXPECT_CALL(ads_service_mock(), + NotifyTabDidLoad(/*tab_id=*/::testing::_, + /*http_status_code=*/net::HTTP_OK)); + NavigateToURL(browser(), kMultiPageApplicationWebpage); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + NotifyTabDidLoadForHttpServerResponseErrorPage) { + EXPECT_CALL( + ads_service_mock(), + NotifyTabDidLoad(/*tab_id=*/::testing::_, + /*http_status_code=*/net::HTTP_INTERNAL_SERVER_ERROR)); + SimulateHttpStatusCodePage(browser(), net::HTTP_INTERNAL_SERVER_ERROR); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + NotifyTabDidLoadForHttpClientResponseErrorPage) { + EXPECT_CALL(ads_service_mock(), + NotifyTabDidLoad(/*tab_id=*/::testing::_, + /*http_status_code=*/net::HTTP_NOT_FOUND)); + SimulateHttpStatusCodePage(browser(), net::HTTP_NOT_FOUND); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + NotifyTabHtmlContentDidChangeForRewardsUser) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); + + EXPECT_CALL(ads_service_mock(), + NotifyTabHtmlContentDidChange( + /*tab_id=*/::testing::_, /*redirect_chain=*/::testing::_, + /*html=*/::testing::Not(::testing::IsEmpty()))); + NavigateToURL(browser(), kMultiPageApplicationWebpage); +} + +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + NotifyTabHtmlContentDidChangeWithEmptyHtmlForNonRewardsUser) { GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, false); - EXPECT_CALL(ads_service(), NotifyTabTextContentDidChange).Times(0); + EXPECT_CALL(ads_service_mock(), + NotifyTabHtmlContentDidChange( + /*tab_id=*/::testing::_, /*redirect_chain=*/::testing::_, + /*html=*/::testing::IsEmpty())); + NavigateToURL(browser(), kMultiPageApplicationWebpage); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + DoNotNotifyTabHtmlContentDidChangeIfTabWasRestored) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); + + base::RunLoop run_loop; + EXPECT_CALL(ads_service_mock(), NotifyTabHtmlContentDidChange) + .WillOnce(base::test::RunClosure(run_loop.QuitClosure())); + NavigateToURL(browser(), kMultiPageApplicationWebpage); + run_loop.Run(); - base::RunLoop html_content_run_loop; - EXPECT_CALL(ads_service(), - NotifyTabHtmlContentDidChange(_, _, /*html=*/IsEmpty())) - .WillOnce(RunClosure(html_content_run_loop.QuitClosure())); + const ScopedKeepAlive keep_alive(KeepAliveOrigin::SESSION_RESTORE, + KeepAliveRestartOption::DISABLED); - const GURL url = https_server().GetURL(kUrlDomain, kUrlPath); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + CloseBrowserSynchronously(browser()); - html_content_run_loop.Run(); + EXPECT_CALL(ads_service_mock(), NotifyTabHtmlContentDidChange).Times(0); + RestoreBrowser(browser()); } -IN_PROC_BROWSER_TEST_F(AdsTabHelperTest, - UserHasJoinedBraveRewardsAndOptedInToNotificationAds) { +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + DoNotNotifyTabHtmlContentDidChangeForPreviouslyCommittedNavigation) { + NavigateToURL(browser(), kMultiPageApplicationWebpage); + + EXPECT_CALL(ads_service_mock(), NotifyTabHtmlContentDidChange).Times(0); + GoBack(browser()); + GoForward(browser()); + Reload(browser()); +} + +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + DoNotNotifyTabHtmlContentDidChangeForHttpClientResponseErrorPage) { GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); - GetPrefs()->SetBoolean(prefs::kOptedInToNotificationAds, true); - base::RunLoop text_content_run_loop; - EXPECT_CALL(ads_service(), - NotifyTabTextContentDidChange(_, _, /*text=*/Not(IsEmpty()))) - .WillOnce(RunClosure(text_content_run_loop.QuitClosure())); + EXPECT_CALL(ads_service_mock(), NotifyTabHtmlContentDidChange).Times(0); + SimulateHttpStatusCodePage(browser(), net::HTTP_NOT_FOUND); +} + +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + DoNotNotifyTabHtmlContentDidChangeForHttpServerResponseErrorPage) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); + + EXPECT_CALL(ads_service_mock(), NotifyTabHtmlContentDidChange).Times(0); + SimulateHttpStatusCodePage(browser(), net::HTTP_INTERNAL_SERVER_ERROR); +} - base::RunLoop html_content_run_loop; - EXPECT_CALL(ads_service(), - NotifyTabHtmlContentDidChange(_, _, /*html=*/Not(IsEmpty()))) - .WillOnce(RunClosure(html_content_run_loop.QuitClosure())); +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + NotifyTabHtmlContentDidChangeForSameDocumentNavigation) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); + + EXPECT_CALL(ads_service_mock(), + NotifyTabHtmlContentDidChange( + /*tab_id=*/::testing::_, /*redirect_chain=*/::testing::_, + /*html=*/::testing::Not(::testing::IsEmpty()))); + NavigateToURL(browser(), kSinglePageApplicationWebpage); + + EXPECT_CALL(ads_service_mock(), NotifyTabHtmlContentDidChange); + SimulateSameDocumentMouseClick(); +} + +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + NotifyTabTextContentDidChangeForRewardsUserOptedInToNotificationAds) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); + GetPrefs()->SetBoolean(prefs::kOptedInToNotificationAds, true); + + EXPECT_CALL(ads_service_mock(), + NotifyTabTextContentDidChange( + /*tab_id=*/::testing::_, /*redirect_chain=*/::testing::_, + /*text=*/::testing::Not(::testing::IsEmpty()))); + NavigateToURL(browser(), kMultiPageApplicationWebpage); +} - const GURL url = https_server().GetURL(kUrlDomain, kUrlPath); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + DoNotNotifyTabTextContentDidChangeForNonRewardsUser) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, false); - text_content_run_loop.Run(); - html_content_run_loop.Run(); + EXPECT_CALL(ads_service_mock(), NotifyTabTextContentDidChange).Times(0); + NavigateToURL(browser(), kMultiPageApplicationWebpage); } -IN_PROC_BROWSER_TEST_F(AdsTabHelperTest, - UserHasJoinedBraveRewardsAndOptedOutNotificationAds) { +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + DoNotNotifyTabTextContentDidChangeForRewardsUserOptedOutOfNotificationAds) { GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); GetPrefs()->SetBoolean(prefs::kOptedInToNotificationAds, false); - EXPECT_CALL(ads_service(), NotifyTabTextContentDidChange).Times(0); + EXPECT_CALL(ads_service_mock(), NotifyTabTextContentDidChange).Times(0); + NavigateToURL(browser(), kMultiPageApplicationWebpage); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + DoNotNotifyTabTextContentDidChangeIfTabWasRestored) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); + GetPrefs()->SetBoolean(prefs::kOptedInToNotificationAds, true); + + base::RunLoop run_loop; + EXPECT_CALL(ads_service_mock(), NotifyTabTextContentDidChange) + .WillOnce(base::test::RunClosure(run_loop.QuitClosure())); + NavigateToURL(browser(), kMultiPageApplicationWebpage); + run_loop.Run(); - base::RunLoop html_content_run_loop; - EXPECT_CALL(ads_service(), - NotifyTabHtmlContentDidChange(_, _, /*html=*/Not(IsEmpty()))) - .WillOnce(RunClosure(html_content_run_loop.QuitClosure())); + const ScopedKeepAlive keep_alive(KeepAliveOrigin::SESSION_RESTORE, + KeepAliveRestartOption::DISABLED); - const GURL url = https_server().GetURL(kUrlDomain, kUrlPath); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + CloseBrowserSynchronously(browser()); - html_content_run_loop.Run(); + EXPECT_CALL(ads_service_mock(), NotifyTabTextContentDidChange).Times(0); + RestoreBrowser(browser()); } -IN_PROC_BROWSER_TEST_F(AdsTabHelperTest, LoadSinglePageApplication) { +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + DoNotNotifyTabTextContentDidChangeForPreviouslyCommittedNavigation) { GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); GetPrefs()->SetBoolean(prefs::kOptedInToNotificationAds, true); - base::RunLoop text_content_run_loop; - EXPECT_CALL(ads_service(), - NotifyTabTextContentDidChange(_, _, /*text=*/Not(IsEmpty()))) - .WillOnce(RunClosure(text_content_run_loop.QuitClosure())); + NavigateToURL(browser(), kMultiPageApplicationWebpage); - base::RunLoop html_content_run_loop; - EXPECT_CALL(ads_service(), - NotifyTabHtmlContentDidChange(_, _, /*html=*/Not(IsEmpty()))) - .WillOnce(RunClosure(html_content_run_loop.QuitClosure())); + EXPECT_CALL(ads_service_mock(), NotifyTabTextContentDidChange).Times(0); + GoBack(browser()); + GoForward(browser()); + Reload(browser()); +} - const GURL url = - https_server().GetURL(kUrlDomain, kSinglePageApplicationUrlPath); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + DoNotNotifyTabTextContentDidChangeForHttpClientResponseErrorPage) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); + GetPrefs()->SetBoolean(prefs::kOptedInToNotificationAds, true); - text_content_run_loop.Run(); - html_content_run_loop.Run(); + EXPECT_CALL(ads_service_mock(), NotifyTabTextContentDidChange).Times(0); + SimulateHttpStatusCodePage(browser(), net::HTTP_NOT_FOUND); } -IN_PROC_BROWSER_TEST_F(AdsTabHelperTest, NotifyTabDidChange) { - base::RunLoop tab_did_change_run_loop; - EXPECT_CALL( - ads_service(), - NotifyTabDidChange(/*tab_id=*/_, /*redirect_chain=*/_, - /*is_new_navigation=*/true, /*is_restoring=*/false, - /*is_error_page_=*/false, /*is_visible=*/_)) - .WillRepeatedly(RunClosure(tab_did_change_run_loop.QuitClosure())); +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + DoNotNotifyTabTextContentDidChangeForHttpServerResponseErrorPage) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); + GetPrefs()->SetBoolean(prefs::kOptedInToNotificationAds, true); - const GURL url = https_server().GetURL(kUrlDomain, kUrlPath); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + EXPECT_CALL(ads_service_mock(), NotifyTabTextContentDidChange).Times(0); + SimulateHttpStatusCodePage(browser(), net::HTTP_INTERNAL_SERVER_ERROR); +} - tab_did_change_run_loop.Run(); +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + DoNotNotifyTabTextContentDidChangeForSameDocumentNavigation) { + GetPrefs()->SetBoolean(brave_rewards::prefs::kEnabled, true); + GetPrefs()->SetBoolean(prefs::kOptedInToNotificationAds, true); + + EXPECT_CALL(ads_service_mock(), NotifyTabTextContentDidChange); + NavigateToURL(browser(), kSinglePageApplicationWebpage); + + EXPECT_CALL(ads_service_mock(), NotifyTabTextContentDidChange).Times(0); + SimulateSameDocumentMouseClick(); } -IN_PROC_BROWSER_TEST_F(AdsTabHelperTest, - NotifyTabDidChangeForServerErrorResponsePage) { - // Mock unexpected NotifyTabDidChange calls to NotifyTabDidChange on browser - // test startup. - EXPECT_CALL(ads_service(), - NotifyTabDidChange(/*tab_id=*/_, /*redirect_chain=*/_, - /*is_new_navigation=*/_, /*is_restoring=*/_, - /*is_error_page_=*/_, /*is_visible=*/_)) - .Times(testing::AnyNumber()); +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + NotifyTabDidStartPlayingMediaForAutoplayVideo) { + GetPrefs()->SetBoolean(::prefs::kAutoplayAllowed, true); - base::RunLoop tab_did_change_run_loop; - EXPECT_CALL( - ads_service(), - NotifyTabDidChange(/*tab_id=*/_, /*redirect_chain=*/_, - /*is_new_navigation=*/true, /*is_restoring=*/false, - /*is_error_page_=*/true, /*is_visible=*/_)) - .WillRepeatedly(RunClosure(tab_did_change_run_loop.QuitClosure())); + content::WebContents* const web_contents = GetActiveWebContents(browser()); + MediaWaiter waiter(web_contents); - const GURL url = https_server().GetURL(kUrlDomain, k500ErrorPagePath); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + EXPECT_CALL(ads_service_mock(), NotifyTabDidStartPlayingMedia); + NavigateToURL(browser(), kAutoplayVideoWebpage); - tab_did_change_run_loop.Run(); + waiter.WaitForMediaStartedPlaying(); } -IN_PROC_BROWSER_TEST_F(AdsTabHelperTest, - NotifyTabDidChangeForClientErrorResponsePage) { - // Mock unexpected NotifyTabDidChange calls to NotifyTabDidChange on browser - // test startup. - EXPECT_CALL(ads_service(), - NotifyTabDidChange(/*tab_id=*/_, /*redirect_chain=*/_, - /*is_new_navigation=*/_, /*is_restoring=*/_, - /*is_error_page_=*/_, /*is_visible=*/_)) - .Times(testing::AnyNumber()); +IN_PROC_BROWSER_TEST_F( + BraveAdsTabHelperTest, + DoNotNotifyTabDidStartPlayingMediaForAutoplayVideoIfDisallowed) { + GetPrefs()->SetBoolean(::prefs::kAutoplayAllowed, false); - base::RunLoop tab_did_change_run_loop; - EXPECT_CALL( - ads_service(), - NotifyTabDidChange(/*tab_id=*/_, /*redirect_chain=*/_, - /*is_new_navigation=*/true, /*is_restoring=*/false, - /*is_error_page_=*/true, /*is_visible=*/_)) - .WillRepeatedly(RunClosure(tab_did_change_run_loop.QuitClosure())); + content::WebContents* const web_contents = GetActiveWebContents(browser()); + MediaWaiter waiter(web_contents); - const GURL url = https_server().GetURL(kUrlDomain, k404ErrorPagePath); - ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), url)); + EXPECT_CALL(ads_service_mock(), NotifyTabDidStartPlayingMedia).Times(0); + NavigateToURL(browser(), kAutoplayVideoWebpage); - tab_did_change_run_loop.Run(); + waiter.WaitForMediaSessionCreated(); } -IN_PROC_BROWSER_TEST_F(AdsTabHelperTest, IncognitoBrowser) { - const GURL url = https_server().GetURL(kUrlDomain, kUrlPath); - Browser* incognito_browser = OpenURLOffTheRecord(browser()->profile(), url); - AdsTabHelper* incognito_ads_tab_helper = - GetActiveAdsTabHelper(incognito_browser); - EXPECT_FALSE(incognito_ads_tab_helper->ads_service()); +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + NotifyTabDidStopPlayingMediaForAutoplayVideo) { + GetPrefs()->SetBoolean(::prefs::kAutoplayAllowed, true); + + content::WebContents* const web_contents = GetActiveWebContents(browser()); + MediaWaiter waiter(web_contents); + + EXPECT_CALL(ads_service_mock(), NotifyTabDidStartPlayingMedia); + NavigateToURL(browser(), kAutoplayVideoWebpage); + + waiter.WaitForMediaStartedPlaying(); + + EXPECT_CALL(ads_service_mock(), NotifyTabDidStopPlayingMedia); + PauseVideoPlayback(); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, NotifyTabDidStartPlayingMedia) { + NavigateToURL(browser(), kVideoWebpage); + + EXPECT_CALL(ads_service_mock(), NotifyTabDidStartPlayingMedia); + StartVideoPlayback(); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, NotifyTabDidStopPlayingMedia) { + NavigateToURL(browser(), kVideoWebpage); + + StartVideoPlayback(); + + EXPECT_CALL(ads_service_mock(), NotifyTabDidStopPlayingMedia); + PauseVideoPlayback(); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, NotifyDidCloseTab) { + NavigateToURL(browser(), kMultiPageApplicationWebpage); + + EXPECT_CALL(ads_service_mock(), NotifyDidCloseTab); + CloseActiveWebContents(); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + CreateAdsServiceForRegularBrowser) { + EXPECT_TRUE(GetActiveAdsTabHelper(browser())->ads_service()); +} + +IN_PROC_BROWSER_TEST_F(BraveAdsTabHelperTest, + DoNotCreateAdsServiceForIncognitoBrowser) { + const Browser* const incognito_browser = CreateIncognitoBrowser(); + ASSERT_TRUE(incognito_browser); + + EXPECT_FALSE(GetActiveAdsTabHelper(incognito_browser)->ads_service()); } } // namespace brave_ads diff --git a/test/data/brave_ads/autoplay_video.html b/test/data/brave_ads/autoplay_video.html new file mode 100644 index 000000000000..12429ed65fa4 --- /dev/null +++ b/test/data/brave_ads/autoplay_video.html @@ -0,0 +1,33 @@ + + + + + Brave stops ads from following you + + + + + +

Yeah, Brave blocks that

+ + + + + diff --git a/test/data/brave_ads/basic_page.html b/test/data/brave_ads/basic_page.html deleted file mode 100644 index a98f23c54734..000000000000 --- a/test/data/brave_ads/basic_page.html +++ /dev/null @@ -1,9 +0,0 @@ - -Basic Page - -

Page header

-

- Page content -

- - diff --git a/test/data/brave_ads/multi_page_application.html b/test/data/brave_ads/multi_page_application.html new file mode 100644 index 000000000000..6bcf38faead6 --- /dev/null +++ b/test/data/brave_ads/multi_page_application.html @@ -0,0 +1,42 @@ + + + + + Adventure Awaits + + + +

Welcome to Your Adventure

+

+ Embark on a journey of learning and discovery. Each step you take brings you closer to mastering new skills and + achieving your goals. +

+ +
+ "The only limit to our realization of tomorrow is our doubts of today." - Franklin D. Roosevelt +
+ + + + + + + + + + + + + + + + + +
TaskStatus
Learn RustCompleted
Contribute to a GitHub repositoryIn Progress
Build a mobile appPending
+ + + diff --git a/test/data/brave_ads/single_page_application.html b/test/data/brave_ads/single_page_application.html index 3bce6f88bfd0..8fe0b73894e6 100644 --- a/test/data/brave_ads/single_page_application.html +++ b/test/data/brave_ads/single_page_application.html @@ -1,48 +1,56 @@ - + + + Single Page Application - -

Header

-
  • Home
  • -
  • Eagle
  • -
  • Vulture
  • + +

    Home

    + + diff --git a/test/data/brave_ads/video.html b/test/data/brave_ads/video.html new file mode 100644 index 000000000000..d99be8d8a8e8 --- /dev/null +++ b/test/data/brave_ads/video.html @@ -0,0 +1,33 @@ + + + + + Brave stops ads from following you + + + + + +

    Yeah, Brave blocks that

    + + + + + diff --git a/test/data/brave_ads/video.mp4 b/test/data/brave_ads/video.mp4 new file mode 100644 index 000000000000..69889b2bf485 Binary files /dev/null and b/test/data/brave_ads/video.mp4 differ