blob: 7851f960be994656b0fb5731912d1664d5fb9d27 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/quick_insert/views/quick_insert_widget.h"
#include <memory>
#include <string_view>
#include "ash/quick_insert/metrics/quick_insert_session_metrics.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/views/quick_insert_preview_bubble.h"
#include "ash/quick_insert/views/quick_insert_view.h"
#include "ash/quick_insert/views/quick_insert_view_delegate.h"
#include "ash/test/ash_test_base.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/window.h"
#include "ui/display/screen.h"
#include "ui/events/test/event_generator.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/views/view_utils.h"
#include "ui/views/widget/widget_utils.h"
namespace ash {
namespace {
using ::testing::ElementsAre;
using ::testing::Truly;
constexpr gfx::Rect kDefaultAnchorBounds(200, 100, 0, 10);
class FakeQuickInsertViewDelegate : public QuickInsertViewDelegate {
public:
// QuickInsertViewDelegate:
std::vector<QuickInsertCategory> GetAvailableCategories() override {
return {};
}
void GetZeroStateSuggestedResults(
SuggestedResultsCallback callback) override {}
void GetResultsForCategory(QuickInsertCategory category,
SearchResultsCallback callback) override {}
void StartSearch(std::u16string_view query,
std::optional<QuickInsertCategory> category,
SearchResultsCallback callback) override {}
void StopSearch() override {}
void StartEmojiSearch(std::u16string_view query,
EmojiSearchResultsCallback callback) override {}
void CloseWidgetThenInsertResultOnNextFocus(
const QuickInsertSearchResult& result) override {}
void OpenResult(const QuickInsertSearchResult& result) override {}
void ShowEmojiPicker(ui::EmojiPickerCategory category,
std::u16string_view query) override {}
void ShowEditor(std::optional<std::string> preset_query_id,
std::optional<std::string> freeform_text) override {}
void ShowLobster(std::optional<std::string> freeform_text) override {}
QuickInsertAssetFetcher* GetAssetFetcher() override { return nullptr; }
QuickInsertSessionMetrics& GetSessionMetrics() override {
return session_metrics_;
}
QuickInsertActionType GetActionForResult(
const QuickInsertSearchResult& result) override {
return QuickInsertActionType::kInsert;
}
std::vector<QuickInsertEmojiResult> GetSuggestedEmoji() override {
return {};
}
bool IsGifsEnabled() override { return true; }
QuickInsertModeType GetMode() override {
return QuickInsertModeType::kNoSelection;
}
QuickInsertCapsLockPosition GetCapsLockPosition() override {
return QuickInsertCapsLockPosition::kTop;
}
private:
QuickInsertSessionMetrics session_metrics_;
};
using QuickInsertWidgetTest = AshTestBase;
TEST_F(QuickInsertWidgetTest, CreateWidgetHasCorrectHierarchy) {
FakeQuickInsertViewDelegate delegate;
auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
// Widget should contain a NonClientView, which has a FrameView for
// borders and shadows, and a ClientView with a sole child of the
// QuickInsertView.
ASSERT_TRUE(widget);
ASSERT_TRUE(widget->non_client_view());
ASSERT_TRUE(widget->non_client_view()->frame_view());
ASSERT_TRUE(widget->non_client_view()->client_view());
EXPECT_THAT(widget->non_client_view()->client_view()->children(),
ElementsAre(Truly(views::IsViewClass<QuickInsertView>)));
}
TEST_F(QuickInsertWidgetTest, CreateWidgetHasCorrectBorder) {
FakeQuickInsertViewDelegate delegate;
auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
EXPECT_TRUE(widget->non_client_view()->frame_view()->GetBorder());
}
TEST_F(QuickInsertWidgetTest, ClickingOutsideClosesQuickInsertWidget) {
FakeQuickInsertViewDelegate delegate;
auto widget = QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
widget->Show();
gfx::Point point_outside_widget = widget->GetWindowBoundsInScreen().origin();
point_outside_widget.Offset(-10, -10);
GetEventGenerator()->MoveMouseTo(point_outside_widget);
GetEventGenerator()->ClickLeftButton();
EXPECT_TRUE(widget->IsClosed());
}
TEST_F(QuickInsertWidgetTest, LosingFocusClosesQuickInsertWidget) {
// Create something other than Quick Insert to focus.
auto window = CreateTestWindow();
window->Show();
// Create the fake Quick Insert and make sure it has focus.
FakeQuickInsertViewDelegate delegate;
auto quick_insert_widget =
QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
quick_insert_widget->Show();
EXPECT_THAT(quick_insert_widget->GetFocusManager()->GetFocusedView(),
testing::NotNull());
// Focus the other Widget and expect Quick Insert to have closed.
window->Focus();
EXPECT_TRUE(window->HasFocus());
EXPECT_TRUE(quick_insert_widget->IsClosed());
EXPECT_EQ(delegate.GetSessionMetrics().GetOutcomeForTesting(),
QuickInsertSessionMetrics::SessionOutcome::kAbandoned);
}
TEST_F(QuickInsertWidgetTest, PreviewBubbleDoesNotStealFocusQuickInsertWidget) {
std::unique_ptr<views::Widget> anchor_widget = CreateFramelessTestWidget();
anchor_widget->SetContentsView(std::make_unique<views::View>());
// Create the QuickInsertWidget and make sure it has focus.
FakeQuickInsertViewDelegate delegate;
auto quick_insert_widget =
QuickInsertWidget::Create(&delegate, kDefaultAnchorBounds);
quick_insert_widget->Show();
// Show bubble widget and expect the QuickInsertWidget to not close.
views::View* bubble_view =
new QuickInsertPreviewBubbleView(anchor_widget->GetContentsView());
bubble_view->GetWidget()->Show();
EXPECT_FALSE(quick_insert_widget->IsClosed());
bubble_view->GetWidget()->CloseNow();
}
TEST_F(QuickInsertWidgetTest, CreatesCenteredWidget) {
FakeQuickInsertViewDelegate delegate;
auto widget =
QuickInsertWidget::CreateCentered(&delegate, gfx::Rect(10, 10, 10, 10));
widget->Show();
EXPECT_EQ(
widget->GetWindowBoundsInScreen().CenterPoint(),
display::Screen::Get()->GetPrimaryDisplay().work_area().CenterPoint());
}
} // namespace
} // namespace ash