blob: e1a6e4c491c7498297670cc52fc1d75fd67ae304 [file]
// Copyright 2026 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/ui/startup/startup_infobar_observer.h"
#include <memory>
#include <utility>
#include "base/test/test_future.h"
#include "chrome/browser/ui/browser_window/public/browser_window_features.h"
#include "chrome/browser/ui/browser_window/test/mock_browser_window_interface.h"
#include "chrome/browser/ui/tabs/tab_model.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/tabs/test_tab_strip_model_delegate.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/browser_task_environment.h"
#include "content/public/test/test_renderer_host.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/unowned_user_data/unowned_user_data_host.h"
using testing::Return;
using testing::ReturnRef;
class StartupInfoBarObserverTest : public testing::Test {
protected:
StartupInfoBarObserverTest() = default;
~StartupInfoBarObserverTest() override = default;
void SetUp() override {
profile_ = TestingProfile::Builder().Build();
tab_strip_model_ = std::make_unique<TabStripModel>(
&tab_strip_model_delegate_, profile_.get());
browser_interface_ =
std::make_unique<testing::NiceMock<MockBrowserWindowInterface>>();
tab_strip_model_delegate_.SetBrowserWindowInterface(
browser_interface_.get());
ON_CALL(*browser_interface_, GetTabStripModel())
.WillByDefault(Return(tab_strip_model_.get()));
ON_CALL(static_cast<const MockBrowserWindowInterface&>(*browser_interface_),
GetUnownedUserDataHost())
.WillByDefault(ReturnRef(user_data_host_));
ON_CALL(*browser_interface_, GetProfile())
.WillByDefault(Return(profile_.get()));
}
StartupInfoBarObserver* CreateObserver(
StartupInfoBarObserver::AddInfoBarsCallback callback) {
StartupInfoBarObserver::ObserveProfile(*profile(), std::move(callback));
return static_cast<StartupInfoBarObserver*>(profile()->GetUserData(
&StartupInfoBarObserver::kStartupInfoBarObserverKey));
}
TestingProfile* profile() { return profile_.get(); }
MockBrowserWindowInterface* browser() { return browser_interface_.get(); }
TabStripModel* tab_strip_model() { return tab_strip_model_.get(); }
private:
content::BrowserTaskEnvironment task_environment_;
content::RenderViewHostTestEnabler rvh_test_enabler_;
tabs::TabModel::PreventFeatureInitializationForTesting prevent_;
std::unique_ptr<TestingProfile> profile_;
ui::UnownedUserDataHost user_data_host_;
std::unique_ptr<MockBrowserWindowInterface> browser_interface_;
TestTabStripModelDelegate tab_strip_model_delegate_;
std::unique_ptr<TabStripModel> tab_strip_model_;
};
TEST_F(StartupInfoBarObserverTest, DoesNotRunOnBrowserCreated) {
base::test::TestFuture<BrowserWindowInterface*> future;
StartupInfoBarObserver* observer = CreateObserver(future.GetCallback());
// Browser created but empty.
observer->OnBrowserCreated(browser());
EXPECT_FALSE(future.IsReady());
ASSERT_NE(nullptr, profile()->GetUserData(
&StartupInfoBarObserver::kStartupInfoBarObserverKey));
}
TEST_F(StartupInfoBarObserverTest, RunsCallbackOnTabInserted) {
base::test::TestFuture<BrowserWindowInterface*> future;
StartupInfoBarObserver* observer = CreateObserver(future.GetCallback());
observer->OnBrowserCreated(browser());
// Adding a tab should trigger the infobar creation and delete the observer.
std::unique_ptr<content::WebContents> contents =
content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
tab_strip_model()->AppendWebContents(std::move(contents), true);
EXPECT_TRUE(future.IsReady());
EXPECT_EQ(nullptr, profile()->GetUserData(
&StartupInfoBarObserver::kStartupInfoBarObserverKey));
}
TEST_F(StartupInfoBarObserverTest, HandlesTabStripModelDestruction) {
base::test::TestFuture<BrowserWindowInterface*> future;
StartupInfoBarObserver* observer = CreateObserver(future.GetCallback());
observer->OnBrowserCreated(browser());
// Destroying the tab strip model before inserting a tab should delete the
// observer.
observer->OnTabStripModelDestroyed(tab_strip_model());
EXPECT_FALSE(future.IsReady());
EXPECT_EQ(nullptr, profile()->GetUserData(
&StartupInfoBarObserver::kStartupInfoBarObserverKey));
}
TEST_F(StartupInfoBarObserverTest, IgnoresNonInsertionTabStripChanges) {
base::test::TestFuture<BrowserWindowInterface*> future;
StartupInfoBarObserver* observer = CreateObserver(future.GetCallback());
observer->OnBrowserCreated(browser());
// Simulate a change other than kInserted.
TabStripSelectionChange selection;
TabStripModelChange change;
observer->OnTabStripModelChanged(tab_strip_model(), change, selection);
// Callback shouldn't trigger and observer should still be alive since the
// change wasn't kInserted.
EXPECT_FALSE(future.IsReady());
EXPECT_NE(nullptr, profile()->GetUserData(
&StartupInfoBarObserver::kStartupInfoBarObserverKey));
}