Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / views / toolbar / browser_actions_container_browsertest.cc
blob9988a54daf6fcf72c93353e9b5c6f967397aec32
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/ui/browser_window.h"
10 #include "chrome/browser/ui/toolbar/browser_actions_bar_browsertest.h"
11 #include "chrome/browser/ui/toolbar/toolbar_actions_model.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/browser/extension_registry.h"
18 #include "extensions/common/extension.h"
19 #include "ui/base/dragdrop/drop_target_event.h"
20 #include "ui/base/dragdrop/os_exchange_data.h"
21 #include "ui/gfx/geometry/point.h"
22 #include "ui/views/view.h"
24 // TODO(devlin): Continue moving any tests that should be platform independent
25 // from this file to the crossplatform tests in
26 // chrome/browser/ui/toolbar/browser_actions_bar_browsertest.cc.
28 // Test that dragging browser actions works, and that dragging a browser action
29 // from the overflow menu results in it "popping" out (growing the container
30 // size by 1), rather than just reordering the extensions.
31 IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, DragBrowserActions) {
32 LoadExtensions();
34 // Sanity check: All extensions showing; order is A B C.
35 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
36 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
37 EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(0));
38 EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(1));
39 EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(2));
41 BrowserActionsContainer* container =
42 BrowserView::GetBrowserViewForBrowser(browser())
43 ->toolbar()->browser_actions();
45 // Simulate a drag and drop to the right.
46 ui::OSExchangeData drop_data;
47 // Drag extension A from index 0...
48 BrowserActionDragData browser_action_drag_data(extension_a()->id(), 0u);
49 browser_action_drag_data.Write(profile(), &drop_data);
50 ToolbarActionView* view = container->GetViewForId(extension_b()->id());
51 // ...to the right of extension B.
52 gfx::Point location(view->x() + view->width(), view->y());
53 ui::DropTargetEvent target_event(
54 drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
56 // Drag and drop.
57 container->OnDragUpdated(target_event);
58 container->OnPerformDrop(target_event);
60 // The order should now be B A C, since A was dragged to the right of B.
61 EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(0));
62 EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(1));
63 EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(2));
65 const extensions::ExtensionSet& extension_set =
66 extensions::ExtensionRegistry::Get(profile())->enabled_extensions();
67 const std::vector<ToolbarActionsModel::ToolbarItem>& toolbar_items =
68 toolbar_model()->toolbar_items();
70 // This order should be reflected in the underlying model.
71 EXPECT_EQ(extension_b(), extension_set.GetByID(toolbar_items[0].id));
72 EXPECT_EQ(extension_a(), extension_set.GetByID(toolbar_items[1].id));
73 EXPECT_EQ(extension_c(), extension_set.GetByID(toolbar_items[2].id));
75 // Simulate a drag and drop to the left.
76 ui::OSExchangeData drop_data2;
77 // Drag extension A from index 1...
78 BrowserActionDragData browser_action_drag_data2(extension_a()->id(), 1u);
79 browser_action_drag_data2.Write(profile(), &drop_data2);
80 // ...to the left of extension B (which is now at index 0).
81 location = gfx::Point(view->x(), view->y());
82 ui::DropTargetEvent target_event2(
83 drop_data2, location, location, ui::DragDropTypes::DRAG_MOVE);
85 // Drag and drop.
86 container->OnDragUpdated(target_event2);
87 container->OnPerformDrop(target_event2);
89 // Order should be restored to A B C.
90 EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(0));
91 EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(1));
92 EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(2));
94 // Shrink the size of the container so we have an overflow menu.
95 toolbar_model()->SetVisibleIconCount(2u);
96 EXPECT_EQ(2u, container->VisibleBrowserActions());
97 ASSERT_TRUE(container->chevron());
98 EXPECT_TRUE(container->chevron()->visible());
100 // Simulate a drag and drop from the overflow menu.
101 ui::OSExchangeData drop_data3;
102 // Drag extension C from index 2 (in the overflow menu)...
103 BrowserActionDragData browser_action_drag_data3(extension_c()->id(), 2u);
104 browser_action_drag_data3.Write(profile(), &drop_data3);
105 // ...to the left of extension B (which is back in index 1 on the main bar).
106 location = gfx::Point(view->x(), view->y());
107 ui::DropTargetEvent target_event3(
108 drop_data3, location, location, ui::DragDropTypes::DRAG_MOVE);
110 // Drag and drop.
111 container->OnDragUpdated(target_event3);
112 container->OnPerformDrop(target_event3);
114 // The order should have changed *and* the container should have grown to
115 // accommodate extension C. The new order should be A C B, and all three
116 // extensions should be visible, with no overflow menu.
117 EXPECT_EQ(extension_a()->id(), browser_actions_bar()->GetExtensionId(0));
118 EXPECT_EQ(extension_c()->id(), browser_actions_bar()->GetExtensionId(1));
119 EXPECT_EQ(extension_b()->id(), browser_actions_bar()->GetExtensionId(2));
120 EXPECT_EQ(3u, container->VisibleBrowserActions());
121 EXPECT_FALSE(container->chevron()->visible());
122 EXPECT_TRUE(toolbar_model()->all_icons_visible());
124 // TODO(devlin): Ideally, we'd also have tests for dragging from the legacy
125 // overflow menu (i.e., chevron) to the main bar, but this requires either
126 // having a fairly complicated interactive UI test or finding a good way to
127 // mock up the BrowserActionOverflowMenuController.
130 // Test that changes performed in one container affect containers in other
131 // windows so that it is consistent.
132 IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, MultipleWindows) {
133 LoadExtensions();
134 BrowserActionsContainer* first =
135 BrowserView::GetBrowserViewForBrowser(browser())->toolbar()->
136 browser_actions();
138 // Create a second browser.
139 Browser* second_browser = new Browser(
140 Browser::CreateParams(profile(), browser()->host_desktop_type()));
141 BrowserActionsContainer* second =
142 BrowserView::GetBrowserViewForBrowser(second_browser)->toolbar()->
143 browser_actions();
145 // Both containers should have the same order and visible actions, which
146 // is right now A B C.
147 EXPECT_EQ(3u, first->VisibleBrowserActions());
148 EXPECT_EQ(3u, second->VisibleBrowserActions());
149 EXPECT_EQ(extension_a()->id(), first->GetIdAt(0u));
150 EXPECT_EQ(extension_a()->id(), second->GetIdAt(0u));
151 EXPECT_EQ(extension_b()->id(), first->GetIdAt(1u));
152 EXPECT_EQ(extension_b()->id(), second->GetIdAt(1u));
153 EXPECT_EQ(extension_c()->id(), first->GetIdAt(2u));
154 EXPECT_EQ(extension_c()->id(), second->GetIdAt(2u));
156 // Simulate a drag and drop to the right.
157 ui::OSExchangeData drop_data;
158 // Drag extension A from index 0...
159 BrowserActionDragData browser_action_drag_data(extension_a()->id(), 0u);
160 browser_action_drag_data.Write(profile(), &drop_data);
161 ToolbarActionView* view = first->GetViewForId(extension_b()->id());
162 // ...to the right of extension B.
163 gfx::Point location(view->x() + view->width(), view->y());
164 ui::DropTargetEvent target_event(
165 drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
167 // Drag and drop.
168 first->OnDragUpdated(target_event);
169 first->OnPerformDrop(target_event);
171 // The new order, B A C, should be reflected in *both* containers, even
172 // though the drag only happened in the first one.
173 EXPECT_EQ(extension_b()->id(), first->GetIdAt(0u));
174 EXPECT_EQ(extension_b()->id(), second->GetIdAt(0u));
175 EXPECT_EQ(extension_a()->id(), first->GetIdAt(1u));
176 EXPECT_EQ(extension_a()->id(), second->GetIdAt(1u));
177 EXPECT_EQ(extension_c()->id(), first->GetIdAt(2u));
178 EXPECT_EQ(extension_c()->id(), second->GetIdAt(2u));
180 // Next, simulate a resize by shrinking the container.
181 first->OnResize(1, true);
182 // The first and second container should each have resized.
183 EXPECT_EQ(2u, first->VisibleBrowserActions());
184 EXPECT_EQ(2u, second->VisibleBrowserActions());
187 // Test that the BrowserActionsContainer responds correctly when the underlying
188 // model enters highlight mode, and that browser actions are undraggable in
189 // highlight mode. (Highlight mode itself it tested more thoroughly in the
190 // ToolbarActionsModel browsertests).
191 IN_PROC_BROWSER_TEST_F(BrowserActionsBarBrowserTest, HighlightMode) {
192 LoadExtensions();
194 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
195 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
197 BrowserActionsContainer* container =
198 BrowserView::GetBrowserViewForBrowser(browser())
199 ->toolbar()->browser_actions();
201 // Currently, dragging should be enabled.
202 ToolbarActionView* action_view = container->GetToolbarActionViewAt(0);
203 ASSERT_TRUE(action_view);
204 gfx::Point point(action_view->x(), action_view->y());
205 EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
207 std::vector<std::string> action_ids;
208 action_ids.push_back(extension_a()->id());
209 action_ids.push_back(extension_b()->id());
210 toolbar_model()->HighlightActions(action_ids,
211 ToolbarActionsModel::HIGHLIGHT_WARNING);
213 // Only two browser actions should be visible.
214 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
215 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
217 // We shouldn't be able to drag in highlight mode.
218 action_view = container->GetToolbarActionViewAt(0);
219 EXPECT_FALSE(container->CanStartDragForView(action_view, point, point));
221 // We should go back to normal after leaving highlight mode.
222 toolbar_model()->StopHighlighting();
223 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
224 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
225 action_view = container->GetToolbarActionViewAt(0);
226 EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
229 // Test the behavior of the overflow container for Extension Actions.
230 class BrowserActionsContainerOverflowTest
231 : public BrowserActionsBarRedesignBrowserTest {
232 public:
233 BrowserActionsContainerOverflowTest() : main_bar_(nullptr),
234 overflow_bar_(nullptr) {
236 ~BrowserActionsContainerOverflowTest() override {}
238 protected:
239 // Returns true if the order of the ToolbarActionViews in |main_bar_|
240 // and |overflow_bar_| match.
241 bool ViewOrdersMatch();
243 // Returns Success if the visible count matches |expected_visible|. This means
244 // that the number of visible browser actions in |main_bar_| is
245 // |expected_visible| and shows the first icons, and that the overflow bar
246 // shows all (and only) the remainder.
247 testing::AssertionResult VerifyVisibleCount(size_t expected_visible)
248 WARN_UNUSED_RESULT;
250 // Accessors.
251 BrowserActionsContainer* main_bar() { return main_bar_; }
252 BrowserActionsContainer* overflow_bar() { return overflow_bar_; }
254 private:
255 void SetUpOnMainThread() override;
256 void TearDownOnMainThread() override;
258 // The main BrowserActionsContainer (owned by the browser view).
259 BrowserActionsContainer* main_bar_;
261 // A parent view for the overflow menu.
262 scoped_ptr<views::View> overflow_parent_;
264 // The overflow BrowserActionsContainer. We manufacture this so that we don't
265 // have to open the wrench menu.
266 // Owned by the |overflow_parent_|.
267 BrowserActionsContainer* overflow_bar_;
269 DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainerOverflowTest);
272 void BrowserActionsContainerOverflowTest::SetUpOnMainThread() {
273 BrowserActionsBarBrowserTest::SetUpOnMainThread();
274 main_bar_ = BrowserView::GetBrowserViewForBrowser(browser())
275 ->toolbar()->browser_actions();
276 overflow_parent_.reset(new views::View());
277 overflow_parent_->set_owned_by_client();
278 overflow_bar_ = new BrowserActionsContainer(browser(), main_bar_);
279 overflow_parent_->AddChildView(overflow_bar_);
282 void BrowserActionsContainerOverflowTest::TearDownOnMainThread() {
283 overflow_parent_.reset();
284 BrowserActionsBarBrowserTest::TearDownOnMainThread();
287 bool BrowserActionsContainerOverflowTest::ViewOrdersMatch() {
288 if (main_bar_->num_toolbar_actions() !=
289 overflow_bar_->num_toolbar_actions())
290 return false;
291 for (size_t i = 0; i < main_bar_->num_toolbar_actions(); ++i) {
292 if (main_bar_->GetIdAt(i) != overflow_bar_->GetIdAt(i))
293 return false;
295 return true;
298 testing::AssertionResult
299 BrowserActionsContainerOverflowTest::VerifyVisibleCount(
300 size_t expected_visible) {
301 // Views order should always match (as it is based directly off the model).
302 if (!ViewOrdersMatch())
303 return testing::AssertionFailure() << "View orders don't match";
305 // Loop through and check each browser action for proper visibility (which
306 // implicitly also guarantees that the proper number are visible).
307 for (size_t i = 0; i < overflow_bar_->num_toolbar_actions(); ++i) {
308 bool visible = i < expected_visible;
309 if (main_bar_->GetToolbarActionViewAt(i)->visible() != visible) {
310 return testing::AssertionFailure() << "Index " << i <<
311 " has improper visibility in main: " << !visible;
313 if (overflow_bar_->GetToolbarActionViewAt(i)->visible() == visible) {
314 return testing::AssertionFailure() << "Index " << i <<
315 " has improper visibility in overflow: " << visible;
318 return testing::AssertionSuccess();
321 // Test the basic functionality of the BrowserActionsContainer in overflow mode.
322 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerOverflowTest,
323 TestBasicActionOverflow) {
324 LoadExtensions();
326 // Since the overflow bar isn't attached to a view, we have to kick it in
327 // order to retrigger layout each time we change the number of icons in the
328 // bar.
329 overflow_bar()->Layout();
331 // All actions are showing, and are in the installation order.
332 EXPECT_TRUE(toolbar_model()->all_icons_visible());
333 EXPECT_EQ(3u, toolbar_model()->visible_icon_count());
334 ASSERT_EQ(3u, main_bar()->num_toolbar_actions());
335 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
336 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(1u));
337 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
338 EXPECT_TRUE(VerifyVisibleCount(3u));
340 // Reduce the visible count to 2. Order should be unchanged (A B C), but
341 // only A and B should be visible on the main bar.
342 toolbar_model()->SetVisibleIconCount(2u);
343 overflow_bar()->Layout(); // Kick.
344 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
345 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(1u));
346 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
347 EXPECT_TRUE(VerifyVisibleCount(2u));
349 // Move extension C to the first position. Order should now be C A B, with
350 // C and A visible in the main bar.
351 toolbar_model()->MoveActionIcon(extension_c()->id(), 0);
352 overflow_bar()->Layout(); // Kick.
353 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(0u));
354 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(1u));
355 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(2u));
356 EXPECT_TRUE(VerifyVisibleCount(2u));
358 // Hide action A. This results in it being sent to overflow, and reducing the
359 // visible size to 1, so the order should be C A B, with only C visible in the
360 // main bar.
361 extensions::ExtensionActionAPI::Get(profile())->SetBrowserActionVisibility(
362 extension_a()->id(),
363 false);
364 overflow_bar()->Layout(); // Kick.
365 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(0u));
366 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(1u));
367 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(2u));
368 EXPECT_TRUE(VerifyVisibleCount(1u));
371 // Test drag and drop between the overflow container and the main container.
372 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerOverflowTest,
373 TestOverflowDragging) {
374 LoadExtensions();
376 // Start with one extension in overflow.
377 toolbar_model()->SetVisibleIconCount(2u);
378 overflow_bar()->Layout();
380 // Verify starting state is A B [C].
381 ASSERT_EQ(3u, main_bar()->num_toolbar_actions());
382 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
383 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(1u));
384 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
385 EXPECT_TRUE(VerifyVisibleCount(2u));
387 // Drag extension A (on the main bar) to the left of extension C (in
388 // overflow).
389 ui::OSExchangeData drop_data;
390 BrowserActionDragData browser_action_drag_data(extension_a()->id(), 0u);
391 browser_action_drag_data.Write(profile(), &drop_data);
392 ToolbarActionView* view = overflow_bar()->GetViewForId(extension_c()->id());
393 gfx::Point location(view->x(), view->y());
394 ui::DropTargetEvent target_event(
395 drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
397 overflow_bar()->OnDragUpdated(target_event);
398 overflow_bar()->OnPerformDrop(target_event);
399 overflow_bar()->Layout();
401 // Order should now be B [A C].
402 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(0u));
403 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(1u));
404 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
405 EXPECT_TRUE(VerifyVisibleCount(1u));
407 // Drag extension A back from overflow to the main bar.
408 ui::OSExchangeData drop_data2;
409 BrowserActionDragData browser_action_drag_data2(extension_a()->id(), 1u);
410 browser_action_drag_data2.Write(profile(), &drop_data2);
411 view = main_bar()->GetViewForId(extension_b()->id());
412 location = gfx::Point(view->x(), view->y());
413 ui::DropTargetEvent target_event2(
414 drop_data2, location, location, ui::DragDropTypes::DRAG_MOVE);
416 main_bar()->OnDragUpdated(target_event2);
417 main_bar()->OnPerformDrop(target_event2);
419 // Order should be A B [C] again.
420 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
421 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(1u));
422 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(2u));
423 EXPECT_TRUE(VerifyVisibleCount(2u));
425 // Drag extension C from overflow to the main bar (before extension B).
426 ui::OSExchangeData drop_data3;
427 BrowserActionDragData browser_action_drag_data3(extension_c()->id(), 2u);
428 browser_action_drag_data3.Write(profile(), &drop_data3);
429 location = gfx::Point(view->x(), view->y());
430 ui::DropTargetEvent target_event3(
431 drop_data3, location, location, ui::DragDropTypes::DRAG_MOVE);
433 main_bar()->OnDragUpdated(target_event3);
434 main_bar()->OnPerformDrop(target_event3);
436 // Order should be A C B, and there should be no extensions in overflow.
437 EXPECT_EQ(extension_a()->id(), main_bar()->GetIdAt(0u));
438 EXPECT_EQ(extension_c()->id(), main_bar()->GetIdAt(1u));
439 EXPECT_EQ(extension_b()->id(), main_bar()->GetIdAt(2u));
440 EXPECT_TRUE(VerifyVisibleCount(3u));