chromium/chrome/browser/ui/ash/birch/birch_browsertest.cc

// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <utility>

#include "ash/birch/birch_data_provider.h"
#include "ash/birch/birch_item.h"
#include "ash/birch/birch_item_remover.h"
#include "ash/birch/birch_model.h"
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_pref_names.h"
#include "ash/constants/ash_switches.h"
#include "ash/public/cpp/test/test_new_window_delegate.h"
#include "ash/session/session_controller_impl.h"
#include "ash/shell.h"
#include "ash/wm/overview/overview_grid_test_api.h"
#include "ash/wm/overview/overview_test_util.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/memory/weak_ptr.h"
#include "base/unguessable_token.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/ash/birch/birch_keyed_service.h"
#include "chrome/browser/ui/ash/birch/birch_keyed_service_factory.h"
#include "chrome/browser/ui/ash/main_extra_parts/chrome_browser_main_extra_parts_ash.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "components/prefs/pref_service.h"
#include "content/public/test/browser_test.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/models/image_model.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/widget/widget.h"
#include "url/gurl.h"

namespace ash {
namespace {

// A weather provider that provides a single weather item.
class TestWeatherProvider : public BirchDataProvider {
 public:
  TestWeatherProvider() = default;
  ~TestWeatherProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    std::vector<BirchWeatherItem> items;
    items.emplace_back(u"Cloudy", 70.f, GURL("http://icon.com/"));
    Shell::Get()->birch_model()->SetWeatherItems(std::move(items));
  }
};

// A calendar provider that provides a single ongoing calendar event.
class TestCalendarProvider : public BirchDataProvider {
 public:
  TestCalendarProvider() = default;
  ~TestCalendarProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    std::vector<BirchCalendarItem> items;
    items.emplace_back(
        /*title=*/u"Event",
        /*start_time=*/base::Time::Now() - base::Minutes(30),
        /*end_time=*/base::Time::Now() + base::Minutes(30),
        /*calendar_url=*/GURL("http://example.com/"),
        /*conference_url=*/GURL(),
        /*event_id=*/"event_id",
        /*all_day_event=*/false);
    Shell::Get()->birch_model()->SetCalendarItems(std::move(items));

    // Also set attachments, which are normally part of calendar fetch.
    Shell::Get()->birch_model()->SetAttachmentItems({});
  }
};

// A provider that provides a single attachment.
class TestCalendarAttachmentProvider : public BirchDataProvider {
 public:
  TestCalendarAttachmentProvider() = default;
  ~TestCalendarAttachmentProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    // Also set calendar items, which are normally fetched with attachments.
    Shell::Get()->birch_model()->SetCalendarItems({});

    std::vector<BirchAttachmentItem> items;
    items.emplace_back(u"Attachment 0",
                       /*file_url=*/GURL("http://attachment.com/"),
                       /*icon_url=*/GURL("http://favicon.com/"),
                       /*start_time=*/base::Time::Now() - base::Minutes(30),
                       /*end_time=*/base::Time::Now() + base::Minutes(30),
                       /*file_id=*/"file_id0");
    Shell::Get()->birch_model()->SetAttachmentItems(std::move(items));
  }
};

// A file suggest provider that provides no files.
class EmptyFileSuggestProvider : public BirchDataProvider {
 public:
  EmptyFileSuggestProvider() = default;
  ~EmptyFileSuggestProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    Shell::Get()->birch_model()->SetFileSuggestItems({});
  }
};

// A file suggest provider that provides a single file.
class TestFileSuggestProvider : public BirchDataProvider {
 public:
  TestFileSuggestProvider() = default;
  ~TestFileSuggestProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    std::vector<BirchFileItem> items;
    items.emplace_back(base::FilePath("test-path"), "title", u"suggestion",
                       base::Time::Now() - base::Minutes(30), "file_id",
                       "icon_url");
    Shell::Get()->birch_model()->SetFileSuggestItems(std::move(items));

    // Ensure attachment data is fresh, otherwise the birch data fetch won't
    // complete. The calendar pref is disabled in the test that uses this
    // provider, so we must provide attachment data here.
    Shell::Get()->birch_model()->SetAttachmentItems({});
  }
};

// A recent tabs provider that provides a single URL.
class TestRecentTabsProvider : public BirchDataProvider {
 public:
  TestRecentTabsProvider() = default;
  ~TestRecentTabsProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    std::vector<BirchTabItem> items;
    items.emplace_back(u"tab", GURL("http://example.com/"), base::Time::Now(),
                       GURL("http://favicon.com/"), "session",
                       BirchTabItem::DeviceFormFactor::kDesktop);
    Shell::Get()->birch_model()->SetRecentTabItems(std::move(items));
  }
};

// A last active provider that provides a single URL.
class TestLastActiveProvider : public BirchDataProvider {
 public:
  TestLastActiveProvider() = default;
  ~TestLastActiveProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    std::vector<BirchLastActiveItem> items;
    items.emplace_back(u"item", GURL("http://example.com/"), base::Time());
    Shell::Get()->birch_model()->SetLastActiveItems(std::move(items));
  }
};

// A most visited provider that provides a single URL.
class TestMostVisitedProvider : public BirchDataProvider {
 public:
  TestMostVisitedProvider() = default;
  ~TestMostVisitedProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    std::vector<BirchMostVisitedItem> items;
    items.emplace_back(u"item", GURL("http://example.com/"));
    Shell::Get()->birch_model()->SetMostVisitedItems(std::move(items));
  }
};

class TestSelfShareProvider : public BirchDataProvider {
 public:
  TestSelfShareProvider() = default;
  ~TestSelfShareProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    std::vector<BirchSelfShareItem> items;
    items.emplace_back(u"guid", u"tab", GURL("http://example.com/"),
                       base::Time::Now(), u"my device",
                       SecondaryIconType::kTabFromPhone, base::DoNothing());
    Shell::Get()->birch_model()->SetSelfShareItems(std::move(items));
  }
};

class TestLostMediaProvider : public BirchDataProvider {
 public:
  TestLostMediaProvider() = default;
  ~TestLostMediaProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    std::vector<BirchLostMediaItem> items;
    items.emplace_back(GURL("https://www.source.com"), u"media title",
                       std::nullopt, SecondaryIconType::kLostMediaVideo,
                       base::BindRepeating(&TestLostMediaProvider::OnActivation,
                                           weak_factory_.GetWeakPtr()));
    Shell::Get()->birch_model()->SetLostMediaItems(std::move(items));
  }

  // Activation callback for the test lost media item.
  void OnActivation() { did_activate_ = true; }

  bool did_activate_ = false;
  base::WeakPtrFactory<TestLostMediaProvider> weak_factory_{this};
};

class TestReleaseNotesProvider : public BirchDataProvider {
 public:
  TestReleaseNotesProvider() = default;
  ~TestReleaseNotesProvider() override = default;

  // BirchDataProvider:
  void RequestBirchDataFetch() override {
    std::vector<BirchReleaseNotesItem> items;
    items.emplace_back(u"title", u"subtitle", GURL("chrome://help-app/updates"),
                       base::Time::Min());
    Shell::Get()->birch_model()->SetReleaseNotesItems(std::move(items));
  }
};

// A new window delegate that records opened files and URLs.
class MockNewWindowDelegate : public TestNewWindowDelegate {
 public:
  MockNewWindowDelegate() = default;
  ~MockNewWindowDelegate() override = default;

  // NewWindowDelegate:
  void OpenUrl(const GURL& url,
               OpenUrlFrom from,
               Disposition disposition) override {
    opened_url_ = url;
  }

  void OpenFile(const base::FilePath& file_path) override {
    opened_file_ = file_path;
  }

  GURL opened_url_;
  base::FilePath opened_file_;
};

// Ensures the item remover is initialized, otherwise data fetches won't
// complete.
void EnsureItemRemoverInitialized() {
  BirchItemRemover* remover =
      Shell::Get()->birch_model()->GetItemRemoverForTest();
  if (!remover->Initialized()) {
    base::RunLoop run_loop;
    remover->SetProtoInitCallbackForTest(run_loop.QuitClosure());
    run_loop.Run();
  }
}

// Returns the button from the birch chip bar. Asserts there is only one button.
BirchChipButtonBase* GetBirchChipButton() {
  aura::Window* root = Shell::GetPrimaryRootWindow();
  auto test_api = std::make_unique<OverviewGridTestApi>(root);
  CHECK(test_api->birch_bar_view());
  CHECK_EQ(test_api->GetBirchChips().size(), 1u);
  return test_api->GetBirchChips()[0];
}

void ClickOnView(views::View* target_view) {
  ui::test::EventGenerator event_generator(
      target_view->GetWidget()->GetNativeWindow()->GetRootWindow());
  target_view->GetWidget()->LayoutRootViewIfNecessary();
  event_generator.MoveMouseTo(target_view->GetBoundsInScreen().CenterPoint());
  event_generator.ClickLeftButton();
}

// Disables all data type prefs except the given exceptions.
void DisableAllDataTypePrefsExcept(std::vector<const char*> exceptions) {
  PrefService* pref_service =
      Shell::Get()->session_controller()->GetPrimaryUserPrefService();
  ASSERT_TRUE(pref_service);
  const char* kDataPrefs[] = {
      prefs::kBirchUseCalendar,     prefs::kBirchUseFileSuggest,
      prefs::kBirchUseChromeTabs,   prefs::kBirchUseLostMedia,
      prefs::kBirchUseReleaseNotes, prefs::kBirchUseWeather,
      prefs::kBirchUseCoral,
  };
  for (const char* pref : kDataPrefs) {
    bool enable = false;
    for (const char* exception : exceptions) {
      /*strcmp returns 0 when inputs are the same*/
      if (0 == strcmp(pref, exception)) {
        enable = true;
      }
    }
    pref_service->SetBoolean(pref, enable);
  }
}

class BirchBrowserTest : public InProcessBrowserTest {
 public:
  BirchBrowserTest() {
    feature_list_.InitWithFeatures(
        {features::kForestFeature, features::kBirchWeather}, {});
  }
  ~BirchBrowserTest() override = default;
  BirchBrowserTest(const BirchBrowserTest&) = delete;
  BirchBrowserTest& operator=(const BirchBrowserTest&) = delete;

  void SetUpOnMainThread() override {
    InProcessBrowserTest::SetUpOnMainThread();
    // Clear out the existing NewWindowDelegateProvider so we can replace it
    // with a mock (there are CHECKs that prevent doing this without the reset).
    ChromeBrowserMainExtraPartsAsh::Get()
        ->ResetNewWindowDelegateProviderForTest();
    auto window_delegate = std::make_unique<MockNewWindowDelegate>();
    mock_new_window_delegate_ = window_delegate.get();
    window_delegate_provider_ = std::make_unique<TestNewWindowDelegateProvider>(
        std::move(window_delegate));
  }

  void TearDownOnMainThread() override {
    mock_new_window_delegate_ = nullptr;  // Avoid dangling pointer.
    window_delegate_provider_.reset();
    InProcessBrowserTest::TearDownOnMainThread();
  }

  BirchKeyedService* GetBirchKeyedService() {
    return BirchKeyedServiceFactory::GetInstance()->GetService(
        browser()->profile());
  }

 protected:
  base::test::ScopedFeatureList feature_list_;
  raw_ptr<MockNewWindowDelegate> mock_new_window_delegate_;
  std::unique_ptr<TestNewWindowDelegateProvider> window_delegate_provider_;
};

// Test that no crash occurs on shutdown with an instantiated BirchKeyedService.
IN_PROC_BROWSER_TEST_F(BirchBrowserTest, NoCrashOnShutdown) {
  auto* birch_keyed_service = GetBirchKeyedService();
  EXPECT_TRUE(birch_keyed_service);
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, WeatherChip) {
  // Set up a weather provider so a single chip for weather will be created.
  Shell::Get()->birch_model()->OverrideWeatherProviderForTest(
      std::make_unique<TestWeatherProvider>());

  // Force it to be morning so the weather item will be ranked and appear.
  base::CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kBirchIsMorning);

  // Disable the prefs for data providers other than weather. This ensures the
  // data is fresh once the weather provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseWeather});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single weather chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kWeather);

  // Clicking the button closes overview and destroys the button, so avoid a
  // dangling pointer with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  // Clicking on the chip opens a browser with a Google search for weather.
  EXPECT_EQ(mock_new_window_delegate_->opened_url_,
            GURL("https://google.com/search?q=weather"));
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, CalendarChip) {
  // Set up a calendar provider that provides a single calendar chip.
  auto* birch_keyed_service = GetBirchKeyedService();
  TestCalendarProvider calendar_provider;
  birch_keyed_service->set_calendar_provider_for_test(&calendar_provider);

  // Disable the prefs for data providers other than calendar. This ensures the
  // data is fresh once the calendar provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseCalendar});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single calendar chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kCalendar);

  // Clicking the button closes overview and destroys the button, so avoid a
  // dangling pointer with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  EXPECT_EQ(mock_new_window_delegate_->opened_url_,
            GURL("http://example.com/"));
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, AttachmentChip) {
  // Set up a calendar provider that provides a single attachment.
  auto* birch_keyed_service = GetBirchKeyedService();
  TestCalendarAttachmentProvider attachment_provider;
  birch_keyed_service->set_calendar_provider_for_test(&attachment_provider);

  // The file suggest pref must be enabled to fetch attachments, so we must also
  // have a file suggest provider.
  EmptyFileSuggestProvider file_suggest_provider;
  birch_keyed_service->set_file_suggest_provider_for_test(
      &file_suggest_provider);

  // Disable the prefs for data providers other than file suggest, which
  // controls attachments. This ensures the data is fresh once the attachment
  // provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseFileSuggest});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single attachment chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kAttachment);

  // Clicking the button closes overview and destroys the button, so avoid
  // dangling pointers with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  EXPECT_EQ(mock_new_window_delegate_->opened_url_,
            GURL("http://attachment.com/"));
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, FileSuggestChip) {
  // Set up a file suggest provider that provides a single file.
  auto* birch_keyed_service = GetBirchKeyedService();
  TestFileSuggestProvider test_provider;
  birch_keyed_service->set_file_suggest_provider_for_test(&test_provider);

  // Disable the prefs for data providers other than file suggest. This ensures
  // the data is fresh once the calendar provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseFileSuggest});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single file chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kFile);

  // Clicking the button closes overview and destroys the button, so avoid a
  // dangling pointer with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  // Clicking the button should attempt to open the file.
  EXPECT_EQ(mock_new_window_delegate_->opened_file_,
            base::FilePath("test-path"));
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, RecentTabsChip) {
  // Set up a provider that provides a single chip.
  auto* birch_keyed_service = GetBirchKeyedService();
  TestRecentTabsProvider recent_tabs_provider;
  birch_keyed_service->set_recent_tabs_provider_for_test(&recent_tabs_provider);

  // Disable the prefs for data providers other than chrome tabs. This ensures
  // the data is fresh once the test provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseChromeTabs});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kTab);

  // Clicking the button closes overview and destroys the button, so avoid a
  // dangling pointer with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  // Clicking the button should attempt to open the URL.
  EXPECT_EQ(mock_new_window_delegate_->opened_url_,
            GURL("http://example.com/"));
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, LastActiveChip) {
  // Set up a last active provider that provides a single chip.
  auto* birch_keyed_service = GetBirchKeyedService();
  TestLastActiveProvider last_active_provider;
  birch_keyed_service->set_last_active_provider_for_test(&last_active_provider);

  // Last active chips only show in the morning so force morning in the ranker.
  base::CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kBirchIsMorning);

  // Disable the prefs for data providers other than chrome tabs. This ensures
  // the data is fresh once the last active provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseChromeTabs});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kLastActive);

  // Clicking the button closes overview and destroys the button, so avoid a
  // dangling pointer with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  // Clicking the button should attempt to open the URL.
  EXPECT_EQ(mock_new_window_delegate_->opened_url_,
            GURL("http://example.com/"));
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, MostVisitedChip) {
  // Set up a most visited provider that provides a single chip.
  auto* birch_keyed_service = GetBirchKeyedService();
  TestMostVisitedProvider most_visited_provider;
  birch_keyed_service->set_most_visited_provider_for_test(
      &most_visited_provider);

  // Most visited chips only show in the morning so force morning in the ranker.
  base::CommandLine::ForCurrentProcess()->AppendSwitch(
      switches::kBirchIsMorning);

  // Disable the prefs for data providers other than chrome tabs. This ensures
  // the data is fresh once the most visited provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseChromeTabs});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kMostVisited);

  // Clicking the button closes overview and destroys the button, so avoid a
  // dangling pointer with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  // Clicking the button should attempt to open the URL.
  EXPECT_EQ(mock_new_window_delegate_->opened_url_,
            GURL("http://example.com/"));
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, SelfShareChip) {
  // Set up a self share provider that provides a single chip.
  auto* birch_keyed_service = GetBirchKeyedService();
  TestSelfShareProvider self_share_provider;
  birch_keyed_service->set_self_share_provider_for_test(&self_share_provider);

  // Disable the prefs for data providers other than chrome tabs. This ensures
  // the data is fresh once the self share provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseChromeTabs});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kSelfShare);

  // Clicking the button closes overview and destroys the button, so avoid a
  // dangling pointer with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  // Clicking the button should attempt to open the URL.
  EXPECT_EQ(mock_new_window_delegate_->opened_url_,
            GURL("http://example.com/"));
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, LostMediaChip) {
  // Set up a provider that provides a single chip.
  auto* birch_keyed_service = GetBirchKeyedService();
  TestLostMediaProvider lost_media_provider;
  birch_keyed_service->set_lost_media_provider_for_test(&lost_media_provider);

  // Disable the prefs for data providers other than lost media. This ensures
  // the data is fresh once the lost media provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseLostMedia});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kLostMedia);

  // Clicking the button closes overview and destroys the button, so avoid a
  // dangling pointer with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  // Clicking the button should activate the item. In this test the activation
  // callback is bound to the provider.
  EXPECT_TRUE(lost_media_provider.did_activate_);

  // Reset lost media provider.
  birch_keyed_service->set_lost_media_provider_for_test(nullptr);
}

IN_PROC_BROWSER_TEST_F(BirchBrowserTest, ReleaseNotesChip) {
  // Set up a provider that provides a single chip.
  auto* birch_keyed_service = GetBirchKeyedService();
  TestReleaseNotesProvider provider;
  birch_keyed_service->set_release_notes_provider_for_test(&provider);

  // Disable the prefs for data providers other than release notes. This
  // ensures the data is fresh once the release notes provider replies.
  DisableAllDataTypePrefsExcept(
      std::vector<const char*>{prefs::kBirchUseReleaseNotes});

  // Ensure the item remover is initialized, otherwise data fetches won't
  // complete.
  EnsureItemRemoverInitialized();

  // Set up a callback for a birch data fetch.
  base::RunLoop birch_data_fetch_waiter;
  Shell::Get()->birch_model()->SetDataFetchCallbackForTest(
      birch_data_fetch_waiter.QuitClosure());

  // Enter overview, which triggers a birch data fetch.
  ToggleOverview();
  WaitForOverviewEntered();

  // Wait for fetch callback to complete.
  birch_data_fetch_waiter.Run();

  // The birch bar is created with a single chip.
  BirchChipButtonBase* button = GetBirchChipButton();
  EXPECT_EQ(button->GetItem()->GetType(), BirchItemType::kReleaseNotes);

  // Clicking the button closes overview and destroys the button, so avoid a
  // dangling pointer with std::exchange.
  ClickOnView(std::exchange(button, nullptr));

  // Clicking the button should attempt to open the URL.
  EXPECT_EQ(mock_new_window_delegate_->opened_url_,
            GURL("chrome://help-app/updates"));
}

}  // namespace
}  // namespace ash