blob: c4fd93327838ac849405e6687886b1ce96fe99e1 [file] [log] [blame]
// Copyright 2022 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/user_notes/user_notes_tab_helper.h"
#include <memory>
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/user_notes/user_note_service_factory.h"
#include "chrome/test/base/chrome_render_view_host_test_harness.h"
#include "components/user_notes/browser/user_note_manager.h"
#include "components/user_notes/browser/user_note_service.h"
#include "components/user_notes/interfaces/user_note_service_delegate.h"
#include "components/user_notes/user_notes_features.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/test/navigation_simulator.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
using testing::_;
using testing::Mock;
namespace user_notes {
namespace {
const char kTestDomain[] = "http://www.google.com/";
// Matcher that verifies whether the page has an attached `UserNoteManager` via
// the navigation handle supplied as arg.
MATCHER(HasUserNoteManager, "") {
return arg != nullptr && UserNoteManager::GetForPage(
arg->GetRenderFrameHost()->GetPage()) != nullptr;
}
} // namespace
class MockUserNoteService : public UserNoteService {
public:
// A service delegate and user note storage are not needed for these tests, so
// pass nullptr.
MockUserNoteService()
: UserNoteService(/*delegate=*/nullptr, /*storage=*/nullptr) {}
MOCK_METHOD(void,
OnFrameNavigated,
(content::RenderFrameHost * rfh),
(override));
};
class MockUserNotesTabHelper : public UserNotesTabHelper {
public:
explicit MockUserNotesTabHelper(content::WebContents* web_contents)
: UserNotesTabHelper(web_contents) {}
MOCK_METHOD(void,
DidFinishNavigation,
(content::NavigationHandle * navigation_handle),
(override));
};
class UserNotesTabHelperTest : public ChromeRenderViewHostTestHarness {
protected:
void SetUp() override {
scoped_feature_list_.InitAndEnableFeature(user_notes::kUserNotes);
UserNoteServiceFactory::SetServiceForTesting(
std::make_unique<MockUserNoteService>());
ChromeRenderViewHostTestHarness::SetUp();
}
void AttachTabHelper(std::unique_ptr<UserNotesTabHelper> tab_helper) {
const auto* user_data_key = tab_helper->UserDataKey();
web_contents()->SetUserData(user_data_key, std::move(tab_helper));
}
void GoBack() { content::NavigationSimulator::GoBack(web_contents()); }
void GoForward() { content::NavigationSimulator::GoForward(web_contents()); }
void SimluateNavigation() {
// Note: Simulating a navigation with the same URL as before causes the
// navigation to be treated as a refresh, so use a counter to keep the URLs
// unique.
static int unique_int = 0;
NavigateAndCommit(GURL(kTestDomain + base::NumberToString(++unique_int)));
}
content::NavigationEntry* GetLastCommittedEntry() {
return web_contents()->GetController().GetLastCommittedEntry();
}
base::test::ScopedFeatureList scoped_feature_list_;
};
// Tests that by the time `UserNotesTabHelper::DidFinishNavigation` is called,
// a `UserNoteManager` is already attached to the `Page` of the navigated
// frame.
TEST_F(UserNotesTabHelperTest, AttachUserNoteManagerToPage) {
// Partially mock the `UserNotesTabHelper` to intercept calls to
// `DidFinishNavigation` and prevent side effects.
auto mock_tab_helper =
std::make_unique<MockUserNotesTabHelper>(web_contents());
EXPECT_CALL(*mock_tab_helper, DidFinishNavigation(HasUserNoteManager()))
.Times(4);
AttachTabHelper(std::move(mock_tab_helper));
// Verify for a normal navigation.
SimluateNavigation();
// Verify for a back navigation.
SimluateNavigation();
GoBack();
// Verify for a forward navigation.
GoForward();
}
// Tests that the `UserNotesTabHelper` properly notifies the `UserNoteService`
// when a frame navigates.
TEST_F(UserNotesTabHelperTest, NotifyServiceOfNavigationWhenNeeded) {
// Use a real `UserNotesTabHelper` so the service gets noitified.
std::unique_ptr<UserNotesTabHelper> tab_helper =
UserNotesTabHelper::CreateForTest(web_contents());
AttachTabHelper(std::move(tab_helper));
// Verify for a normal navigation.
auto* service = static_cast<MockUserNoteService*>(
UserNoteServiceFactory::GetForContext(nullptr));
EXPECT_CALL(*service, OnFrameNavigated(_)).Times(1);
SimluateNavigation();
Mock::VerifyAndClearExpectations(service);
// Verify for a back navigation.
EXPECT_CALL(*service, OnFrameNavigated(_)).Times(2);
SimluateNavigation();
GoBack();
Mock::VerifyAndClearExpectations(service);
// Verify for a forward navigation.
EXPECT_CALL(*service, OnFrameNavigated(_)).Times(1);
GoForward();
Mock::VerifyAndClearExpectations(service);
}
} // namespace user_notes