MacViews: Use Mac's "Constrained Window Button" style for Button::STYLE_BUTTON LabelB...
[chromium-blink-merge.git] / chrome / browser / ui / views / toolbar / browser_actions_container_browsertest.cc
blob05d3dbcd551bf8c66da5b9ce84f4c7ffb28548fc
1 // Copyright 2013 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.
5 #include "chrome/browser/ui/views/toolbar/browser_actions_container.h"
7 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
8 #include "chrome/browser/extensions/browser_action_test_util.h"
9 #include "chrome/browser/extensions/extension_toolbar_model.h"
10 #include "chrome/browser/ui/browser_window.h"
11 #include "chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h"
12 #include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
13 #include "chrome/browser/ui/views/frame/browser_view.h"
14 #include "chrome/browser/ui/views/toolbar/toolbar_action_view.h"
15 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
16 #include "extensions/browser/extension_prefs.h"
17 #include "extensions/common/extension.h"
18 #include "ui/base/dragdrop/drop_target_event.h"
19 #include "ui/base/dragdrop/os_exchange_data.h"
20 #include "ui/gfx/geometry/point.h"
21 #include "ui/views/view.h"
23 // TODO(devlin): Continue moving any tests that should be platform independent
24 // from this file to the crossplatform tests in
25 // chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc.
27 // Test that dragging browser actions works, and that dragging a browser action
28 // from the overflow menu results in it "popping" out (growing the container
29 // size by 1), rather than just reordering the extensions.
30 IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, DragBrowserActions) {
31 LoadExtensions();
33 // Sanity check: All extensions showing; order is A B C.
34 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
35 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
36 EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(0));
37 EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(1));
38 EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(2));
40 BrowserActionsContainer* container =
41 BrowserView::GetBrowserViewForBrowser(browser())
42 ->toolbar()->browser_actions();
44 // Simulate a drag and drop to the right.
45 ui::OSExchangeData drop_data;
46 // Drag extension A from index 0...
47 BrowserActionDragData browser_action_drag_data(extension_a()->id(), 0u);
48 browser_action_drag_data.Write(profile(), &drop_data);
49 ToolbarActionView* view = container->GetViewForId(extension_b()->id());
50 // ...to the right of extension B.
51 gfx::Point location(view->x() + view->width(), view->y());
52 ui::DropTargetEvent target_event(
53 drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
55 // Drag and drop.
56 container->OnDragUpdated(target_event);
57 container->OnPerformDrop(target_event);
59 // The order should now be B A C, since A was dragged to the right of B.
60 EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(0));
61 EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(1));
62 EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(2));
64 // This order should be reflected in the underlying model.
65 EXPECT_EQ(extension_b(), toolbar_model()->toolbar_items()[0].get());
66 EXPECT_EQ(extension_a(), toolbar_model()->toolbar_items()[1].get());
67 EXPECT_EQ(extension_c(), toolbar_model()->toolbar_items()[2].get());
69 // Simulate a drag and drop to the left.
70 ui::OSExchangeData drop_data2;
71 // Drag extension A from index 1...
72 BrowserActionDragData browser_action_drag_data2(extension_a()->id(), 1u);
73 browser_action_drag_data2.Write(profile(), &drop_data2);
74 // ...to the left of extension B (which is now at index 0).
75 location = gfx::Point(view->x(), view->y());
76 ui::DropTargetEvent target_event2(
77 drop_data2, location, location, ui::DragDropTypes::DRAG_MOVE);
79 // Drag and drop.
80 container->OnDragUpdated(target_event2);
81 container->OnPerformDrop(target_event2);
83 // Order should be restored to A B C.
84 EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(0));
85 EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(1));
86 EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(2));
88 // Shrink the size of the container so we have an overflow menu.
89 toolbar_model()->SetVisibleIconCount(2u);
90 EXPECT_EQ(2u, container->VisibleBrowserActions());
91 ASSERT_TRUE(container->chevron());
92 EXPECT_TRUE(container->chevron()->visible());
94 // Simulate a drag and drop from the overflow menu.
95 ui::OSExchangeData drop_data3;
96 // Drag extension C from index 2 (in the overflow menu)...
97 BrowserActionDragData browser_action_drag_data3(extension_c()->id(), 2u);
98 browser_action_drag_data3.Write(profile(), &drop_data3);
99 // ...to the left of extension B (which is back in index 1 on the main bar).
100 location = gfx::Point(view->x(), view->y());
101 ui::DropTargetEvent target_event3(
102 drop_data3, location, location, ui::DragDropTypes::DRAG_MOVE);
104 // Drag and drop.
105 container->OnDragUpdated(target_event3);
106 container->OnPerformDrop(target_event3);
108 // The order should have changed *and* the container should have grown to
109 // accommodate extension C. The new order should be A C B, and all three
110 // extensions should be visible, with no overflow menu.
111 EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(0));
112 EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(1));
113 EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(2));
114 EXPECT_EQ(3u, container->VisibleBrowserActions());
115 EXPECT_FALSE(container->chevron()->visible());
116 EXPECT_TRUE(toolbar_model()->all_icons_visible());
118 // TODO(devlin): Ideally, we'd also have tests for dragging from the legacy
119 // overflow menu (i.e., chevron) to the main bar, but this requires either
120 // having a fairly complicated interactive UI test or finding a good way to
121 // mock up the BrowserActionOverflowMenuController.
124 // Test that changes performed in one container affect containers in other
125 // windows so that it is consistent.
126 IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, MultipleWindows) {
127 LoadExtensions();
128 BrowserActionsContainer* first =
129 BrowserView::GetBrowserViewForBrowser(browser())->toolbar()->
130 browser_actions();
132 // Create a second browser.
133 Browser* second_browser = new Browser(
134 Browser::CreateParams(profile(), browser()->host_desktop_type()));
135 BrowserActionsContainer* second =
136 BrowserView::GetBrowserViewForBrowser(second_browser)->toolbar()->
137 browser_actions();
139 // Both containers should have the same order and visible actions, which
140 // is right now A B C.
141 EXPECT_EQ(3u, first->VisibleBrowserActions());
142 EXPECT_EQ(3u, second->VisibleBrowserActions());
143 EXPECT_EQ(extension_a()->id(), first->GetIdAt(0u));
144 EXPECT_EQ(extension_a()->id(), second->GetIdAt(0u));
145 EXPECT_EQ(extension_b()->id(), first->GetIdAt(1u));
146 EXPECT_EQ(extension_b()->id(), second->GetIdAt(1u));
147 EXPECT_EQ(extension_c()->id(), first->GetIdAt(2u));
148 EXPECT_EQ(extension_c()->id(), second->GetIdAt(2u));
150 // Simulate a drag and drop to the right.
151 ui::OSExchangeData drop_data;
152 // Drag extension A from index 0...
153 BrowserActionDragData browser_action_drag_data(extension_a()->id(), 0u);
154 browser_action_drag_data.Write(profile(), &drop_data);
155 ToolbarActionView* view = first->GetViewForId(extension_b()->id());
156 // ...to the right of extension B.
157 gfx::Point location(view->x() + view->width(), view->y());
158 ui::DropTargetEvent target_event(
159 drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
161 // Drag and drop.
162 first->OnDragUpdated(target_event);
163 first->OnPerformDrop(target_event);
165 // The new order, B A C, should be reflected in *both* containers, even
166 // though the drag only happened in the first one.
167 EXPECT_EQ(extension_b()->id(), first->GetIdAt(0u));
168 EXPECT_EQ(extension_b()->id(), second->GetIdAt(0u));
169 EXPECT_EQ(extension_a()->id(), first->GetIdAt(1u));
170 EXPECT_EQ(extension_a()->id(), second->GetIdAt(1u));
171 EXPECT_EQ(extension_c()->id(), first->GetIdAt(2u));
172 EXPECT_EQ(extension_c()->id(), second->GetIdAt(2u));
174 // Next, simulate a resize by shrinking the container.
175 first->OnResize(1, true);
176 // The first and second container should each have resized.
177 EXPECT_EQ(2u, first->VisibleBrowserActions());
178 EXPECT_EQ(2u, second->VisibleBrowserActions());
181 // Test that the BrowserActionsContainer responds correctly when the underlying
182 // model enters highlight mode, and that browser actions are undraggable in
183 // highlight mode. (Highlight mode itself it tested more thoroughly in the
184 // ExtensionToolbarModel browsertests).
185 IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, HighlightMode) {
186 LoadExtensions();
188 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
189 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
191 BrowserActionsContainer* container =
192 BrowserView::GetBrowserViewForBrowser(browser())
193 ->toolbar()->browser_actions();
195 // Currently, dragging should be enabled.
196 ToolbarActionView* action_view = container->GetToolbarActionViewAt(0);
197 ASSERT_TRUE(action_view);
198 gfx::Point point(action_view->x(), action_view->y());
199 EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
201 extensions::ExtensionIdList extension_ids;
202 extension_ids.push_back(extension_a()->id());
203 extension_ids.push_back(extension_b()->id());
204 toolbar_model()->HighlightExtensions(
205 extension_ids, extensions::ExtensionToolbarModel::HIGHLIGHT_WARNING);
207 // Only two browser actions should be visible.
208 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
209 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
211 // We shouldn't be able to drag in highlight mode.
212 action_view = container->GetToolbarActionViewAt(0);
213 EXPECT_FALSE(container->CanStartDragForView(action_view, point, point));
215 // We should go back to normal after leaving highlight mode.
216 toolbar_model()->StopHighlighting();
217 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
218 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
219 action_view = container->GetToolbarActionViewAt(0);
220 EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
223 // Test the behavior of the overflow container for Extension Actions.
224 class BrowserActionsContainerOverflowTest
225 : public BrowserActionsBarRedesignBrowserTest {
226 public:
227 BrowserActionsContainerOverflowTest() : main_bar_(nullptr),
228 overflow_bar_(nullptr) {
230 ~BrowserActionsContainerOverflowTest() override {}
232 protected:
233 // Returns true if the order of the ToolbarActionViews in |main_bar_|
234 // and |overflow_bar_| match.
235 bool ViewOrdersMatch();
237 // Returns Success if the visible count matches |expected_visible|. This means
238 // that the number of visible browser actions in |main_bar_| is
239 // |expected_visible| and shows the first icons, and that the overflow bar
240 // shows all (and only) the remainder.
241 testing::AssertionResult VerifyVisibleCount(size_t expected_visible)
242 WARN_UNUSED_RESULT;
244 // Accessors.
245 BrowserActionsContainer* main_bar() { return main_bar_; }
246 BrowserActionsContainer* overflow_bar() { return overflow_bar_; }
248 private:
249 void SetUpOnMainThread() override;
250 void TearDownOnMainThread() override;
252 // The main BrowserActionsContainer (owned by the browser view).
253 BrowserActionsContainer* main_bar_;
255 // A parent view for the overflow menu.
256 scoped_ptr<views::View> overflow_parent_;
258 // The overflow BrowserActionsContainer. We manufacture this so that we don't
259 // have to open the wrench menu.
260 // Owned by the |overflow_parent_|.
261 BrowserActionsContainer* overflow_bar_;
263 DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainerOverflowTest);
266 void BrowserActionsContainerOverflowTest::SetUpOnMainThread() {
267 BrowserActionsBarBrowserTest::SetUpOnMainThread();
268 main_bar_ = BrowserView::GetBrowserViewForBrowser(browser())
269 ->toolbar()->browser_actions();
270 overflow_parent_.reset(new views::View());
271 overflow_parent_->set_owned_by_client();
272 overflow_bar_ = new BrowserActionsContainer(browser(), main_bar_);
273 overflow_parent_->AddChildView(overflow_bar_);
276 void BrowserActionsContainerOverflowTest::TearDownOnMainThread() {
277 overflow_parent_.reset();
278 BrowserActionsBarBrowserTest::TearDownOnMainThread();
281 bool BrowserActionsContainerOverflowTest::ViewOrdersMatch() {
282 if (main_bar_->num_toolbar_actions() !=
283 overflow_bar_->num_toolbar_actions())
284 return false;
285 for (size_t i = 0; i < main_bar_->num_toolbar_actions(); ++i) {
286 if (main_bar_->GetIdAt(i) != overflow_bar_->GetIdAt(i))
287 return false;
289 return true;
292 testing::AssertionResult
293 BrowserActionsContainerOverflowTest::VerifyVisibleCount(
294 size_t expected_visible) {
295 // Views order should always match (as it is based directly off the model).
296 if (!ViewOrdersMatch())
297 return testing::AssertionFailure() << "View orders don't match";
299 // Loop through and check each browser action for proper visibility (which
300 // implicitly also guarantees that the proper number are visible).
301 for (size_t i = 0; i < overflow_bar_->num_toolbar_actions(); ++i) {
302 bool visible = i < expected_visible;
303 if (main_bar_->GetToolbarActionViewAt(i)->visible() != visible) {
304 return testing::AssertionFailure() << "Index " << i <<
305 " has improper visibility in main: " << !visible;
307 if (overflow_bar_->GetToolbarActionViewAt(i)->visible() == visible) {
308 return testing::AssertionFailure() << "Index " << i <<
309 " has improper visibility in overflow: " << visible;
312 return testing::AssertionSuccess();
315 // Test the basic functionality of the BrowserActionsContainer in overflow mode.
316 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerOverflowTest,
317 TestBasicActionOverflow) {
318 LoadExtensions();
320 // Since the overflow bar isn't attached to a view, we have to kick it in
321 // order to retrigger layout each time we change the number of icons in the
322 // bar.
323 overflow_bar()->Layout();
325 // All actions are showing, and are in the installation order.
326 EXPECT_TRUE(toolbar_model()->all_icons_visible());
327 EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
328 ASSERT_EQ(3u, main_bar()->num_toolbar_actions());
329 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
330 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(1u));
331 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
332 EXPECT_TRUE(VerifyVisibleCount(3u));
334 // Reduce the visible count to 2. Order should be unchanged (A B C), but
335 // only A and B should be visible on the main bar.
336 toolbar_model()->SetVisibleIconCount(2u);
337 overflow_bar()->Layout(); // Kick.
338 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
339 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(1u));
340 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
341 EXPECT_TRUE(VerifyVisibleCount(2u));
343 // Move extension C to the first position. Order should now be C A B, with
344 // C and A visible in the main bar.
345 toolbar_model()->MoveExtensionIcon(extension_c()->id(), 0);
346 overflow_bar()->Layout(); // Kick.
347 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(0u));
348 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(1u));
349 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(2u));
350 EXPECT_TRUE(VerifyVisibleCount(2u));
352 // Hide action A. This results in it being sent to overflow, and reducing the
353 // visible size to 1, so the order should be C A B, with only C visible in the
354 // main bar.
355 extensions::ExtensionActionAPI::Get(profile())->SetBrowserActionVisibility(
356 extension_a()->id(),
357 false);
358 overflow_bar()->Layout(); // Kick.
359 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(0u));
360 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(1u));
361 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(2u));
362 EXPECT_TRUE(VerifyVisibleCount(1u));
365 // Test drag and drop between the overflow container and the main container.
366 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerOverflowTest,
367 TestOverflowDragging) {
368 LoadExtensions();
370 // Start with one extension in overflow.
371 toolbar_model()->SetVisibleIconCount(2u);
372 overflow_bar()->Layout();
374 // Verify starting state is A B [C].
375 ASSERT_EQ(3u, main_bar()->num_toolbar_actions());
376 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
377 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(1u));
378 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
379 EXPECT_TRUE(VerifyVisibleCount(2u));
381 // Drag extension A (on the main bar) to the left of extension C (in
382 // overflow).
383 ui::OSExchangeData drop_data;
384 BrowserActionDragData browser_action_drag_data(extension_a()->id(), 0u);
385 browser_action_drag_data.Write(profile(), &drop_data);
386 ToolbarActionView* view = overflow_bar()->GetViewForId(extension_c()->id());
387 gfx::Point location(view->x(), view->y());
388 ui::DropTargetEvent target_event(
389 drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
391 overflow_bar()->OnDragUpdated(target_event);
392 overflow_bar()->OnPerformDrop(target_event);
393 overflow_bar()->Layout();
395 // Order should now be B [A C].
396 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(0u));
397 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(1u));
398 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
399 EXPECT_TRUE(VerifyVisibleCount(1u));
401 // Drag extension A back from overflow to the main bar.
402 ui::OSExchangeData drop_data2;
403 BrowserActionDragData browser_action_drag_data2(extension_a()->id(), 1u);
404 browser_action_drag_data2.Write(profile(), &drop_data2);
405 view = main_bar()->GetViewForId(extension_b()->id());
406 location = gfx::Point(view->x(), view->y());
407 ui::DropTargetEvent target_event2(
408 drop_data2, location, location, ui::DragDropTypes::DRAG_MOVE);
410 main_bar()->OnDragUpdated(target_event2);
411 main_bar()->OnPerformDrop(target_event2);
413 // Order should be A B [C] again.
414 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
415 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(1u));
416 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
417 EXPECT_TRUE(VerifyVisibleCount(2u));
419 // Drag extension C from overflow to the main bar (before extension B).
420 ui::OSExchangeData drop_data3;
421 BrowserActionDragData browser_action_drag_data3(extension_c()->id(), 2u);
422 browser_action_drag_data3.Write(profile(), &drop_data3);
423 location = gfx::Point(view->x(), view->y());
424 ui::DropTargetEvent target_event3(
425 drop_data3, location, location, ui::DragDropTypes::DRAG_MOVE);
427 main_bar()->OnDragUpdated(target_event3);
428 main_bar()->OnPerformDrop(target_event3);
430 // Order should be A C B, and there should be no extensions in overflow.
431 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
432 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(1u));
433 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(2u));
434 EXPECT_TRUE(VerifyVisibleCount(3u));