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

#include "ash/quick_insert/views/quick_insert_view.h"

#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>

#include "ash/constants/ash_features.h"
#include "ash/quick_insert/metrics/quick_insert_session_metrics.h"
#include "ash/quick_insert/mock_quick_insert_asset_fetcher.h"
#include "ash/quick_insert/model/quick_insert_action_type.h"
#include "ash/quick_insert/model/quick_insert_caps_lock_position.h"
#include "ash/quick_insert/model/quick_insert_search_results_section.h"
#include "ash/quick_insert/quick_insert_category.h"
#include "ash/quick_insert/quick_insert_controller.h"
#include "ash/quick_insert/quick_insert_search_result.h"
#include "ash/quick_insert/views/quick_insert_category_type.h"
#include "ash/quick_insert/views/quick_insert_contents_view.h"
#include "ash/quick_insert/views/quick_insert_emoji_bar_view.h"
#include "ash/quick_insert/views/quick_insert_emoji_item_view.h"
#include "ash/quick_insert/views/quick_insert_gif_view.h"
#include "ash/quick_insert/views/quick_insert_image_item_view.h"
#include "ash/quick_insert/views/quick_insert_item_view.h"
#include "ash/quick_insert/views/quick_insert_list_item_view.h"
#include "ash/quick_insert/views/quick_insert_preview_bubble.h"
#include "ash/quick_insert/views/quick_insert_preview_bubble_controller.h"
#include "ash/quick_insert/views/quick_insert_search_bar_textfield.h"
#include "ash/quick_insert/views/quick_insert_search_field_view.h"
#include "ash/quick_insert/views/quick_insert_search_results_view.h"
#include "ash/quick_insert/views/quick_insert_section_list_view.h"
#include "ash/quick_insert/views/quick_insert_section_view.h"
#include "ash/quick_insert/views/quick_insert_style.h"
#include "ash/quick_insert/views/quick_insert_submenu_controller.h"
#include "ash/quick_insert/views/quick_insert_submenu_view.h"
#include "ash/quick_insert/views/quick_insert_view_delegate.h"
#include "ash/quick_insert/views/quick_insert_widget.h"
#include "ash/quick_insert/views/quick_insert_zero_state_view.h"
#include "ash/strings/grit/ash_strings.h"
#include "ash/style/icon_button.h"
#include "ash/test/ash_test_base.h"
#include "ash/test/view_drawn_waiter.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/scoped_observation.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/bind.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/scoped_feature_list.h"
#include "base/test/test_future.h"
#include "base/time/time.h"
#include "build/branding_buildflags.h"
#include "components/metrics/structured/structured_events.h"
#include "components/metrics/structured/test/test_structured_metrics_recorder.h"
#include "testing/gmock/include/gmock/gmock-matchers.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/emoji/emoji_panel_helper.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/image_model.h"
#include "ui/chromeos/styles/cros_tokens_color_mappings.h"
#include "ui/display/screen.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/keycodes/keyboard_codes_posix.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/accessibility/ax_update_notifier.h"
#include "ui/views/background.h"
#include "ui/views/controls/image_view.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/test/ax_event_counter.h"
#include "ui/views/test/widget_test.h"
#include "ui/views/view.h"
#include "ui/views/view_utils.h"
#include "url/gurl.h"

#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
#include "chromeos/ash/resources/internal/strings/grit/ash_internal_strings.h"
#endif  // BUILDFLAG(GOOGLE_CHROME_BRANDING)

namespace ash {
namespace {

namespace cros_events = metrics::structured::events::v2::cr_os_events;

using ::testing::AllOf;
using ::testing::ElementsAre;
using ::testing::Eq;
using ::testing::Field;
using ::testing::IsEmpty;
using ::testing::Not;
using ::testing::Optional;
using ::testing::Pointee;
using ::testing::Property;
using ::testing::ResultOf;
using ::testing::Truly;
using ::testing::VariantWith;

constexpr gfx::Rect kDefaultAnchorBounds(200, 100, 0, 10);

template <class V, class Matcher>
auto AsView(Matcher matcher) {
  return ResultOf(
      "AsViewClass",
      [](views::View* view) { return views::AsViewClass<V>(view); },
      Pointee(matcher));
}

auto ContainsEvent(const metrics::structured::Event& event) {
  return Contains(AllOf(
      Property("event name", &metrics::structured::Event::event_name,
               Eq(event.event_name())),
      Property("metric values", &metrics::structured::Event::metric_values,
               Eq(std::ref(event.metric_values())))));
}

class QuickInsertPreviewBubbleVisibleWaiter
    : public QuickInsertPreviewBubbleController::Observer {
 public:
  void Wait(QuickInsertPreviewBubbleController* preview_controller) {
    if (!preview_controller->IsBubbleVisible()) {
      preview_bubble_observation_.Observe(preview_controller);
      run_loop_.Run();
    }
  }

  void OnPreviewBubbleVisibilityChanged(bool visible) override {
    if (visible) {
      run_loop_.Quit();
    }
  }

 private:
  base::RunLoop run_loop_;
  base::ScopedObservation<QuickInsertPreviewBubbleController,
                          QuickInsertPreviewBubbleController::Observer>
      preview_bubble_observation_{this};
};

class QuickInsertViewTest : public AshTestBase {
 public:
  QuickInsertViewTest()
      : AshTestBase(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}

  void SetUp() override {
    AshTestBase::SetUp();
    metrics_recorder_.Initialize();
  }

 protected:
  metrics::structured::TestStructuredMetricsRecorder metrics_recorder_;
};

// QuickInsertViewTest parameterized by the Emoji Category.
class QuickInsertViewEmojiTest
    : public QuickInsertViewTest,
      public testing::WithParamInterface<QuickInsertCategory> {};

INSTANTIATE_TEST_SUITE_P(,
                         QuickInsertViewEmojiTest,
                         testing::ValuesIn({QuickInsertCategory::kEmojisGifs,
                                            QuickInsertCategory::kEmojis}));

class FakeQuickInsertViewDelegate : public QuickInsertViewDelegate {
 public:
  using FakeSearchFunction =
      base::RepeatingCallback<void(std::u16string_view query,
                                   SearchResultsCallback callback)>;
  using FakeCategorySearchFunction =
      base::RepeatingCallback<void(SearchResultsCallback callback)>;

  struct Options {
    std::vector<QuickInsertCategory> available_categories;
    std::vector<QuickInsertSearchResult> zero_state_suggested_results;
    FakeSearchFunction search_function;
    base::RepeatingClosure stop_search_function;
    FakeCategorySearchFunction category_results_function;
    QuickInsertActionType action_type = QuickInsertActionType::kInsert;
    std::vector<QuickInsertEmojiResult> emoji_results;
    std::vector<std::string> suggested_emojis;
    QuickInsertModeType mode = QuickInsertModeType::kNoSelection;
  };

  FakeQuickInsertViewDelegate() = default;
  explicit FakeQuickInsertViewDelegate(Options options) : options_(options) {}

  std::vector<QuickInsertCategory> GetAvailableCategories() override {
    if (options_.available_categories.empty()) {
      // Use at least one category.
      return {QuickInsertCategory::kLinks};
    }
    return options_.available_categories;
  }

  void GetZeroStateSuggestedResults(
      SuggestedResultsCallback callback) override {
    callback.Run(options_.zero_state_suggested_results);
  }

  void GetResultsForCategory(QuickInsertCategory category,
                             SearchResultsCallback callback) override {
    if (options_.category_results_function.is_null()) {
      std::move(callback).Run({});
    } else {
      options_.category_results_function.Run(std::move(callback));
    }
  }

  void StartSearch(std::u16string_view query,
                   std::optional<QuickInsertCategory> category,
                   SearchResultsCallback callback) override {
    if (options_.search_function.is_null()) {
      std::move(callback).Run({});
    } else {
      options_.search_function.Run(query, std::move(callback));
    }
  }

  void StopSearch() override {
    if (!options_.stop_search_function.is_null()) {
      options_.stop_search_function.Run();
    }
  }

  void StartEmojiSearch(std::u16string_view query,
                        EmojiSearchResultsCallback callback) override {
    std::move(callback).Run(options_.emoji_results);
  }

  void CloseWidgetThenInsertResultOnNextFocus(
      const QuickInsertSearchResult& result) override {
    last_inserted_result_ = result;
    session_metrics_.SetOutcome(
        QuickInsertSessionMetrics::SessionOutcome::kInsertedOrCopied);
  }
  void OpenResult(const QuickInsertSearchResult& result) override {
    last_opened_result_ = result;
  }

  void ShowEmojiPicker(ui::EmojiPickerCategory category,
                       std::u16string_view query) override {
    emoji_picker_category_ = category;
    emoji_picker_query_ = std::u16string(query);
  }
  void ShowEditor(std::optional<std::string> preset_query_id,
                  std::optional<std::string> freeform_text) override {
    showed_editor_ = true;
  }
  void ShowLobster(std::optional<std::string> freeform_text) override {
    showed_lobster_ = true;
  }

  QuickInsertAssetFetcher* GetAssetFetcher() override {
    return &asset_fetcher_;
  }

  QuickInsertSessionMetrics& GetSessionMetrics() override {
    return session_metrics_;
  }
  QuickInsertActionType GetActionForResult(
      const QuickInsertSearchResult& result) override {
    return options_.action_type;
  }

  std::vector<QuickInsertEmojiResult> GetSuggestedEmoji() override {
    std::vector<QuickInsertEmojiResult> results;
    for (const std::string& emoji : options_.suggested_emojis) {
      results.push_back(
          QuickInsertEmojiResult::Emoji(base::UTF8ToUTF16(emoji)));
    }
    return results;
  }

  bool IsGifsEnabled() override { return true; }
  QuickInsertModeType GetMode() override { return options_.mode; }

  QuickInsertCapsLockPosition GetCapsLockPosition() override {
    return QuickInsertCapsLockPosition::kTop;
  }

  std::optional<QuickInsertSearchResult> last_inserted_result() const {
    return last_inserted_result_;
  }
  std::optional<QuickInsertSearchResult> last_opened_result() const {
    return last_opened_result_;
  }

  std::optional<ui::EmojiPickerCategory> emoji_picker_category() const {
    return emoji_picker_category_;
  }
  std::optional<std::u16string> emoji_picker_query() const {
    return emoji_picker_query_;
  }
  bool showed_editor() const { return showed_editor_; }

  // TODO: b/348279987 - Adds unit test once the Lobster entry point is added to
  // zero state.
  bool showed_lobster() const { return showed_lobster_; }

 private:
  Options options_;
  MockQuickInsertAssetFetcher asset_fetcher_;
  QuickInsertSessionMetrics session_metrics_;
  std::optional<QuickInsertSearchResult> last_inserted_result_;
  std::optional<QuickInsertSearchResult> last_opened_result_;
  std::optional<ui::EmojiPickerCategory> emoji_picker_category_;
  std::optional<std::u16string> emoji_picker_query_;
  bool showed_editor_ = false;
  bool showed_lobster_ = false;
};

QuickInsertView* GetQuickInsertViewFromWidget(views::Widget& widget) {
  return views::AsViewClass<QuickInsertView>(
      widget.non_client_view()->client_view()->children().front());
}

// Gets the first category item view that can be clicked to select a category.
QuickInsertItemView* GetFirstCategoryItemView(
    QuickInsertView* quick_insert_view) {
  return quick_insert_view->zero_state_view_for_testing()
      .category_section_views_for_testing()
      .begin()
      ->second->item_views_for_testing()[0];
}

TEST_P(QuickInsertViewEmojiTest,
       SizeIsLessThanMaxWhenNoContentWithoutEmojiBar) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {GetParam()},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);

  EXPECT_EQ(view->size().width(), kQuickInsertViewWidth);
  EXPECT_LT(view->size().height(), 300);
}

TEST_P(QuickInsertViewEmojiTest, SizeIsLessThanMaxWhenNoContentWithEmojiBar) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {GetParam()},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);

  EXPECT_EQ(view->size().width(), kQuickInsertViewWidth);
  EXPECT_LT(view->size().height(), 356);
}

TEST_F(QuickInsertViewTest, SizeIsMaxWhenLotsOfContentWithoutEmojiBar) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
      .zero_state_suggested_results = std::vector<QuickInsertSearchResult>(
          10, QuickInsertTextResult(u"abc")),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);

  EXPECT_EQ(view->size(), gfx::Size(kQuickInsertViewWidth, 300));
}

TEST_P(QuickInsertViewEmojiTest, SizeIsMaxWhenLotsOfContentWithEmojiBar) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {GetParam()},
      .zero_state_suggested_results = std::vector<QuickInsertSearchResult>(
          10, QuickInsertTextResult(u"abc")),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);

  EXPECT_EQ(view->size(), gfx::Size(kQuickInsertViewWidth, 356));
}

TEST_F(QuickInsertViewTest, ShowsZeroStateView) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);

  EXPECT_THAT(view->search_field_view_for_testing(),
              Property(&views::View::GetVisible, true));
  EXPECT_THAT(view->zero_state_view_for_testing(),
              Property(&views::View::GetVisible, true));
  EXPECT_THAT(view->search_results_view_for_testing(),
              Property(&views::View::GetVisible, false));
}

#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
TEST_F(QuickInsertViewTest, SearchPlaceholderMatchesUnfocusedMode) {
  FakeQuickInsertViewDelegate delegate({
      .mode = QuickInsertModeType::kUnfocused,
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_EQ(quick_insert_view->search_field_view_for_testing()
                .textfield_for_testing()
                .GetPlaceholderText(),
            l10n_util::GetStringUTF16(
                IDS_PICKER_SEARCH_FIELD_NO_FOCUS_PLACEHOLDER_TEXT));
}

TEST_F(QuickInsertViewTest, SearchPlaceholderMatchesNoSelectionModeWithEditor) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEditorWrite},
      .mode = QuickInsertModeType::kNoSelection,
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_EQ(
      quick_insert_view->search_field_view_for_testing()
          .textfield_for_testing()
          .GetPlaceholderText(),
      l10n_util::GetStringUTF16(
          IDS_PICKER_SEARCH_FIELD_NO_SELECTION_WITH_EDITOR_PLACEHOLDER_TEXT));
}

TEST_F(QuickInsertViewTest,
       SearchPlaceholderMatchesNoSelectionModeWithoutEditor) {
  FakeQuickInsertViewDelegate delegate({
      .mode = QuickInsertModeType::kNoSelection,
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_EQ(quick_insert_view->search_field_view_for_testing()
                .textfield_for_testing()
                .GetPlaceholderText(),
            l10n_util::GetStringUTF16(
                IDS_PICKER_SEARCH_FIELD_NO_SELECTION_PLACEHOLDER_TEXT));
}

TEST_F(QuickInsertViewTest,
       SearchPlaceholderMatchesHasSelectionModeWithEditor) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEditorRewrite},
      .mode = QuickInsertModeType::kHasSelection,
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_EQ(
      quick_insert_view->search_field_view_for_testing()
          .textfield_for_testing()
          .GetPlaceholderText(),
      l10n_util::GetStringUTF16(
          IDS_PICKER_SEARCH_FIELD_HAS_SELECTION_WITH_EDITOR_PLACEHOLDER_TEXT));
}

TEST_F(QuickInsertViewTest,
       SearchPlaceholderMatchesHasSelectionModeWithoutEditor) {
  FakeQuickInsertViewDelegate delegate({
      .mode = QuickInsertModeType::kHasSelection,
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_EQ(quick_insert_view->search_field_view_for_testing()
                .textfield_for_testing()
                .GetPlaceholderText(),
            l10n_util::GetStringUTF16(
                IDS_PICKER_SEARCH_FIELD_HAS_SELECTION_PLACEHOLDER_TEXT));
}
#endif

TEST_F(QuickInsertViewTest,
       NonEmptySearchFieldContentsSwitchesToSearchResultsView) {
  FakeQuickInsertViewDelegate delegate;
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  EXPECT_THAT(view->zero_state_view_for_testing(),
              Property(&views::View::GetVisible, false));
  EXPECT_THAT(view->search_results_view_for_testing(),
              Property(&views::View::GetVisible, true));
}

TEST_F(QuickInsertViewTest, EmptySearchFieldContentsSwitchesToZeroStateView) {
  FakeQuickInsertViewDelegate delegate;
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);

  EXPECT_THAT(view->zero_state_view_for_testing(),
              Property(&views::View::GetVisible, true));
  EXPECT_THAT(view->search_results_view_for_testing(),
              Property(&views::View::GetVisible, false));
}

TEST_F(QuickInsertViewTest, LeftClickSearchResultInsertsResult) {
  {
    base::test::TestFuture<void> future;
    FakeQuickInsertViewDelegate delegate({
        .search_function = base::BindLambdaForTesting(
            [&](std::u16string_view query,
                FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
              future.SetValue();
              callback.Run({
                  QuickInsertSearchResultsSection(
                      QuickInsertSectionType::kClipboard,
                      {{QuickInsertTextResult(u"result")}},
                      /*has_more_results=*/false),
              });
            }),
        .action_type = QuickInsertActionType::kInsert,
    });
    auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
    widget->Show();
    QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
    PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
    ASSERT_TRUE(future.Wait());
    ASSERT_THAT(
        view->search_results_view_for_testing().section_views_for_testing(),
        Not(IsEmpty()));
    ASSERT_THAT(view->search_results_view_for_testing()
                    .section_views_for_testing()[0]
                    ->item_views_for_testing(),
                Not(IsEmpty()));

    QuickInsertItemView* result_view = view->search_results_view_for_testing()
                                           .section_views_for_testing()[0]
                                           ->item_views_for_testing()[0];
    ViewDrawnWaiter().Wait(result_view);
    LeftClickOn(result_view);

    EXPECT_EQ(delegate.last_opened_result(), std::nullopt);
    EXPECT_THAT(delegate.last_inserted_result(),
                Optional(QuickInsertTextResult(u"result")));
  }

  cros_events::Picker_FinishSession expected_event;
  expected_event
      .SetOutcome(cros_events::PickerSessionOutcome::INSERTED_OR_COPIED)
      .SetAction(cros_events::PickerAction::UNKNOWN)
      .SetResultSource(cros_events::PickerResultSource::UNKNOWN)
      .SetResultType(cros_events::PickerResultType::TEXT)
      .SetTotalEdits(1)
      .SetFinalQuerySize(1)
      .SetResultIndex(0);
  EXPECT_THAT(metrics_recorder_.GetEvents(), ContainsEvent(expected_event));
}

TEST_F(QuickInsertViewTest, LeftClickZeroStateSuggestedResultInsertsResult) {
  {
    base::test::TestFuture<void> future;
    FakeQuickInsertViewDelegate delegate({
        .available_categories = {QuickInsertCategory::kLinks},
        .zero_state_suggested_results = std::vector<QuickInsertSearchResult>(
            10, QuickInsertTextResult(u"abc")),
        .action_type = QuickInsertActionType::kInsert,
    });
    auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
    widget->Show();
    QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
    QuickInsertItemView* result_view = view->zero_state_view_for_testing()
                                           .primary_section_view_for_testing()
                                           ->item_views_for_testing()[0];
    ViewDrawnWaiter().Wait(result_view);
    LeftClickOn(result_view);

    EXPECT_EQ(delegate.last_opened_result(), std::nullopt);
    EXPECT_THAT(delegate.last_inserted_result(),
                Optional(QuickInsertTextResult(u"abc")));
  }

  cros_events::Picker_FinishSession expected_event;
  expected_event
      .SetOutcome(cros_events::PickerSessionOutcome::INSERTED_OR_COPIED)
      .SetAction(cros_events::PickerAction::UNKNOWN)
      .SetResultSource(cros_events::PickerResultSource::UNKNOWN)
      .SetResultType(cros_events::PickerResultType::TEXT)
      .SetTotalEdits(0)
      .SetFinalQuerySize(0)
      .SetResultIndex(-1);
  EXPECT_THAT(metrics_recorder_.GetEvents(), ContainsEvent(expected_event));
}

TEST_F(QuickInsertViewTest, LeftClickSearchResultOpensResult) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kLinks,
                    {QuickInsertBrowsingHistoryResult({}, u"a", {})},
                    /*has_more_results=*/false),
            });
          }),
      .action_type = QuickInsertActionType::kOpen,
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  ASSERT_THAT(
      view->search_results_view_for_testing().section_views_for_testing(),
      Not(IsEmpty()));
  ASSERT_THAT(view->search_results_view_for_testing()
                  .section_views_for_testing()[0]
                  ->item_views_for_testing(),
              Not(IsEmpty()));

  QuickInsertItemView* result_view = view->search_results_view_for_testing()
                                         .section_views_for_testing()[0]
                                         ->item_views_for_testing()[0];
  ViewDrawnWaiter().Wait(result_view);
  LeftClickOn(result_view);

  EXPECT_EQ(delegate.last_inserted_result(), std::nullopt);
  EXPECT_THAT(delegate.last_opened_result(),
              Optional(QuickInsertBrowsingHistoryResult({}, u"a", {})));
}

TEST_F(QuickInsertViewTest, SwitchesToCategoryView) {
  {
    FakeQuickInsertViewDelegate delegate({
        .available_categories = {QuickInsertCategory::kLinks},
    });
    auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
    widget->Show();

    QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
    views::View* category_item_view =
        GetFirstCategoryItemView(quick_insert_view);

    category_item_view->ScrollViewToVisible();
    ViewDrawnWaiter().Wait(category_item_view);
    LeftClickOn(category_item_view);

    EXPECT_TRUE(
        quick_insert_view->category_results_view_for_testing().GetVisible());
    EXPECT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
    EXPECT_FALSE(
        quick_insert_view->search_results_view_for_testing().GetVisible());
  }

  cros_events::Picker_FinishSession expected_event;
  expected_event.SetOutcome(cros_events::PickerSessionOutcome::ABANDONED)
      .SetAction(cros_events::PickerAction::OPEN_LINKS)
      .SetResultSource(cros_events::PickerResultSource::UNKNOWN)
      .SetResultType(cros_events::PickerResultType::UNKNOWN)
      .SetTotalEdits(0)
      .SetFinalQuerySize(0)
      .SetResultIndex(-1);
  EXPECT_THAT(metrics_recorder_.GetEvents(), ContainsEvent(expected_event));
}

TEST_F(QuickInsertViewTest, ClickingCategoryResultsSwitchesToCategoryView) {
  base::test::TestFuture<void> search_called;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            search_called.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kNone,
                    {{QuickInsertCategoryResult(QuickInsertCategory::kLinks)}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search_called.Wait());

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_result_item_view =
      quick_insert_view->search_results_view_for_testing()
          .section_views_for_testing()[0]
          ->item_views_for_testing()[0];
  ViewDrawnWaiter().Wait(category_result_item_view);
  LeftClickOn(category_result_item_view);

  EXPECT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  EXPECT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest,
       SelectingCategoryUpdatesSearchFieldPlaceholderText) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);

  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  EXPECT_EQ(quick_insert_view->search_field_view_for_testing()
                .textfield_for_testing()
                .GetPlaceholderText(),
            l10n_util::GetStringUTF16(
                IDS_PICKER_LINKS_CATEGORY_SEARCH_FIELD_PLACEHOLDER_TEXT));
}

TEST_F(QuickInsertViewTest, SelectingCategoryShowsBackButton) {
  FakeQuickInsertViewDelegate delegate;
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);
  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);

  LeftClickOn(category_item_view);

  EXPECT_TRUE(quick_insert_view->search_field_view_for_testing()
                  .back_button_for_testing()
                  .GetVisible());
}

TEST_F(QuickInsertViewTest, SearchingWithCategoryKeepsShowingBackButton) {
  FakeQuickInsertViewDelegate delegate;
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);
  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  // Type something into the search field.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  EXPECT_TRUE(quick_insert_view->search_field_view_for_testing()
                  .back_button_for_testing()
                  .GetVisible());
}

TEST_P(QuickInsertViewEmojiTest, SelectingCategoryHidesEmojiBar) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks, GetParam()},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);
  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);

  LeftClickOn(category_item_view);

  EXPECT_FALSE(quick_insert_view->emoji_bar_view_for_testing()->GetVisible());
}

TEST_P(QuickInsertViewEmojiTest,
       ReturningToZeroStateFromCategoryPageShowsEmojiBar) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks, GetParam()},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);
  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_BROWSER_BACK, ui::EF_NONE);

  EXPECT_TRUE(quick_insert_view->emoji_bar_view_for_testing()->GetVisible());
}

TEST_F(QuickInsertViewTest, SearchingWithCategorySwitchesToSearchResultsView) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  // Switch to category view.
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);

  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);
  // Type something into the search field.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  EXPECT_FALSE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  EXPECT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, EmptySearchFieldSwitchesBackToCategoryView) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  // Switch to category view.
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);

  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);
  // Type something into the search field.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  // Clear the search field.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);

  EXPECT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  EXPECT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, EmptySearchFieldSwitchesToCategoryViewFromSeeMore) {
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [](std::u16string_view query,
             FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            callback.Run({
                QuickInsertSearchResultsSection(QuickInsertSectionType::kLinks,
                                                {},
                                                /*has_more_results=*/true),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  // Type something into the search field.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  // See more results.
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* trailing_link =
      quick_insert_view->search_results_view_for_testing()
          .section_views_for_testing()[0]
          ->title_trailing_link_for_testing();
  ViewDrawnWaiter().Wait(trailing_link);
  LeftClickOn(trailing_link);
  // Clear the search field.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);

  EXPECT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  EXPECT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, CategoryViewFromSeeMoreHasResults) {
  FakeQuickInsertViewDelegate delegate(
      {.search_function = base::BindLambdaForTesting(
           [&](std::u16string_view query,
               FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
             callback.Run({
                 QuickInsertSearchResultsSection(QuickInsertSectionType::kLinks,
                                                 {},
                                                 /*has_more_results=*/true),
             });
           }),
       .category_results_function = base::BindLambdaForTesting(
           [&](FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
             callback.Run({
                 QuickInsertSearchResultsSection(
                     QuickInsertSectionType::kLinks,
                     {
                         QuickInsertTextResult(u"result"),
                     },
                     /*has_more_results=*/false),
             });
           })});
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  // Type something into the search field.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  // See more results.
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* trailing_link =
      quick_insert_view->search_results_view_for_testing()
          .section_views_for_testing()[0]
          ->title_trailing_link_for_testing();
  ViewDrawnWaiter().Wait(trailing_link);
  LeftClickOn(trailing_link);
  // Clear the search field.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);

  ASSERT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  EXPECT_THAT(quick_insert_view->category_results_view_for_testing()
                  .section_views_for_testing(),
              ElementsAre(Pointee(Property(
                  "item views", &QuickInsertSectionView::item_views_for_testing,
                  ElementsAre(AsView<QuickInsertListItemView>(Property(
                      "primary text",
                      &QuickInsertListItemView::GetPrimaryTextForTesting,
                      u"result")))))));
}

TEST_F(QuickInsertViewTest, SearchingSpacesFromZeroStateDoesNotStartSearch) {
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            ADD_FAILURE()
                << "Search function was unexpectedly called with query "
                << query;
            // This should never be run - but if it is, immediately publish
            // to get results.
            callback.Run({{QuickInsertSearchResultsSection(
                QuickInsertSectionType::kClipboard,
                {{QuickInsertTextResult(u"result")}},
                /*has_more_results=*/false)}});
            // Signals that all results are done.
            callback.Run({});
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);
  EXPECT_TRUE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);
  EXPECT_TRUE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, SearchTrimsLeftAndRightSpaces) {
  base::test::TestFuture<std::u16string> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            // This will crash if it is run multiple times.
            future.SetValue(std::u16string(query));
            callback.Run({{QuickInsertSearchResultsSection(
                QuickInsertSectionType::kClipboard,
                {{QuickInsertTextResult(u"result")}},
                /*has_more_results=*/false)}});
            // Signals that all results are done.
            callback.Run({});
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  // [....|]
  PressAndReleaseKey(ui::KeyboardCode::VKEY_LEFT, ui::EF_NONE);
  // [...|.]
  PressAndReleaseKey(ui::KeyboardCode::VKEY_LEFT, ui::EF_NONE);
  // [..|..]
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  // [..a|..]
  ASSERT_EQ(quick_insert_view->search_field_view_for_testing()
                .textfield_for_testing()
                .GetText(),
            u"  a  ");
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);
  EXPECT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_EQ(future.Take(), u"a");
}

TEST_F(QuickInsertViewTest, SearchIsNotRerunIfSpacesAreAddedToEnds) {
  base::test::TestFuture<std::u16string> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            // This will crash if it is run multiple times.
            future.SetValue(std::u16string(query));
            callback.Run({{QuickInsertSearchResultsSection(
                QuickInsertSectionType::kClipboard,
                {{QuickInsertTextResult(u"result")}},
                /*has_more_results=*/false)}});
            // Signals that all results are done.
            callback.Run({});
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  EXPECT_EQ(future.Get(), u"a");
  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  // [a..|]
  PressAndReleaseKey(ui::KeyboardCode::VKEY_HOME, ui::EF_NONE);
  // [|a..]
  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  // [.|a..]
  PressAndReleaseKey(ui::KeyboardCode::VKEY_SPACE, ui::EF_NONE);
  // [..|a..]
  ASSERT_EQ(quick_insert_view->search_field_view_for_testing()
                .textfield_for_testing()
                .GetText(),
            u"  a  ");
}

TEST_F(QuickInsertViewTest,
       SearchingFromZeroStateDoesNotImmediatelySwitchToResults) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback callback = future.Take();

  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  callback.Run({{QuickInsertSearchResultsSection(
      QuickInsertSectionType::kClipboard, {{QuickInsertTextResult(u"result")}},
      /*has_more_results=*/false)}});
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest,
       SearchingFromZeroStateSwitchesToEmptyResultsAfterTimeout) {
  base::test::TestFuture<void> search_called;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            search_called.SetValue();
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search_called.Wait());

  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_THAT(quick_insert_view->search_results_view_for_testing()
                  .section_list_view_for_testing()
                  ->children(),
              IsEmpty());
}

TEST_F(QuickInsertViewTest,
       SearchingFromCategoryDoesNotImmediatelySwitchToResults) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);

  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  ASSERT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  ASSERT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  ASSERT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback callback = future.Take();

  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  callback.Run({{QuickInsertSearchResultsSection(
      QuickInsertSectionType::kLinks, {{QuickInsertTextResult(u"result")}},
      /*has_more_results=*/false)}});
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest,
       SearchingFromCategorySwitchesToEmptyResultsAfterTimeout) {
  base::test::TestFuture<void> search_called;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            search_called.SetValue();
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);

  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  ASSERT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  ASSERT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  ASSERT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search_called.Wait());

  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_THAT(quick_insert_view->search_results_view_for_testing()
                  .section_list_view_for_testing()
                  ->children(),
              IsEmpty());
}

TEST_F(QuickInsertViewTest,
       SearchingShowResultsWhenResultsArriveAsynchronously) {
  base::test::TestFuture<void> search_called;
  FakeQuickInsertViewDelegate::SearchResultsCallback search_callback;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            search_callback = std::move(callback);
            search_called.SetValue();
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search_called.Wait());

  search_callback.Run({
      QuickInsertSearchResultsSection(QuickInsertSectionType::kLinks, {},
                                      /*has_more_results=*/false),
  });

  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_THAT(quick_insert_view->search_results_view_for_testing()
                  .section_views_for_testing(),
              ElementsAre(Pointee(Property(
                  "title", &QuickInsertSectionView::title_label_for_testing,
                  Property("text", &views::Label::GetText,
                           l10n_util::GetStringUTF16(
                               IDS_PICKER_LINKS_CATEGORY_LABEL))))));
}

TEST_F(QuickInsertViewTest, SearchingKeepsOldResultsUntilNewResultsArrive) {
  base::test::TestFuture<void> search1_called;
  base::test::TestFuture<void> search2_called;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            if (!search1_called.IsReady()) {
              callback.Run({
                  QuickInsertSearchResultsSection(
                      QuickInsertSectionType::kLinks, {},
                      /*has_more_results=*/false),
              });
              search1_called.SetValue();
            } else {
              search2_called.SetValue();
            }
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  // Go to the results page.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search1_called.Wait());
  // Start another search.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search2_called.Wait());

  // Results page should keep old results until new results arrive.
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_THAT(quick_insert_view->search_results_view_for_testing()
                  .section_views_for_testing(),
              ElementsAre(Pointee(Property(
                  "title", &QuickInsertSectionView::title_label_for_testing,
                  Property("text", &views::Label::GetText,
                           l10n_util::GetStringUTF16(
                               IDS_PICKER_LINKS_CATEGORY_LABEL))))));
}

TEST_F(QuickInsertViewTest, SearchingReplacesOldResultsWithNewResults) {
  base::test::TestFuture<void> search1_called;
  base::test::TestFuture<void> search2_called;
  FakeQuickInsertViewDelegate::SearchResultsCallback search2_callback;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            if (!search1_called.IsReady()) {
              callback.Run({
                  QuickInsertSearchResultsSection(
                      QuickInsertSectionType::kLocalFiles, {},
                      /*has_more_results=*/false),
              });
              search1_called.SetValue();
            } else {
              search2_callback = std::move(callback);
              search2_called.SetValue();
            }
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  // Go to the results page.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search1_called.Wait());
  // Start another search.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search2_called.Wait());
  search2_callback.Run({
      QuickInsertSearchResultsSection(QuickInsertSectionType::kLinks, {},
                                      /*has_more_results=*/false),
  });

  // Results page should show the new results.
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_THAT(quick_insert_view->search_results_view_for_testing()
                  .section_views_for_testing(),
              ElementsAre(Pointee(Property(
                  "title", &QuickInsertSectionView::title_label_for_testing,
                  Property("text", &views::Label::GetText,
                           l10n_util::GetStringUTF16(
                               IDS_PICKER_LINKS_CATEGORY_LABEL))))));
}

TEST_F(QuickInsertViewTest, ShowsNoResultsBeforeTimeout) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout -
                                    base::Milliseconds(1));
  future.Take().Run({});

  EXPECT_TRUE(quick_insert_view->search_results_view_for_testing()
                  .no_results_view_for_testing()
                  ->GetVisible());
}

TEST_F(QuickInsertViewTest, ShowsNoResultsAfterTimeout) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);
  future.Take().Run({});

  EXPECT_TRUE(quick_insert_view->search_results_view_for_testing()
                  .no_results_view_for_testing()
                  ->GetVisible());
}

TEST_F(QuickInsertViewTest, ShowsNoResultsWithNoIllustration) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);
  future.Take().Run({});

  EXPECT_TRUE(quick_insert_view->search_results_view_for_testing()
                  .no_results_view_for_testing()
                  ->GetVisible());
  EXPECT_FALSE(quick_insert_view->search_results_view_for_testing()
                   .no_results_illustration_for_testing()
                   .GetVisible());
  EXPECT_EQ(quick_insert_view->search_results_view_for_testing()
                .no_results_label_for_testing()
                .GetText(),
            l10n_util::GetStringUTF16(IDS_PICKER_NO_RESULTS_TEXT));
}

TEST_F(QuickInsertViewTest, NoMainResultsAndNoEmojisIsAnnounced) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  views::test::AXEventCounter counter(views::AXUpdateNotifier::Get());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  future.Take().Run({});

  EXPECT_EQ(
      quick_insert_view->search_results_view_for_testing().GetAccessibleName(),
      l10n_util::GetStringUTF16(IDS_PICKER_NO_RESULTS_TEXT));
  EXPECT_EQ(counter.GetCount(ax::mojom::Event::kLiveRegionChanged), 1);
}

TEST_P(QuickInsertViewEmojiTest, NoMainResultsAndSomeEmojisIsAnnounced) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {GetParam()},
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
      .emoji_results = {QuickInsertEmojiResult::Emoji(u"😊"),
                        QuickInsertEmojiResult::Symbol(u"♬")},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  views::test::AXEventCounter counter(views::AXUpdateNotifier::Get());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  future.Take().Run({});

  EXPECT_EQ(
      quick_insert_view->search_results_view_for_testing().GetAccessibleName(),
      u"2 emojis. No other results.");
  EXPECT_EQ(counter.GetCount(ax::mojom::Event::kLiveRegionChanged), 1);
}

TEST_F(QuickInsertViewTest, DoesNotClearResultsBeforeTimeout) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback first_callback =
      future.Take();
  first_callback.Run({{QuickInsertSearchResultsSection(
      QuickInsertSectionType::kClipboard, {{QuickInsertTextResult(u"result")}},
      /*has_more_results=*/false)}});
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);
  ASSERT_FALSE(quick_insert_view->search_results_view_for_testing()
                   .section_views_for_testing()
                   .empty());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  future.Clear();
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout -
                                    base::Milliseconds(1));

  EXPECT_FALSE(quick_insert_view->search_results_view_for_testing()
                   .section_views_for_testing()
                   .empty());
}

TEST_F(QuickInsertViewTest, ClearsResultsAfterTimeout) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback first_callback =
      future.Take();
  first_callback.Run({{QuickInsertSearchResultsSection(
      QuickInsertSectionType::kClipboard, {{QuickInsertTextResult(u"result")}},
      /*has_more_results=*/false)}});
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);
  ASSERT_FALSE(quick_insert_view->search_results_view_for_testing()
                   .section_views_for_testing()
                   .empty());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  future.Clear();
  task_environment()->FastForwardBy(QuickInsertView::kClearResultsTimeout);

  EXPECT_TRUE(quick_insert_view->search_results_view_for_testing()
                  .section_views_for_testing()
                  .empty());
}

TEST_F(QuickInsertViewTest, ClearsResultsWhenQueryClearedNoCategory) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback callback = future.Take();
  callback.Run({{QuickInsertSearchResultsSection(
      QuickInsertSectionType::kClipboard, {{QuickInsertTextResult(u"result")}},
      /*has_more_results=*/false)}});
  ASSERT_FALSE(quick_insert_view->search_results_view_for_testing()
                   .section_views_for_testing()
                   .empty());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);

  EXPECT_TRUE(quick_insert_view->search_results_view_for_testing()
                  .section_views_for_testing()
                  .empty());
}

TEST_F(QuickInsertViewTest, ClearsResultsWhenQueryClearedWithCategory) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(std::move(callback));
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);

  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  ASSERT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  ASSERT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  ASSERT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback callback = future.Take();
  callback.Run({{QuickInsertSearchResultsSection(
      QuickInsertSectionType::kLinks, {{QuickInsertTextResult(u"result")}},
      /*has_more_results=*/false)}});
  ASSERT_FALSE(quick_insert_view->search_results_view_for_testing()
                   .section_views_for_testing()
                   .empty());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);
  EXPECT_TRUE(quick_insert_view->search_results_view_for_testing()
                  .section_views_for_testing()
                  .empty());
  EXPECT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  EXPECT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, StopsSearchWhenQueryClearedNoCategory) {
  base::test::TestFuture<void> search_future;
  base::test::TestFuture<void> stop_search_future;
  FakeQuickInsertViewDelegate delegate(
      {.search_function = base::BindLambdaForTesting(
           [&](std::u16string_view query,
               FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
             search_future.SetValue();
           }),
       .stop_search_function = stop_search_future.GetRepeatingCallback()});
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search_future.Wait());
  EXPECT_FALSE(stop_search_future.IsReady());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);
  EXPECT_TRUE(stop_search_future.Wait());
}

TEST_F(QuickInsertViewTest, StopsSearchWhenQueryClearedWithCategory) {
  base::test::TestFuture<void> search_future;
  base::test::TestFuture<void> stop_search_future;
  FakeQuickInsertViewDelegate delegate(
      {.available_categories = {QuickInsertCategory::kLinks},
       .search_function = base::BindLambdaForTesting(
           [&](std::u16string_view query,
               FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
             search_future.SetValue();
           }),
       .stop_search_function = stop_search_future.GetRepeatingCallback()});
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);

  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);
  // Starting a category search - even if there is no query - stops the previous
  // search.
  ASSERT_TRUE(stop_search_future.WaitAndClear());

  ASSERT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  ASSERT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  ASSERT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search_future.Wait());
  EXPECT_FALSE(stop_search_future.IsReady());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);
  EXPECT_TRUE(stop_search_future.Wait());
  EXPECT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  EXPECT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, StopsSearchWhenBackButtonPressed) {
  base::test::TestFuture<void> search_future;
  base::test::TestFuture<void> stop_search_future;
  FakeQuickInsertViewDelegate delegate(
      {.available_categories = {QuickInsertCategory::kLinks},
       .search_function = base::BindLambdaForTesting(
           [&](std::u16string_view query,
               FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
             search_future.SetValue();
           }),
       .stop_search_function = stop_search_future.GetRepeatingCallback()});
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);

  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);
  // Starting a category search - even if there is no query - stops the previous
  // search.
  ASSERT_TRUE(stop_search_future.WaitAndClear());

  ASSERT_TRUE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  ASSERT_FALSE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  ASSERT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search_future.Wait());
  ASSERT_FALSE(stop_search_future.IsReady());

  QuickInsertSearchFieldView& search_field_view =
      quick_insert_view->search_field_view_for_testing();
  ViewDrawnWaiter().Wait(&search_field_view.back_button_for_testing());
  LeftClickOn(&search_field_view.back_button_for_testing());

  EXPECT_TRUE(stop_search_future.Wait());
}

TEST_F(QuickInsertViewTest,
       StopsSearchWhenCategorySelectedOnZeroStateDuringSearch) {
  base::test::TestFuture<void> search_future;
  base::test::TestFuture<void> stop_search_future;
  FakeQuickInsertViewDelegate delegate(
      {.available_categories = {QuickInsertCategory::kLinks},
       .search_function = base::BindLambdaForTesting(
           [&](std::u16string_view query,
               FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
             search_future.SetValue();
           }),
       .stop_search_function = stop_search_future.GetRepeatingCallback()});
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search_future.Wait());
  ASSERT_FALSE(stop_search_future.IsReady());

  ASSERT_FALSE(
      quick_insert_view->category_results_view_for_testing().GetVisible());
  ASSERT_TRUE(quick_insert_view->zero_state_view_for_testing().GetVisible());
  ASSERT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());

  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  EXPECT_TRUE(stop_search_future.Wait());
}

TEST_F(QuickInsertViewTest, StopsSearchWhenCategorySelectedInSearchResults) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      search_future;
  base::test::TestFuture<void> stop_search_future;
  FakeQuickInsertViewDelegate delegate(
      {.search_function = base::BindLambdaForTesting(
           [&](std::u16string_view query,
               FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
             search_future.SetValue(std::move(callback));
           }),
       .stop_search_function = stop_search_future.GetRepeatingCallback()});
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback callback =
      search_future.Take();
  callback.Run({
      QuickInsertSearchResultsSection(
          QuickInsertSectionType::kNone,
          {{QuickInsertCategoryResult(QuickInsertCategory::kLinks)}},
          /*has_more_results=*/false),
  });

  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_result = view->search_results_view_for_testing()
                                     .section_list_view_for_testing()
                                     ->GetTopItem();
  ASSERT_TRUE(category_result);
  ViewDrawnWaiter().Wait(category_result);
  ASSERT_FALSE(stop_search_future.IsReady());
  LeftClickOn(category_result);

  ASSERT_TRUE(view->category_results_view_for_testing().GetVisible());
  ASSERT_FALSE(view->zero_state_view_for_testing().GetVisible());
  ASSERT_FALSE(view->search_results_view_for_testing().GetVisible());
  EXPECT_TRUE(stop_search_future.Wait());
}

TEST_P(QuickInsertViewEmojiTest, SearchingShowsExpressionResultsInEmojiBar) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {GetParam()},
      .emoji_results = {QuickInsertEmojiResult::Emoji(u"😊"),
                        QuickInsertEmojiResult::Symbol(u"♬")},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  ASSERT_NE(quick_insert_view->emoji_bar_view_for_testing(), nullptr);
  EXPECT_TRUE(quick_insert_view->emoji_bar_view_for_testing()->GetVisible());
  EXPECT_THAT(
      quick_insert_view->emoji_bar_view_for_testing()->GetItemsForTesting(),
      ElementsAre(Truly(&views::IsViewClass<QuickInsertEmojiItemView>),
                  Truly(&views::IsViewClass<QuickInsertEmojiItemView>)));
}

TEST_P(QuickInsertViewEmojiTest, InitiallyShowsSuggestedEmojis) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {GetParam()},
      .suggested_emojis = {"😊", "👍"},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  ASSERT_NE(quick_insert_view->emoji_bar_view_for_testing(), nullptr);
  EXPECT_TRUE(quick_insert_view->emoji_bar_view_for_testing()->GetVisible());
  EXPECT_THAT(
      quick_insert_view->emoji_bar_view_for_testing()->GetItemsForTesting(),
      ElementsAre(AsView<QuickInsertEmojiItemView>(Property(
                      &QuickInsertEmojiItemView::GetTextForTesting, u"😊")),
                  AsView<QuickInsertEmojiItemView>(Property(
                      &QuickInsertEmojiItemView::GetTextForTesting, u"👍"))));
}

TEST_F(QuickInsertViewTest, NoEmojiBarIfExpressionsCategoryNotAvailable) {
  FakeQuickInsertViewDelegate delegate(
      {.available_categories = {QuickInsertCategory::kLinks}});
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);

  EXPECT_EQ(GetQuickInsertViewFromWidget(*widget)->emoji_bar_view_for_testing(),
            nullptr);
}

TEST_F(QuickInsertViewTest, ClearsResultsWhenGoingBackToZeroState) {
  base::test::TestFuture<void> search_called;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            search_called.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kClipboard,
                    {{QuickInsertTextResult(u"result")}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  // Go to the results page.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(search_called.Wait());
  // Go back to the zero state page.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_BACK, ui::EF_NONE);

  EXPECT_FALSE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_THAT(quick_insert_view->search_results_view_for_testing()
                  .section_list_view_for_testing()
                  ->children(),
              IsEmpty());
}

TEST_F(QuickInsertViewTest, PressingEscClosesQuickInsertWidget) {
  FakeQuickInsertViewDelegate delegate;
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE, ui::EF_NONE);

  EXPECT_TRUE(widget->IsClosed());
}

TEST_F(QuickInsertViewTest, RecordsSearchLatencyAfterSearchFinished) {
  base::HistogramTester histogram;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&, this](
              std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            // The search automatically publishes results after burn-in + 50ms,
            // so publish "burn in results" before that.
            task_environment()->FastForwardBy(
                QuickInsertController::kBurnInPeriod);
            // This needs to be non-empty, or else `MarkSearchResultsUpdated`
            // will be called with `kNoResultsFound` - which does not emit the
            // search latency metric.
            // TODO: b/349913604 - Replace the metric with a new one which
            // records search latency even if "no results found" was shown.
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kClipboard,
                    {{QuickInsertTextResult(u"result")}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  histogram.ExpectUniqueTimeSample("Ash.Picker.Session.SearchLatency",
                                   QuickInsertController::kBurnInPeriod, 1);
}

TEST_F(QuickInsertViewTest,
       RecordsSearchLatencyWhenResultsAreAutomaticallyCleared) {
  base::HistogramTester histogram;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&, this](
              std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            task_environment()->FastForwardBy(
                QuickInsertView::kClearResultsTimeout);
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  histogram.ExpectUniqueTimeSample("Ash.Picker.Session.SearchLatency",
                                   QuickInsertView::kClearResultsTimeout, 1);
}

TEST_F(QuickInsertViewTest, BoundsDefaultAlignedWithAnchor) {
  FakeQuickInsertViewDelegate delegate;
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  // Should be entirely on screen.
  EXPECT_TRUE(display::Screen::Get()
                  ->GetDisplayMatching(kDefaultAnchorBounds)
                  .work_area()
                  .Contains(view->GetBoundsInScreen()));
  // Should be to the right of the anchor.
  EXPECT_EQ(view->GetBoundsInScreen().x(), kDefaultAnchorBounds.right());
  // Center of the search field should be vertically aligned with the anchor.
  EXPECT_EQ(view->search_field_view_for_testing()
                .GetBoundsInScreen()
                .CenterPoint()
                .y(),
            kDefaultAnchorBounds.CenterPoint().y());
}

TEST_F(QuickInsertViewTest, BoundsAlignedWithAnchorNearTopLeftOfScreen) {
  FakeQuickInsertViewDelegate delegate;
  const gfx::Rect screen_work_area =
      display::Screen::Get()->GetPrimaryDisplay().work_area();
  gfx::Rect anchor_bounds(screen_work_area.origin(), {0, 10});
  anchor_bounds.Offset(80, 120);

  auto widget = QuickInsertWidget::Create(&delegate, anchor_bounds);
  widget->Show();

  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  // Should be entirely on screen.
  EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
  // Should be to the right of the anchor.
  EXPECT_EQ(view->GetBoundsInScreen().x(), anchor_bounds.right());
  // Center of the search field should be vertically aligned with the anchor.
  EXPECT_EQ(view->search_field_view_for_testing()
                .GetBoundsInScreen()
                .CenterPoint()
                .y(),
            anchor_bounds.CenterPoint().y());
}

TEST_F(QuickInsertViewTest, BoundsAlignedWithAnchorNearBottomLeftOfScreen) {
  FakeQuickInsertViewDelegate delegate;
  const gfx::Rect screen_work_area =
      display::Screen::Get()->GetPrimaryDisplay().work_area();
  gfx::Rect anchor_bounds(screen_work_area.bottom_left(), {0, 10});
  anchor_bounds.Offset(80, -80);

  auto widget = QuickInsertWidget::Create(&delegate, anchor_bounds);
  widget->Show();

  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  // Should be entirely on screen.
  EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
  // Should be to the right of the anchor.
  EXPECT_EQ(view->GetBoundsInScreen().x(), anchor_bounds.right());
  // Center of the search field should be vertically aligned with the anchor.
  EXPECT_EQ(view->search_field_view_for_testing()
                .GetBoundsInScreen()
                .CenterPoint()
                .y(),
            anchor_bounds.CenterPoint().y());
}

TEST_F(QuickInsertViewTest, BoundsBelowAnchorForAnchorNearTopRightOfScreen) {
  FakeQuickInsertViewDelegate delegate;
  const gfx::Rect screen_work_area =
      display::Screen::Get()->GetPrimaryDisplay().work_area();
  gfx::Rect anchor_bounds(screen_work_area.top_right(), {0, 10});
  anchor_bounds.Offset(-20, 20);

  auto widget = QuickInsertWidget::Create(&delegate, anchor_bounds);
  widget->Show();

  const QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  // Should be entirely on screen.
  EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
  // Should be below the anchor.
  EXPECT_EQ(view->GetBoundsInScreen().y(), anchor_bounds.bottom());
}

TEST_F(QuickInsertViewTest, BoundsAboveAnchorForAnchorNearBottomRightOfScreen) {
  FakeQuickInsertViewDelegate delegate;
  const gfx::Rect screen_work_area =
      display::Screen::Get()->GetPrimaryDisplay().work_area();
  gfx::Rect anchor_bounds(screen_work_area.bottom_right(), {0, 10});
  anchor_bounds.Offset(-20, -20);

  auto widget = QuickInsertWidget::Create(&delegate, anchor_bounds);
  widget->Show();

  const QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  // Should be entirely on screen.
  EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
  // Should be above the anchor.
  EXPECT_EQ(view->GetBoundsInScreen().bottom(), anchor_bounds.y());
}

TEST_F(QuickInsertViewTest, BoundsLeftAlignedBelowSelectionNearTopOfScreen) {
  FakeQuickInsertViewDelegate delegate({
      .mode = QuickInsertModeType::kHasSelection,
  });
  const gfx::Rect screen_work_area =
      display::Screen::Get()->GetPrimaryDisplay().work_area();
  const gfx::Rect anchor_bounds(20, 20, 100, 20);

  auto widget = QuickInsertWidget::Create(&delegate, anchor_bounds);
  widget->Show();

  const QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
  EXPECT_EQ(view->GetBoundsInScreen().x(), anchor_bounds.x());
  EXPECT_GE(view->GetBoundsInScreen().y(), anchor_bounds.bottom());
}

TEST_F(QuickInsertViewTest, BoundsLeftAlignedAboveSelectionNearBottomOfScreen) {
  FakeQuickInsertViewDelegate delegate({
      .mode = QuickInsertModeType::kHasSelection,
  });
  const gfx::Rect screen_work_area =
      display::Screen::Get()->GetPrimaryDisplay().work_area();
  const gfx::Rect anchor_bounds(20, screen_work_area.bottom() - 30, 100, 20);

  auto widget = QuickInsertWidget::Create(&delegate, anchor_bounds);
  widget->Show();

  const QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_TRUE(screen_work_area.Contains(view->GetBoundsInScreen()));
  EXPECT_EQ(view->GetBoundsInScreen().x(), anchor_bounds.x());
  EXPECT_LE(view->GetBoundsInScreen().bottom(), anchor_bounds.y());
}

TEST_F(QuickInsertViewTest, BoundsOnScreenForEmptyAnchorBounds) {
  FakeQuickInsertViewDelegate delegate;
  auto widget = QuickInsertWidget::Create(&delegate, gfx::Rect());
  widget->Show();

  const QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_TRUE(display::Screen::Get()->GetPrimaryDisplay().work_area().Contains(
      view->GetBoundsInScreen()));
}

TEST_F(QuickInsertViewTest, MainContentBelowSearchFieldNearTopOfScreen) {
  FakeQuickInsertViewDelegate delegate;
  const gfx::Rect screen_work_area =
      display::Screen::Get()->GetPrimaryDisplay().work_area();
  gfx::Rect anchor_bounds(screen_work_area.top_center(), {0, 10});
  anchor_bounds.Offset(0, 80);

  auto widget = QuickInsertWidget::Create(&delegate, anchor_bounds);
  widget->Show();

  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_GE(view->zero_state_view_for_testing().GetBoundsInScreen().y(),
            view->search_field_view_for_testing().GetBoundsInScreen().bottom());
}

TEST_F(QuickInsertViewTest, MainContentAboveSearchFieldNearBottomOfScreen) {
  FakeQuickInsertViewDelegate delegate;
  const gfx::Rect screen_work_area =
      display::Screen::Get()->GetPrimaryDisplay().work_area();
  gfx::Rect anchor_bounds(screen_work_area.bottom_center(), {0, 10});
  anchor_bounds.Offset(0, -80);

  auto widget = QuickInsertWidget::Create(&delegate, anchor_bounds);
  widget->Show();

  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  EXPECT_LE(view->zero_state_view_for_testing().GetBoundsInScreen().bottom(),
            view->search_field_view_for_testing().GetBoundsInScreen().y());
}

TEST_P(QuickInsertViewEmojiTest, ShowsEmojiPickerWhenClickingOnExpressions) {
  {
    FakeQuickInsertViewDelegate delegate({
        .available_categories = {GetParam()},
    });
    auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
    widget->Show();

    LeftClickOn(
        GetFirstCategoryItemView(GetQuickInsertViewFromWidget(*widget)));

    EXPECT_TRUE(widget->IsClosed());
    EXPECT_THAT(delegate.emoji_picker_query(), Optional(Eq(u"")));
  }

  cros_events::Picker_FinishSession expected_event;
  expected_event.SetOutcome(cros_events::PickerSessionOutcome::REDIRECTED)
      .SetAction(cros_events::PickerAction::OPEN_EXPRESSIONS)
      .SetResultSource(cros_events::PickerResultSource::UNKNOWN)
      .SetResultType(cros_events::PickerResultType::UNKNOWN)
      .SetTotalEdits(0)
      .SetFinalQuerySize(0)
      .SetResultIndex(-1);
  EXPECT_THAT(metrics_recorder_.GetEvents(), ContainsEvent(expected_event));
}

TEST_F(QuickInsertViewTest, ShowsEditorWhenClickingOnEditor) {
  {
    FakeQuickInsertViewDelegate delegate({
        .available_categories = {QuickInsertCategory::kEditorWrite},
    });
    auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
    widget->Show();

    LeftClickOn(
        GetFirstCategoryItemView(GetQuickInsertViewFromWidget(*widget)));

    EXPECT_TRUE(widget->IsClosed());
    EXPECT_TRUE(delegate.showed_editor());
  }

  cros_events::Picker_FinishSession expected_event;
  expected_event.SetOutcome(cros_events::PickerSessionOutcome::REDIRECTED)
      .SetAction(cros_events::PickerAction::OPEN_EDITOR_WRITE)
      .SetResultSource(cros_events::PickerResultSource::UNKNOWN)
      .SetResultType(cros_events::PickerResultType::UNKNOWN)
      .SetTotalEdits(0)
      .SetFinalQuerySize(0)
      .SetResultIndex(-1);
  EXPECT_THAT(metrics_recorder_.GetEvents(), ContainsEvent(expected_event));
}

TEST_F(QuickInsertViewTest, PressingEnterDoesNothingOnEmptySearchResultsPage) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(QuickInsertSectionType::kLinks,
                                                {},
                                                /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_TRUE(view->search_results_view_for_testing().GetVisible());
  EXPECT_EQ(delegate.last_inserted_result(), std::nullopt);
}

TEST_F(QuickInsertViewTest, PressingEnterDefaultSelectsFirstSearchResult) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kClipboard,
                    {{QuickInsertTextResult(u"Result A"),
                      QuickInsertTextResult(u"Result B")}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(QuickInsertTextResult(u"Result A")));
}

TEST_F(QuickInsertViewTest, ArrowKeysNavigateEmojiBar) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs},
      .emoji_results = {QuickInsertEmojiResult::Emoji(u"😊"),
                        QuickInsertEmojiResult::Symbol(u"♬")},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ViewDrawnWaiter().Wait(GetQuickInsertViewFromWidget(*widget)
                             ->emoji_bar_view_for_testing()
                             ->GetTopItem());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_UP, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RIGHT, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(QuickInsertEmojiResult::Symbol(u"♬")));
}

TEST_F(QuickInsertViewTest, CanTypeQueryWhileEmojiBarIsPseudoFocused) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs},
      .emoji_results = {QuickInsertEmojiResult::Emoji(u"😊"),
                        QuickInsertEmojiResult::Symbol(u"♬")},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ViewDrawnWaiter().Wait(GetQuickInsertViewFromWidget(*widget)
                             ->emoji_bar_view_for_testing()
                             ->GetTopItem());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_UP, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_B, ui::EF_NONE);

  EXPECT_EQ(GetQuickInsertViewFromWidget(*widget)
                ->search_field_view_for_testing()
                .textfield_for_testing()
                .GetText(),
            u"ab");
}

TEST_F(QuickInsertViewTest, DownArrowKeyNavigatesSearchResults) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kNone,
                    {{QuickInsertBrowsingHistoryResult(
                          GURL("http://foo.com"), u"Foo", ui::ImageModel()),
                      QuickInsertBrowsingHistoryResult(
                          GURL("http://bar.com"), u"Bar", ui::ImageModel())}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_DOWN, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(QuickInsertBrowsingHistoryResult(
                  GURL("http://bar.com"), u"Bar", ui::ImageModel())));
}

TEST_F(QuickInsertViewTest, RightArrowKeyShowsSubmenu) {
  FakeQuickInsertViewDelegate delegate({
      .zero_state_suggested_results =
          {QuickInsertNewWindowResult(QuickInsertNewWindowResult::Type::kDoc),
           QuickInsertNewWindowResult(
               QuickInsertNewWindowResult::Type::kSheet)},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_RIGHT, ui::EF_NONE);

  EXPECT_NE(GetQuickInsertViewFromWidget(*widget)
                ->submenu_controller_for_testing()
                .GetSubmenuView(),
            nullptr);
}

TEST_F(QuickInsertViewTest, EnterKeyShowsSubmenu) {
  FakeQuickInsertViewDelegate delegate({
      .zero_state_suggested_results =
          {QuickInsertNewWindowResult(QuickInsertNewWindowResult::Type::kDoc),
           QuickInsertNewWindowResult(
               QuickInsertNewWindowResult::Type::kSheet)},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_NE(GetQuickInsertViewFromWidget(*widget)
                ->submenu_controller_for_testing()
                .GetSubmenuView(),
            nullptr);
}

TEST_F(QuickInsertViewTest, LeftArrowKeyClosesSubmenu) {
  FakeQuickInsertViewDelegate delegate({
      .zero_state_suggested_results =
          {QuickInsertNewWindowResult(QuickInsertNewWindowResult::Type::kDoc),
           QuickInsertNewWindowResult(
               QuickInsertNewWindowResult::Type::kSheet)},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  PressAndReleaseKey(ui::KeyboardCode::VKEY_RIGHT, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_LEFT, ui::EF_NONE);

  QuickInsertSubmenuController& submenu_controller =
      GetQuickInsertViewFromWidget(*widget)->submenu_controller_for_testing();
  views::test::WidgetDestroyedWaiter(submenu_controller.widget_for_testing())
      .Wait();
  EXPECT_EQ(submenu_controller.GetSubmenuView(), nullptr);
}

TEST_F(QuickInsertViewTest, PressingEscClosesSubmenuThenWidget) {
  FakeQuickInsertViewDelegate delegate({
      .zero_state_suggested_results = {QuickInsertNewWindowResult(
          QuickInsertNewWindowResult::Type::kDoc)},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RIGHT, ui::EF_NONE);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE, ui::EF_NONE);

  QuickInsertSubmenuController& submenu_controller =
      GetQuickInsertViewFromWidget(*widget)->submenu_controller_for_testing();
  views::test::WidgetDestroyedWaiter(submenu_controller.widget_for_testing())
      .Wait();
  EXPECT_EQ(submenu_controller.GetSubmenuView(), nullptr);
  EXPECT_FALSE(widget->IsClosed());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE, ui::EF_NONE);

  views::test::WidgetDestroyedWaiter(widget.get()).Wait();
}

TEST_F(QuickInsertViewTest, PressingEscClosesPreviewThenWidget) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kLocalFiles,
                    {{QuickInsertLocalFileResult(u"a", /*file_path=*/{})}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  QuickInsertPreviewBubbleController& preview_controller =
      GetQuickInsertViewFromWidget(*widget)->preview_controller_for_testing();
  QuickInsertPreviewBubbleVisibleWaiter().Wait(&preview_controller);
  EXPECT_TRUE(preview_controller.IsBubbleVisible());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE, ui::EF_NONE);

  EXPECT_FALSE(preview_controller.IsBubbleVisible());
  EXPECT_FALSE(widget->IsClosed());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_ESCAPE, ui::EF_NONE);

  views::test::WidgetDestroyedWaiter(widget.get()).Wait();
}

TEST_F(QuickInsertViewTest, TabKeyNavigatesItemWithPreview) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kLocalFiles,
                    {{
                        QuickInsertTextResult(u"Result A"),
                        QuickInsertLocalFileResult(u"Result B",
                                                   /*file_path=*/{}),
                        QuickInsertTextResult(u"Result C"),
                    }},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  // Should navigate to the file result and show the preview bubble.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_NONE);
  QuickInsertPreviewBubbleController& preview_controller =
      GetQuickInsertViewFromWidget(*widget)->preview_controller_for_testing();
  QuickInsertPreviewBubbleVisibleWaiter().Wait(&preview_controller);

  EXPECT_TRUE(preview_controller.IsBubbleVisible());

  // Should close the preview bubble and navigate to the next result.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_NONE);

  EXPECT_FALSE(preview_controller.IsBubbleVisible());
  EXPECT_FALSE(widget->IsClosed());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(QuickInsertTextResult(u"Result C")));
}

TEST_F(QuickInsertViewTest, KeyEventsNavigateWithinSubmenu) {
  FakeQuickInsertViewDelegate delegate({
      .zero_state_suggested_results =
          {QuickInsertNewWindowResult(QuickInsertNewWindowResult::Type::kDoc),
           QuickInsertNewWindowResult(
               QuickInsertNewWindowResult::Type::kSheet)},
      .action_type = QuickInsertActionType::kOpen,
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  // Open submenu, navigate down to next submenu item, then select the item.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RIGHT, ui::EF_NONE);
  ViewDrawnWaiter().Wait(GetQuickInsertViewFromWidget(*widget)
                             ->submenu_controller_for_testing()
                             .GetSubmenuView());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_DOWN, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_opened_result(),
              Optional(QuickInsertNewWindowResult(
                  QuickInsertNewWindowResult::Type::kSheet)));
}

TEST_F(QuickInsertViewTest, LeftArrowKeyNavigatesToBackButton) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  // Select a category so that the back button is visible.
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);
  category_item_view->ScrollViewToVisible();
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  // Navigate to the back button from the textfield, then select it.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_LEFT, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_TRUE(quick_insert_view->zero_state_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, RightArrowKeyNavigatesToClearButton) {
  FakeQuickInsertViewDelegate delegate;
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  // Type a query so that the clear button is visible.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  const views::Textfield& textfield = GetQuickInsertViewFromWidget(*widget)
                                          ->search_field_view_for_testing()
                                          .textfield_for_testing();
  EXPECT_EQ(textfield.GetText(), u"a");

  // Navigate to the clear button from the textfield, then select it.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RIGHT, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_TRUE(textfield.GetText().empty());
}

TEST_F(QuickInsertViewTest, TabKeyNavigatesSearchResults) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kClipboard,
                    {{QuickInsertTextResult(u"Result A"),
                      QuickInsertTextResult(u"Result B")}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  ViewDrawnWaiter().Wait(GetQuickInsertViewFromWidget(*widget)
                             ->search_results_view_for_testing()
                             .section_list_view_for_testing()
                             ->GetTopItem());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(QuickInsertTextResult(u"Result B")));
}

TEST_F(QuickInsertViewTest, ShiftTabKeyNavigatesSearchResultsWithEmojiBar) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs},
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kClipboard,
                    {{QuickInsertTextResult(u"Result A"),
                      QuickInsertTextResult(u"Result B")}},
                    /*has_more_results=*/false),
            });
          }),
      .emoji_results = {QuickInsertEmojiResult::Emoji(u"😊")},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  ViewDrawnWaiter().Wait(GetQuickInsertViewFromWidget(*widget)
                             ->search_results_view_for_testing()
                             .section_list_view_for_testing()
                             ->GetTopItem());

  // Navigate backward, to clear button.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
  // Navigate backward, to textfield.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
  // Navigate backward, to emoji bar.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
  // Navigate backward, to the last search result.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_UP);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(QuickInsertTextResult(u"Result B")));
}

TEST_F(QuickInsertViewTest, ShiftTabKeyNavigatesSearchResultsWithoutEmojiBar) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kClipboard,
                    {{QuickInsertTextResult(u"Result A"),
                      QuickInsertTextResult(u"Result B")}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  ViewDrawnWaiter().Wait(GetQuickInsertViewFromWidget(*widget)
                             ->search_results_view_for_testing()
                             .section_list_view_for_testing()
                             ->GetTopItem());

  // Navigate backward, to clear button.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
  // Navigate backward, to textfield.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
  // Navigate backward, to the last search result.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(QuickInsertTextResult(u"Result B")));
}

TEST_F(QuickInsertViewTest, ShiftTabNavigatesToClearButton) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kClipboard,
                    {{QuickInsertTextResult(u"Result A"),
                      QuickInsertTextResult(u"Result B")}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  ViewDrawnWaiter().Wait(GetQuickInsertViewFromWidget(*widget)
                             ->search_results_view_for_testing()
                             .section_list_view_for_testing()
                             ->GetTopItem());

  // Navigate backward, to clear button.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_EQ(GetQuickInsertViewFromWidget(*widget)
                ->search_field_view_for_testing()
                .textfield_for_testing()
                .GetText(),
            u"");
}

TEST_F(QuickInsertViewTest,
       DownArrowKeyNavigatesFromClearButtonToSearchResults) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kClipboard,
                    {{QuickInsertTextResult(u"Result A"),
                      QuickInsertTextResult(u"Result B")}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  ViewDrawnWaiter().Wait(GetQuickInsertViewFromWidget(*widget)
                             ->search_results_view_for_testing()
                             .section_list_view_for_testing()
                             ->GetTopItem());

  // Navigate backward, to clear button.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_SHIFT_DOWN);
  // Navigate downward, to the first search result.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_DOWN, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(QuickInsertTextResult(u"Result A")));
}

TEST_F(QuickInsertViewTest, ShowsSubmenuOnMouseHover) {
  FakeQuickInsertViewDelegate delegate({
      .zero_state_suggested_results =
          {QuickInsertNewWindowResult(QuickInsertNewWindowResult::Type::kDoc),
           QuickInsertNewWindowResult(
               QuickInsertNewWindowResult::Type::kSheet)},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  GetEventGenerator()->MoveMouseTo(
      quick_insert_view->zero_state_view_for_testing()
          .primary_section_view_for_testing()
          ->item_views_for_testing()[0]
          ->GetBoundsInScreen()
          .CenterPoint());

  QuickInsertSubmenuController& submenu_controller =
      quick_insert_view->submenu_controller_for_testing();
  views::test::WidgetVisibleWaiter(submenu_controller.widget_for_testing())
      .Wait();
  EXPECT_NE(submenu_controller.GetSubmenuView(), nullptr);
}

// This is an edge case where the user can open a submenu with mouse hover while
// they are using keyboard to navigate the main QuickInsertView. Since the
// keyboard selection can be separate to the mouse hover selection, we just
// close the submenu if the user resumes keyboard navigation in the main
// QuickInsertView.
TEST_F(QuickInsertViewTest,
       ClosesSubmenuWhenResumingKeyboardNavigationInMainView) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs},
      .zero_state_suggested_results =
          {QuickInsertNewWindowResult(QuickInsertNewWindowResult::Type::kDoc),
           QuickInsertNewWindowResult(
               QuickInsertNewWindowResult::Type::kSheet)},
      .emoji_results = {QuickInsertEmojiResult::Emoji(u"😊"),
                        QuickInsertEmojiResult::Symbol(u"♬")},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  // Start keyboard navigation.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_UP, ui::EF_NONE);
  // Mouse hover over an item with a submenu to show a submenu.
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  GetEventGenerator()->MoveMouseTo(
      quick_insert_view->zero_state_view_for_testing()
          .primary_section_view_for_testing()
          ->item_views_for_testing()[0]
          ->GetBoundsInScreen()
          .CenterPoint());
  QuickInsertSubmenuController& submenu_controller =
      quick_insert_view->submenu_controller_for_testing();
  views::test::WidgetVisibleWaiter(submenu_controller.widget_for_testing())
      .Wait();
  // Resume keyboard navigation.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RIGHT, ui::EF_NONE);

  views::test::WidgetDestroyedWaiter(submenu_controller.widget_for_testing())
      .Wait();
  EXPECT_EQ(submenu_controller.GetSubmenuView(), nullptr);
}

TEST_F(QuickInsertViewTest, ClearsSearchWhenClickingOnCategoryResult) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kNone,
                    {{QuickInsertCategoryResult(QuickInsertCategory::kLinks)}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_result = view->search_results_view_for_testing()
                                     .section_list_view_for_testing()
                                     ->GetTopItem();
  ASSERT_TRUE(category_result);
  ViewDrawnWaiter().Wait(category_result);

  LeftClickOn(category_result);

  EXPECT_EQ(
      view->search_field_view_for_testing().textfield_for_testing().GetText(),
      u"");
}

TEST_F(QuickInsertViewTest,
       PerformsCategorySearchWhenClickingOnSeeMoreResults) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(QuickInsertSectionType::kLinks,
                                                {},
                                                /*has_more_results=*/true),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  future.Clear();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  views::View* trailing_link = view->search_results_view_for_testing()
                                   .section_views_for_testing()[0]
                                   ->title_trailing_link_for_testing();

  ViewDrawnWaiter().Wait(trailing_link);
  LeftClickOn(trailing_link);

  // Should call search a second time.
  EXPECT_TRUE(future.Wait());
  EXPECT_TRUE(view->search_results_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, KeyNavigationToSeeMoreResults) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kClipboard,
                    {{QuickInsertTextResult(u"Result A")}},
                    /*has_more_results=*/false),
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kLinks,
                    {QuickInsertBrowsingHistoryResult({}, u"Result B", {})},
                    /*has_more_results=*/true),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  future.Clear();
  ViewDrawnWaiter().Wait(GetQuickInsertViewFromWidget(*widget)
                             ->search_results_view_for_testing()
                             .section_list_view_for_testing()
                             ->GetTopItem());

  // Navigate to see more button, then press enter.
  PressAndReleaseKey(ui::KeyboardCode::VKEY_TAB, ui::EF_NONE);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  // Should call search a second time.
  EXPECT_TRUE(future.Wait());
  EXPECT_TRUE(GetQuickInsertViewFromWidget(*widget)
                  ->search_results_view_for_testing()
                  .GetVisible());
}

TEST_P(QuickInsertViewEmojiTest,
       ClickingMoreEmojisButtonOpensEmojiPickerWithQuerySearch) {
  FakeQuickInsertViewDelegate delegate({.available_categories = {GetParam()}});
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  QuickInsertEmojiBarView* emoji_bar =
      GetQuickInsertViewFromWidget(*widget)->emoji_bar_view_for_testing();
  ASSERT_NE(emoji_bar, nullptr);
  views::View* more_emojis_button = emoji_bar->more_emojis_button_for_testing();
  ViewDrawnWaiter().Wait(more_emojis_button);
  LeftClickOn(more_emojis_button);

  EXPECT_TRUE(widget->IsClosed());
  EXPECT_THAT(delegate.emoji_picker_category(),
              Optional(Eq(ui::EmojiPickerCategory::kEmojis)));
  EXPECT_THAT(delegate.emoji_picker_query(), Optional(Eq(u"a")));
}

TEST_F(QuickInsertViewTest, ClickingGifsButtonOpensGifPickerWithQuerySearch) {
  base::test::ScopedFeatureList feature_list;
  feature_list.InitAndDisableFeature(features::kPickerGifs);
  FakeQuickInsertViewDelegate delegate(
      {.available_categories = {QuickInsertCategory::kEmojisGifs}});
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  QuickInsertEmojiBarView* emoji_bar =
      GetQuickInsertViewFromWidget(*widget)->emoji_bar_view_for_testing();
  ASSERT_NE(emoji_bar, nullptr);
  views::View* gifs_button = emoji_bar->gifs_button_for_testing();
  ViewDrawnWaiter().Wait(gifs_button);
  LeftClickOn(gifs_button);

  EXPECT_TRUE(widget->IsClosed());
  EXPECT_THAT(delegate.emoji_picker_category(),
              Optional(Eq(ui::EmojiPickerCategory::kGifs)));
  EXPECT_THAT(delegate.emoji_picker_query(), Optional(Eq(u"a")));
}

TEST_F(QuickInsertViewTest,
       KeepsSearchFieldQueryTextAndFocusWhenClickingOnSeeMoreResults) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(QuickInsertSectionType::kLinks,
                                                {},
                                                /*has_more_results=*/true),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  future.Clear();
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  views::View* trailing_link = view->search_results_view_for_testing()
                                   .section_views_for_testing()[0]
                                   ->title_trailing_link_for_testing();

  ViewDrawnWaiter().Wait(trailing_link);
  LeftClickOn(trailing_link);

  EXPECT_EQ(
      view->search_field_view_for_testing().textfield_for_testing().GetText(),
      u"a");
  EXPECT_TRUE(
      view->search_field_view_for_testing().textfield_for_testing().HasFocus());
}

TEST_F(QuickInsertViewTest,
       CategoryOnlySearchShowsNoResultsPageWithNoIllustration) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({});
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  ASSERT_TRUE(future.Wait());
  EXPECT_TRUE(quick_insert_view->search_results_view_for_testing()
                  .no_results_view_for_testing()
                  ->GetVisible());
  EXPECT_FALSE(quick_insert_view->search_results_view_for_testing()
                   .no_results_illustration_for_testing()
                   .GetVisible());
  EXPECT_EQ(quick_insert_view->search_results_view_for_testing()
                .no_results_label_for_testing()
                .GetText(),
            l10n_util::GetStringUTF16(IDS_PICKER_NO_RESULTS_TEXT));
}

TEST_F(QuickInsertViewTest,
       CategoryZeroStateShowsNoResultsPageWithIllustration) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kLinks},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_item_view = GetFirstCategoryItemView(quick_insert_view);
  ViewDrawnWaiter().Wait(category_item_view);
  LeftClickOn(category_item_view);

  EXPECT_TRUE(quick_insert_view->category_results_view_for_testing()
                  .no_results_view_for_testing()
                  ->GetVisible());
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
  EXPECT_TRUE(quick_insert_view->category_results_view_for_testing()
                  .no_results_illustration_for_testing()
                  .GetVisible());
#endif
  EXPECT_EQ(quick_insert_view->category_results_view_for_testing()
                .no_results_label_for_testing()
                .GetText(),
            l10n_util::GetStringUTF16(
                IDS_PICKER_NO_RESULTS_FOR_BROWSING_HISTORY_LABEL_TEXT));
}

TEST_F(
    QuickInsertViewTest,
    ChangingPseudoFocusOnZeroStateNotifiesInitialActiveDescendantChangeAfterDelay) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kClipboard,
                               QuickInsertCategory::kLinks},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  views::test::AXEventCounter counter(views::AXUpdateNotifier::Get());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_DOWN, ui::EF_NONE);

  EXPECT_EQ(counter.GetCount(ax::mojom::Event::kActiveDescendantChanged), 0);

  task_environment()->FastForwardBy(
      QuickInsertSearchFieldView::kNotifyInitialActiveDescendantA11yDelay);

  EXPECT_EQ(counter.GetCount(ax::mojom::Event::kActiveDescendantChanged), 1);
}

TEST_F(
    QuickInsertViewTest,
    ChangingPseudoFocusOnZeroStateNotifiesActiveDescendantChangeImmediately) {
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kClipboard,
                               QuickInsertCategory::kLinks},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  views::test::AXEventCounter counter(views::AXUpdateNotifier::Get());

  PressAndReleaseKey(ui::KeyboardCode::VKEY_DOWN, ui::EF_NONE);
  task_environment()->FastForwardBy(
      QuickInsertSearchFieldView::kNotifyInitialActiveDescendantA11yDelay);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_DOWN, ui::EF_NONE);

  EXPECT_EQ(counter.GetCount(ax::mojom::Event::kActiveDescendantChanged), 2);
}

TEST_F(QuickInsertViewTest, EnterOnZeroState) {
  FakeQuickInsertViewDelegate delegate({
      .zero_state_suggested_results = {QuickInsertTextResult(u"zero state")},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  base::span<const raw_ptr<QuickInsertItemView>> zero_state_item_views =
      quick_insert_view->zero_state_view_for_testing()
          .primary_section_view_for_testing()
          ->item_views_for_testing();
  QuickInsertListItemView* suggested_item_view;
  ASSERT_THAT(
      zero_state_item_views,
      ElementsAre(ResultOf(
          [&](const raw_ptr<QuickInsertItemView> view) {
            ViewDrawnWaiter().Wait(view);
            suggested_item_view =
                views::AsViewClass<QuickInsertListItemView>(view);
            return suggested_item_view;
          },
          Pointee(
              AllOf(Property("primary text",
                             &QuickInsertListItemView::GetPrimaryTextForTesting,
                             u"zero state"),
                    Property("is visible", &views::View::GetVisible, true))))));
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(VariantWith<QuickInsertTextResult>(
                  Field("primary text", &QuickInsertTextResult::primary_text,
                        u"zero state"))));
}

// TODO: b/351920494 - Insert the first new result instead of doing nothing.
TEST_F(QuickInsertViewTest, EnterDuringBurnInOnZeroState) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .zero_state_suggested_results = {QuickInsertTextResult(u"zero state")},
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  base::span<const raw_ptr<QuickInsertItemView>> zero_state_item_views =
      quick_insert_view->zero_state_view_for_testing()
          .primary_section_view_for_testing()
          ->item_views_for_testing();
  QuickInsertListItemView* suggested_item_view;
  ASSERT_THAT(
      zero_state_item_views,
      ElementsAre(ResultOf(
          [&](const raw_ptr<QuickInsertItemView> view) {
            ViewDrawnWaiter().Wait(view);
            suggested_item_view =
                views::AsViewClass<QuickInsertListItemView>(view);
            return suggested_item_view;
          },
          Pointee(
              AllOf(Property("primary text",
                             &QuickInsertListItemView::GetPrimaryTextForTesting,
                             u"zero state"),
                    Property("is visible", &views::View::GetVisible, true))))));
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  // The suggested item should still be visible.
  ASSERT_TRUE(suggested_item_view->GetVisible());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_EQ(delegate.last_inserted_result(), std::nullopt);
}

TEST_F(QuickInsertViewTest, EnterOnSearchResults) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(callback);
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback first_callback =
      future.Take();
  first_callback.Run(
      {QuickInsertSearchResultsSection(QuickInsertSectionType::kClipboard,
                                       {QuickInsertTextResult(u"first search")},
                                       /*has_more_results=*/false)});
  base::span<const raw_ptr<QuickInsertSectionView>> section_views =
      quick_insert_view->search_results_view_for_testing()
          .section_views_for_testing();
  QuickInsertListItemView* search_item_view;
  ASSERT_THAT(
      section_views,
      ElementsAre(Pointee(Property(
          "item views", &QuickInsertSectionView::item_views_for_testing,
          ElementsAre(ResultOf(
              [&](const raw_ptr<QuickInsertItemView> view) {
                ViewDrawnWaiter().Wait(view);
                search_item_view =
                    views::AsViewClass<QuickInsertListItemView>(view);
                return search_item_view;
              },
              Pointee(AllOf(
                  Property("primary text",
                           &QuickInsertListItemView::GetPrimaryTextForTesting,
                           u"first search"),
                  Property("is visible", &views::View::GetVisible,
                           true)))))))));
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_THAT(delegate.last_inserted_result(),
              Optional(VariantWith<QuickInsertTextResult>(
                  Field("primary text", &QuickInsertTextResult::primary_text,
                        u"first search"))));
}

// TODO: b/351920494 - Insert the first new result instead of doing nothing.
TEST_F(QuickInsertViewTest, EnterDuringBurnInOnSearchResults) {
  base::test::TestFuture<FakeQuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue(callback);
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback first_callback =
      future.Take();
  first_callback.Run(
      {QuickInsertSearchResultsSection(QuickInsertSectionType::kClipboard,
                                       {QuickInsertTextResult(u"first search")},
                                       /*has_more_results=*/false)});
  base::span<const raw_ptr<QuickInsertSectionView>> section_views =
      quick_insert_view->search_results_view_for_testing()
          .section_views_for_testing();
  QuickInsertListItemView* search_item_view;
  ASSERT_THAT(
      section_views,
      ElementsAre(Pointee(Property(
          "item views", &QuickInsertSectionView::item_views_for_testing,
          ElementsAre(ResultOf(
              [&](const raw_ptr<QuickInsertItemView> view) {
                ViewDrawnWaiter().Wait(view);
                search_item_view =
                    views::AsViewClass<QuickInsertListItemView>(view);
                return search_item_view;
              },
              Pointee(AllOf(
                  Property("primary text",
                           &QuickInsertListItemView::GetPrimaryTextForTesting,
                           u"first search"),
                  Property("is visible", &views::View::GetVisible,
                           true)))))))));
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  FakeQuickInsertViewDelegate::SearchResultsCallback second_callback =
      future.Take();
  // The search item should still be visible.
  ASSERT_TRUE(search_item_view->GetVisible());
  PressAndReleaseKey(ui::KeyboardCode::VKEY_RETURN, ui::EF_NONE);

  EXPECT_EQ(delegate.last_inserted_result(), std::nullopt);
}

TEST_F(QuickInsertViewTest, ResetsToZeroStateWhenClickingOnBackButton) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kNone,
                    {{QuickInsertCategoryResult(QuickInsertCategory::kLinks)}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_result = view->search_results_view_for_testing()
                                     .section_list_view_for_testing()
                                     ->GetTopItem();
  ASSERT_TRUE(category_result);
  ViewDrawnWaiter().Wait(category_result);
  LeftClickOn(category_result);

  QuickInsertSearchFieldView& search_field_view =
      view->search_field_view_for_testing();
  ViewDrawnWaiter().Wait(&search_field_view.back_button_for_testing());
  LeftClickOn(&search_field_view.back_button_for_testing());

  EXPECT_TRUE(view->zero_state_view_for_testing().GetVisible());
  EXPECT_EQ(search_field_view.textfield_for_testing().GetText(), u"");
  EXPECT_FALSE(search_field_view.clear_button_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, ResetsToZeroStateAfterPressingBrowserBack) {
  base::test::TestFuture<void> future;
  FakeQuickInsertViewDelegate delegate({
      .search_function = base::BindLambdaForTesting(
          [&](std::u16string_view query,
              FakeQuickInsertViewDelegate::SearchResultsCallback callback) {
            future.SetValue();
            callback.Run({
                QuickInsertSearchResultsSection(
                    QuickInsertSectionType::kNone,
                    {{QuickInsertCategoryResult(QuickInsertCategory::kLinks)}},
                    /*has_more_results=*/false),
            });
          }),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  ASSERT_TRUE(future.Wait());
  QuickInsertView* view = GetQuickInsertViewFromWidget(*widget);
  views::View* category_result = view->search_results_view_for_testing()
                                     .section_list_view_for_testing()
                                     ->GetTopItem();
  ASSERT_TRUE(category_result);
  ViewDrawnWaiter().Wait(category_result);
  LeftClickOn(category_result);

  PressAndReleaseKey(ui::KeyboardCode::VKEY_BROWSER_BACK, ui::EF_NONE);

  EXPECT_TRUE(view->zero_state_view_for_testing().GetVisible());
  EXPECT_EQ(
      view->search_field_view_for_testing().textfield_for_testing().GetText(),
      u"");
  EXPECT_FALSE(view->search_field_view_for_testing()
                   .clear_button_for_testing()
                   .GetVisible());
}

TEST_F(QuickInsertViewTest, CheckingGifButtonWithQueryShowsGifSearchResults) {
  base::test::ScopedFeatureList feature_list(features::kPickerGifs);
  base::test::TestFuture<std::u16string_view,
                         QuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs,
                               QuickInsertCategory::kGifs},
      .search_function = future.GetRepeatingCallback(),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  future.Clear();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::Button* gifs_button = quick_insert_view->emoji_bar_view_for_testing()
                                   ->gifs_button_for_testing();
  ViewDrawnWaiter().Wait(gifs_button);
  LeftClickOn(gifs_button);
  auto [query, search_callback] = future.Take();
  std::move(search_callback)
      .Run({
          QuickInsertSearchResultsSection(
              QuickInsertSectionType::kNone,
              {{QuickInsertGifResult(
                  GURL("http://foo.com/fake_preview.gif"),
                  GURL("http://foo.com/fake_preview_image.png"), gfx::Size(),
                  GURL("http://foo.com/fake.gif"), gfx::Size(),
                  /*content_description=*/u"")}},
              /*has_more_results=*/false),
      });

  EXPECT_EQ(query, u"a");
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_THAT(
      quick_insert_view->search_results_view_for_testing()
          .section_views_for_testing(),
      ElementsAre(Pointee(Property(
          "item views", &QuickInsertSectionView::item_views_for_testing,
          ElementsAre(AsView<QuickInsertImageItemView>(Property(
              "image view", &QuickInsertImageItemView::image_view_for_testing,
              Truly(&views::IsViewClass<QuickInsertGifView>))))))));
}

TEST_F(QuickInsertViewTest,
       TypingQueryWithGifToggleCheckedShowsGifSearchResults) {
  base::test::ScopedFeatureList feature_list(features::kPickerGifs);
  base::test::TestFuture<std::u16string_view,
                         QuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs,
                               QuickInsertCategory::kGifs},
      .search_function = future.GetRepeatingCallback(),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();

  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::Button* gifs_button = quick_insert_view->emoji_bar_view_for_testing()
                                   ->gifs_button_for_testing();
  ViewDrawnWaiter().Wait(gifs_button);
  LeftClickOn(gifs_button);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);

  auto [query, search_callback] = future.Take();
  std::move(search_callback)
      .Run({
          QuickInsertSearchResultsSection(
              QuickInsertSectionType::kNone,
              {{QuickInsertGifResult(
                  GURL("http://foo.com/fake_preview.gif"),
                  GURL("http://foo.com/fake_preview_image.png"), gfx::Size(),
                  GURL("http://foo.com/fake.gif"), gfx::Size(),
                  /*content_description=*/u"")}},
              /*has_more_results=*/false),
      });

  EXPECT_EQ(query, u"a");
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_THAT(
      quick_insert_view->search_results_view_for_testing()
          .section_views_for_testing(),
      ElementsAre(Pointee(Property(
          "item views", &QuickInsertSectionView::item_views_for_testing,
          ElementsAre(AsView<QuickInsertImageItemView>(Property(
              "image view", &QuickInsertImageItemView::image_view_for_testing,
              Truly(&views::IsViewClass<QuickInsertGifView>))))))));
}

TEST_F(QuickInsertViewTest, UncheckingGifButtonSearchesNormally) {
  base::test::ScopedFeatureList feature_list(features::kPickerGifs);
  base::test::TestFuture<std::u16string_view,
                         QuickInsertViewDelegate::SearchResultsCallback>
      future;
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs,
                               QuickInsertCategory::kGifs},
      .search_function = future.GetRepeatingCallback(),
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::Button* gifs_button = quick_insert_view->emoji_bar_view_for_testing()
                                   ->gifs_button_for_testing();
  ViewDrawnWaiter().Wait(gifs_button);
  LeftClickOn(gifs_button);
  PressAndReleaseKey(ui::KeyboardCode::VKEY_A, ui::EF_NONE);
  future.Clear();

  LeftClickOn(gifs_button);
  auto [query, search_callback] = future.Take();
  std::move(search_callback)
      .Run({
          QuickInsertSearchResultsSection(QuickInsertSectionType::kClipboard,
                                          {{QuickInsertTextResult(u"result")}},
                                          /*has_more_results=*/false),
      });

  EXPECT_EQ(query, u"a");
  EXPECT_TRUE(
      quick_insert_view->search_results_view_for_testing().GetVisible());
  EXPECT_THAT(
      quick_insert_view->search_results_view_for_testing()
          .section_views_for_testing(),
      ElementsAre(Pointee(Property(
          "item views", &QuickInsertSectionView::item_views_for_testing,
          ElementsAre(Truly(&views::IsViewClass<QuickInsertListItemView>))))));
}

TEST_F(QuickInsertViewTest, UncheckingGifButtonWithoutQueryShowsZeroState) {
  base::test::ScopedFeatureList feature_list(features::kPickerGifs);
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs,
                               QuickInsertCategory::kGifs},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::Button* gifs_button = quick_insert_view->emoji_bar_view_for_testing()
                                   ->gifs_button_for_testing();
  ViewDrawnWaiter().Wait(gifs_button);
  LeftClickOn(gifs_button);

  LeftClickOn(gifs_button);

  EXPECT_TRUE(quick_insert_view->zero_state_view_for_testing().GetVisible());
}

TEST_F(QuickInsertViewTest, CheckingGifButtonDoesNotShowBackButton) {
  base::test::ScopedFeatureList feature_list(features::kPickerGifs);
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs,
                               QuickInsertCategory::kGifs},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::Button* gifs_button = quick_insert_view->emoji_bar_view_for_testing()
                                   ->gifs_button_for_testing();
  ViewDrawnWaiter().Wait(gifs_button);

  LeftClickOn(gifs_button);

  EXPECT_FALSE(quick_insert_view->search_field_view_for_testing()
                   .back_button_for_testing()
                   .GetVisible());
}

TEST_F(QuickInsertViewTest, CheckingGifButtonKeepsEmojiBarVisible) {
  base::test::ScopedFeatureList feature_list(features::kPickerGifs);
  FakeQuickInsertViewDelegate delegate({
      .available_categories = {QuickInsertCategory::kEmojisGifs,
                               QuickInsertCategory::kGifs},
  });
  auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
  widget->Show();
  QuickInsertView* quick_insert_view = GetQuickInsertViewFromWidget(*widget);
  views::Button* gifs_button = quick_insert_view->emoji_bar_view_for_testing()
                                   ->gifs_button_for_testing();
  ViewDrawnWaiter().Wait(gifs_button);

  LeftClickOn(gifs_button);

  EXPECT_TRUE(quick_insert_view->emoji_bar_view_for_testing()->GetVisible());
}

}  // namespace
}  // namespace ash
