1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/ui/views/toolbar/toolbar_actions_bar_bubble_views.h"
6
7 #include <memory>
8
9 #include "base/run_loop.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/ui/toolbar/test_toolbar_actions_bar_bubble_delegate.h"
12 #include "chrome/browser/ui/toolbar/toolbar_actions_bar_bubble_delegate.h"
13 #include "chrome/grit/generated_resources.h"
14 #include "chrome/test/views/chrome_views_test_base.h"
15 #include "components/vector_icons/vector_icons.h"
16 #include "ui/base/l10n/l10n_util.h"
17 #include "ui/base/resource/resource_bundle.h"
18 #include "ui/events/event_utils.h"
19 #include "ui/gfx/color_palette.h"
20 #include "ui/gfx/image/image.h"
21 #include "ui/gfx/image/image_unittest_util.h"
22 #include "ui/gfx/paint_vector_icon.h"
23 #include "ui/views/controls/button/image_button.h"
24 #include "ui/views/controls/button/label_button.h"
25 #include "ui/views/controls/link.h"
26 #include "ui/views/test/test_widget_observer.h"
27 #include "ui/views/widget/widget.h"
28
29 namespace {
30 const int kIconSize = 16;
31 }
32
33 class ToolbarActionsBarBubbleViewsTest : public ChromeViewsTestBase {
34 protected:
ToolbarActionsBarBubbleViewsTest()35 ToolbarActionsBarBubbleViewsTest() {}
36 ToolbarActionsBarBubbleViewsTest(const ToolbarActionsBarBubbleViewsTest&) =
37 delete;
38 ToolbarActionsBarBubbleViewsTest& operator=(
39 const ToolbarActionsBarBubbleViewsTest&) = delete;
40 ~ToolbarActionsBarBubbleViewsTest() override = default;
41
TearDown()42 void TearDown() override {
43 anchor_widget_.reset();
44 ChromeViewsTestBase::TearDown();
45 }
46
CreateAnchorWidget()47 std::unique_ptr<views::Widget> CreateAnchorWidget() {
48 std::unique_ptr<views::Widget> anchor_widget =
49 CreateTestWidget(views::Widget::InitParams::TYPE_WINDOW);
50 anchor_widget->Show();
51 return anchor_widget;
52 }
53
ShowBubble(TestToolbarActionsBarBubbleDelegate * delegate)54 void ShowBubble(TestToolbarActionsBarBubbleDelegate* delegate) {
55 ASSERT_TRUE(delegate);
56 ASSERT_FALSE(bubble_widget_);
57 ASSERT_FALSE(bubble_);
58 anchor_widget_ = CreateAnchorWidget();
59 bool anchored_to_action = false;
60 bubble_ = new ToolbarActionsBarBubbleViews(
61 anchor_widget_->GetContentsView(), anchored_to_action,
62 delegate->GetDelegate());
63 bubble_widget_ = views::BubbleDialogDelegateView::CreateBubble(bubble_);
64 bubble_widget_->Show();
65 }
66
CloseBubble()67 void CloseBubble() {
68 ASSERT_TRUE(bubble_);
69 bubble_->GetWidget()->Close();
70 base::RunLoop().RunUntilIdle();
71 bubble_ = nullptr;
72 bubble_widget_ = nullptr;
73 }
74
ClickButton(views::Button * button)75 void ClickButton(views::Button* button) {
76 bubble()->ResetViewShownTimeStampForTesting();
77
78 ASSERT_TRUE(button);
79 const gfx::Point point(10, 10);
80 const ui::MouseEvent event(ui::ET_MOUSE_PRESSED, point, point,
81 ui::EventTimeForNow(), ui::EF_LEFT_MOUSE_BUTTON,
82 ui::EF_LEFT_MOUSE_BUTTON);
83 button->OnMousePressed(event);
84 button->OnMouseReleased(event);
85 base::RunLoop().RunUntilIdle();
86 }
87
HeadingString()88 base::string16 HeadingString() { return base::ASCIIToUTF16("Heading"); }
BodyString()89 base::string16 BodyString() { return base::ASCIIToUTF16("Body"); }
ActionString()90 base::string16 ActionString() { return base::ASCIIToUTF16("Action"); }
DismissString()91 base::string16 DismissString() { return base::ASCIIToUTF16("Dismiss"); }
LearnMoreString()92 base::string16 LearnMoreString() { return base::ASCIIToUTF16("Learn"); }
ItemListString()93 base::string16 ItemListString() {
94 return base::ASCIIToUTF16("Item 1\nItem2");
95 }
96
anchor_widget()97 views::Widget* anchor_widget() { return anchor_widget_.get(); }
bubble_widget()98 views::Widget* bubble_widget() { return bubble_widget_; }
bubble()99 ToolbarActionsBarBubbleViews* bubble() { return bubble_; }
100
101 private:
102 std::unique_ptr<views::Widget> anchor_widget_;
103 views::Widget* bubble_widget_ = nullptr;
104 ToolbarActionsBarBubbleViews* bubble_ = nullptr;
105 };
106
TEST_F(ToolbarActionsBarBubbleViewsTest,TestBubbleLayoutActionButton)107 TEST_F(ToolbarActionsBarBubbleViewsTest, TestBubbleLayoutActionButton) {
108 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
109 ActionString());
110 ShowBubble(&delegate);
111
112 EXPECT_TRUE(bubble()->GetOkButton());
113 EXPECT_EQ(ActionString(), bubble()->GetOkButton()->GetText());
114 EXPECT_FALSE(bubble()->GetCancelButton());
115
116 CloseBubble();
117 }
118
TEST_F(ToolbarActionsBarBubbleViewsTest,TestBubbleLayoutNoButtons)119 TEST_F(ToolbarActionsBarBubbleViewsTest, TestBubbleLayoutNoButtons) {
120 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
121 ActionString());
122 std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>
123 extra_view_info =
124 std::make_unique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>();
125 delegate.set_extra_view_info(std::move(extra_view_info));
126 delegate.set_dismiss_button_text(base::string16());
127 delegate.set_action_button_text(base::string16());
128 ShowBubble(&delegate);
129
130 EXPECT_EQ(nullptr, bubble()->GetExtraView());
131 EXPECT_FALSE(bubble()->GetOkButton());
132 EXPECT_FALSE(bubble()->GetCancelButton());
133 EXPECT_FALSE(bubble()->learn_more_button());
134
135 CloseBubble();
136 }
137
TEST_F(ToolbarActionsBarBubbleViewsTest,TestBubbleLayoutActionAndDismissButton)138 TEST_F(ToolbarActionsBarBubbleViewsTest,
139 TestBubbleLayoutActionAndDismissButton) {
140 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
141 ActionString());
142 delegate.set_dismiss_button_text(DismissString());
143 ShowBubble(&delegate);
144
145 EXPECT_TRUE(bubble()->GetOkButton());
146 EXPECT_EQ(ActionString(), bubble()->GetOkButton()->GetText());
147 EXPECT_TRUE(bubble()->GetCancelButton());
148 EXPECT_EQ(DismissString(), bubble()->GetCancelButton()->GetText());
149
150 EXPECT_FALSE(bubble()->learn_more_button());
151 EXPECT_FALSE(bubble()->item_list());
152
153 CloseBubble();
154 }
155
TEST_F(ToolbarActionsBarBubbleViewsTest,TestBubbleLayoutActionDismissAndLearnMoreButton)156 TEST_F(ToolbarActionsBarBubbleViewsTest,
157 TestBubbleLayoutActionDismissAndLearnMoreButton) {
158 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
159 ActionString());
160 delegate.set_dismiss_button_text(DismissString());
161 std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>
162 extra_view_info_linked_text =
163 std::make_unique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>();
164 extra_view_info_linked_text->text = LearnMoreString();
165 extra_view_info_linked_text->is_learn_more = true;
166 delegate.set_extra_view_info(std::move(extra_view_info_linked_text));
167
168 ShowBubble(&delegate);
169
170 EXPECT_TRUE(bubble()->GetOkButton());
171 EXPECT_EQ(ActionString(), bubble()->GetOkButton()->GetText());
172 EXPECT_TRUE(bubble()->GetCancelButton());
173 EXPECT_EQ(DismissString(), bubble()->GetCancelButton()->GetText());
174 EXPECT_TRUE(bubble()->learn_more_button());
175 EXPECT_EQ(LearnMoreString(),
176 bubble()->learn_more_button()->GetTooltipText(gfx::Point(0, 0)));
177 EXPECT_FALSE(bubble()->item_list());
178
179 CloseBubble();
180 }
181
TEST_F(ToolbarActionsBarBubbleViewsTest,TestBubbleLayoutListView)182 TEST_F(ToolbarActionsBarBubbleViewsTest, TestBubbleLayoutListView) {
183 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
184 ActionString());
185 delegate.set_item_list_text(ItemListString());
186 ShowBubble(&delegate);
187
188 EXPECT_TRUE(bubble()->GetOkButton());
189 EXPECT_EQ(ActionString(), bubble()->GetOkButton()->GetText());
190 EXPECT_FALSE(bubble()->GetCancelButton());
191 EXPECT_FALSE(bubble()->learn_more_button());
192 EXPECT_TRUE(bubble()->item_list());
193 EXPECT_EQ(ItemListString(), bubble()->item_list()->GetText());
194
195 CloseBubble();
196 }
197
TEST_F(ToolbarActionsBarBubbleViewsTest,TestBubbleLayoutNoBodyText)198 TEST_F(ToolbarActionsBarBubbleViewsTest, TestBubbleLayoutNoBodyText) {
199 TestToolbarActionsBarBubbleDelegate delegate(
200 HeadingString(), base::string16(), ActionString());
201 ShowBubble(&delegate);
202
203 EXPECT_TRUE(bubble()->GetOkButton());
204 EXPECT_EQ(ActionString(), bubble()->GetOkButton()->GetText());
205 EXPECT_FALSE(bubble()->GetCancelButton());
206 EXPECT_FALSE(bubble()->learn_more_button());
207 EXPECT_FALSE(bubble()->body_text());
208 EXPECT_FALSE(bubble()->item_list());
209
210 CloseBubble();
211 }
212
TEST_F(ToolbarActionsBarBubbleViewsTest,TestBubbleDefaultDialogButtons)213 TEST_F(ToolbarActionsBarBubbleViewsTest, TestBubbleDefaultDialogButtons) {
214 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
215 ActionString());
216 delegate.set_dismiss_button_text(DismissString());
217 delegate.set_default_dialog_button(ui::DIALOG_BUTTON_OK);
218 ShowBubble(&delegate);
219
220 ASSERT_TRUE(bubble()->GetOkButton());
221 EXPECT_TRUE(bubble()->GetOkButton()->GetIsDefault());
222
223 ASSERT_TRUE(bubble()->GetCancelButton());
224 EXPECT_FALSE(bubble()->GetCancelButton()->GetIsDefault());
225
226 CloseBubble();
227 }
228
TEST_F(ToolbarActionsBarBubbleViewsTest,TestShowAndCloseBubble)229 TEST_F(ToolbarActionsBarBubbleViewsTest, TestShowAndCloseBubble) {
230 std::unique_ptr<views::Widget> anchor_widget = CreateAnchorWidget();
231 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
232 ActionString());
233 delegate.set_dismiss_button_text(DismissString());
234 ToolbarActionsBarBubbleViews* bubble = new ToolbarActionsBarBubbleViews(
235 anchor_widget->GetContentsView(), false, delegate.GetDelegate());
236
237 EXPECT_FALSE(delegate.shown());
238 EXPECT_FALSE(delegate.close_action());
239 views::Widget* bubble_widget =
240 views::BubbleDialogDelegateView::CreateBubble(bubble);
241 views::test::TestWidgetObserver bubble_observer(bubble_widget);
242 bubble_widget->Show();
243 EXPECT_TRUE(delegate.shown());
244 EXPECT_FALSE(delegate.close_action());
245
246 bubble->CancelDialog();
247 base::RunLoop().RunUntilIdle();
248 ASSERT_TRUE(delegate.close_action());
249 EXPECT_EQ(ToolbarActionsBarBubbleDelegate::CLOSE_DISMISS_USER_ACTION,
250 *delegate.close_action());
251 EXPECT_TRUE(bubble_observer.widget_closed());
252 }
253
TEST_F(ToolbarActionsBarBubbleViewsTest,TestClickActionButton)254 TEST_F(ToolbarActionsBarBubbleViewsTest, TestClickActionButton) {
255 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
256 ActionString());
257 delegate.set_dismiss_button_text(DismissString());
258 delegate.set_learn_more_button_text(LearnMoreString());
259 ShowBubble(&delegate);
260 views::test::TestWidgetObserver bubble_observer(bubble_widget());
261
262 EXPECT_FALSE(delegate.close_action());
263
264 ClickButton(bubble()->GetOkButton());
265 ASSERT_TRUE(delegate.close_action());
266 EXPECT_EQ(ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE,
267 *delegate.close_action());
268 EXPECT_TRUE(bubble_observer.widget_closed());
269 }
270
TEST_F(ToolbarActionsBarBubbleViewsTest,TestClickDismissButton)271 TEST_F(ToolbarActionsBarBubbleViewsTest, TestClickDismissButton) {
272 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
273 ActionString());
274 delegate.set_dismiss_button_text(DismissString());
275 delegate.set_learn_more_button_text(LearnMoreString());
276 ShowBubble(&delegate);
277 views::test::TestWidgetObserver bubble_observer(bubble_widget());
278
279 EXPECT_FALSE(delegate.close_action());
280
281 ClickButton(bubble()->GetCancelButton());
282 ASSERT_TRUE(delegate.close_action());
283 EXPECT_EQ(ToolbarActionsBarBubbleDelegate::CLOSE_DISMISS_USER_ACTION,
284 *delegate.close_action());
285 }
286
TEST_F(ToolbarActionsBarBubbleViewsTest,TestClickLearnMoreLink)287 TEST_F(ToolbarActionsBarBubbleViewsTest, TestClickLearnMoreLink) {
288 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
289 ActionString());
290 delegate.set_dismiss_button_text(DismissString());
291 delegate.set_learn_more_button_text(LearnMoreString());
292 ShowBubble(&delegate);
293 views::test::TestWidgetObserver bubble_observer(bubble_widget());
294
295 EXPECT_FALSE(delegate.close_action());
296
297 ClickButton(bubble()->learn_more_button());
298 ASSERT_TRUE(delegate.close_action());
299 EXPECT_EQ(ToolbarActionsBarBubbleDelegate::CLOSE_LEARN_MORE,
300 *delegate.close_action());
301 }
302
TEST_F(ToolbarActionsBarBubbleViewsTest,TestCloseOnDeactivation)303 TEST_F(ToolbarActionsBarBubbleViewsTest, TestCloseOnDeactivation) {
304 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
305 ActionString());
306 ShowBubble(&delegate);
307 views::test::TestWidgetObserver bubble_observer(bubble_widget());
308
309 EXPECT_FALSE(delegate.close_action());
310 // Close the bubble by activating another widget. The delegate should be
311 // told it was dismissed.
312 anchor_widget()->Activate();
313 base::RunLoop().RunUntilIdle();
314 ASSERT_TRUE(delegate.close_action());
315 EXPECT_EQ(ToolbarActionsBarBubbleDelegate::CLOSE_DISMISS_DEACTIVATION,
316 *delegate.close_action());
317 EXPECT_TRUE(bubble_observer.widget_closed());
318 }
319
TEST_F(ToolbarActionsBarBubbleViewsTest,TestDontCloseOnDeactivation)320 TEST_F(ToolbarActionsBarBubbleViewsTest, TestDontCloseOnDeactivation) {
321 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
322 ActionString());
323 delegate.set_close_on_deactivate(false);
324 ShowBubble(&delegate);
325 views::test::TestWidgetObserver bubble_observer(bubble_widget());
326
327 EXPECT_FALSE(delegate.close_action());
328 // Activate another widget. The bubble shouldn't close.
329 anchor_widget()->Activate();
330 base::RunLoop().RunUntilIdle();
331 EXPECT_FALSE(delegate.close_action());
332 CloseBubble();
333 }
334
TEST_F(ToolbarActionsBarBubbleViewsTest,TestNullExtraView)335 TEST_F(ToolbarActionsBarBubbleViewsTest, TestNullExtraView) {
336 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
337 ActionString());
338 ShowBubble(&delegate);
339 EXPECT_EQ(nullptr, bubble()->GetExtraView());
340 CloseBubble();
341 }
342
TEST_F(ToolbarActionsBarBubbleViewsTest,TestCreateExtraViewIconOnly)343 TEST_F(ToolbarActionsBarBubbleViewsTest, TestCreateExtraViewIconOnly) {
344 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
345 ActionString());
346 std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>
347 extra_view_info =
348 std::make_unique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>();
349 extra_view_info->resource = &vector_icons::kBusinessIcon;
350 delegate.set_extra_view_info(std::move(extra_view_info));
351 ShowBubble(&delegate);
352 const views::View* const extra_view = bubble()->GetExtraView();
353 ASSERT_TRUE(extra_view);
354 ASSERT_EQ("ImageView", std::string(extra_view->GetClassName()));
355 EXPECT_TRUE(gfx::test::AreImagesEqual(
356 gfx::Image(static_cast<const views::ImageView*>(extra_view)->GetImage()),
357 gfx::Image(gfx::CreateVectorIcon(vector_icons::kBusinessIcon, kIconSize,
358 gfx::kChromeIconGrey))));
359 CloseBubble();
360 }
361
TEST_F(ToolbarActionsBarBubbleViewsTest,TestCreateExtraViewLinkedTextOnly)362 TEST_F(ToolbarActionsBarBubbleViewsTest, TestCreateExtraViewLinkedTextOnly) {
363 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
364 ActionString());
365 std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>
366 extra_view_info_linked_text =
367 std::make_unique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>();
368 extra_view_info_linked_text->text =
369 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN);
370 extra_view_info_linked_text->is_learn_more = true;
371 delegate.set_extra_view_info(std::move(extra_view_info_linked_text));
372
373 ShowBubble(&delegate);
374
375 const views::View* const extra_view = bubble()->GetExtraView();
376 ASSERT_TRUE(extra_view);
377 ASSERT_EQ("ImageButton", std::string(extra_view->GetClassName()));
378 EXPECT_EQ(l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN),
379 extra_view->GetTooltipText(gfx::Point(0, 0)));
380 CloseBubble();
381 }
382
TEST_F(ToolbarActionsBarBubbleViewsTest,TestCreateExtraViewLabelTextOnly)383 TEST_F(ToolbarActionsBarBubbleViewsTest, TestCreateExtraViewLabelTextOnly) {
384 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
385 ActionString());
386 std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>
387 extra_view_info =
388 std::make_unique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>();
389 extra_view_info->text =
390 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN);
391 extra_view_info->is_learn_more = false;
392 delegate.set_extra_view_info(std::move(extra_view_info));
393
394 ShowBubble(&delegate);
395
396 const views::View* const extra_view = bubble()->GetExtraView();
397 ASSERT_TRUE(extra_view);
398 EXPECT_EQ("Label", std::string(extra_view->GetClassName()));
399 EXPECT_EQ(l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN),
400 static_cast<const views::Label*>(extra_view)->GetText());
401 CloseBubble();
402 }
403
TEST_F(ToolbarActionsBarBubbleViewsTest,TestCreateExtraViewImageAndText)404 TEST_F(ToolbarActionsBarBubbleViewsTest, TestCreateExtraViewImageAndText) {
405 TestToolbarActionsBarBubbleDelegate delegate(HeadingString(), BodyString(),
406 ActionString());
407 std::unique_ptr<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>
408 extra_view_info =
409 std::make_unique<ToolbarActionsBarBubbleDelegate::ExtraViewInfo>();
410 extra_view_info->resource = &vector_icons::kBusinessIcon;
411 extra_view_info->text =
412 l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN);
413 extra_view_info->is_learn_more = false;
414 delegate.set_extra_view_info(std::move(extra_view_info));
415
416 ShowBubble(&delegate);
417
418 const views::View* const extra_view = bubble()->GetExtraView();
419 ASSERT_TRUE(extra_view);
420 EXPECT_STREQ("View", extra_view->GetClassName());
421 EXPECT_EQ(2u, extra_view->children().size());
422
423 for (const views::View* v : extra_view->children()) {
424 std::string class_name = v->GetClassName();
425 if (class_name == "Label") {
426 EXPECT_EQ(l10n_util::GetStringUTF16(IDS_EXTENSIONS_INSTALLED_BY_ADMIN),
427 static_cast<const views::Label*>(v)->GetText());
428 } else {
429 ASSERT_EQ("ImageView", class_name);
430 EXPECT_TRUE(gfx::test::AreImagesEqual(
431 gfx::Image(static_cast<const views::ImageView*>(v)->GetImage()),
432 gfx::Image(gfx::CreateVectorIcon(vector_icons::kBusinessIcon,
433 kIconSize, gfx::kChromeIconGrey))));
434 }
435 }
436
437 CloseBubble();
438 }
439