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/chrome_notification_types.h"
8 #include "chrome/browser/extensions/api/extension_action/extension_action_api.h"
9 #include "chrome/browser/extensions/browser_action_test_util.h"
10 #include "chrome/browser/extensions/extension_browsertest.h"
11 #include "chrome/browser/extensions/extension_toolbar_model.h"
12 #include "chrome/browser/ui/browser_window.h"
13 #include "chrome/browser/ui/browser_window_testing_views.h"
14 #include "chrome/browser/ui/views/extensions/browser_action_drag_data.h"
15 #include "chrome/browser/ui/views/frame/browser_view.h"
16 #include "chrome/browser/ui/views/toolbar/browser_action_view.h"
17 #include "chrome/browser/ui/views/toolbar/toolbar_view.h"
18 #include "content/public/test/test_utils.h"
19 #include "extensions/browser/extension_prefs.h"
20 #include "extensions/common/extension.h"
21 #include "ui/base/dragdrop/drop_target_event.h"
22 #include "ui/base/dragdrop/os_exchange_data.h"
23 #include "ui/gfx/geometry/point.h"
24 #include "ui/views/view.h"
26 using extensions::Extension;
28 class BrowserActionsContainerTest : public ExtensionBrowserTest {
30 BrowserActionsContainerTest() {
32 virtual ~BrowserActionsContainerTest() {}
34 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE {
35 BrowserActionsContainer::disable_animations_during_testing_ = true;
36 ExtensionBrowserTest::SetUpCommandLine(command_line);
39 virtual void SetUpOnMainThread() OVERRIDE {
40 ExtensionBrowserTest::SetUpOnMainThread();
41 browser_actions_bar_.reset(new BrowserActionTestUtil(browser()));
44 virtual void TearDownOnMainThread() OVERRIDE {
45 BrowserActionsContainer::disable_animations_during_testing_ = false;
48 BrowserActionTestUtil* browser_actions_bar() {
49 return browser_actions_bar_.get();
53 scoped_ptr<BrowserActionTestUtil> browser_actions_bar_;
56 // Test the basic functionality.
57 // http://crbug.com/120770
59 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, DISABLED_Basic) {
61 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Basic) {
63 // Load an extension with no browser action.
64 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
65 .AppendASCII("browser_action")
66 .AppendASCII("none")));
67 // This extension should not be in the model (has no browser action).
68 EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions());
70 // Load an extension with a browser action.
71 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
72 .AppendASCII("browser_action")
73 .AppendASCII("basics")));
74 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions());
75 EXPECT_TRUE(browser_actions_bar()->HasIcon(0));
78 // Unload the extension.
79 std::string id = browser_actions_bar()->GetExtensionId(0);
81 EXPECT_EQ(0, browser_actions_bar()->NumberOfBrowserActions());
84 // Test moving various browser actions. This is not to check the logic of the
85 // move (that's in the toolbar model tests), but just to check our ui.
86 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest,
88 base::FilePath data_dir =
89 test_data_dir_.AppendASCII("api_test").AppendASCII("browser_action");
90 // Load three extensions with browser actions.
91 const extensions::Extension* extension_a =
92 LoadExtension(data_dir.AppendASCII("basics"));
93 ASSERT_TRUE(extension_a);
94 const extensions::Extension* extension_b =
95 LoadExtension(data_dir.AppendASCII("add_popup"));
96 ASSERT_TRUE(extension_b);
97 const extensions::Extension* extension_c =
98 LoadExtension(data_dir.AppendASCII("remove_popup"));
99 ASSERT_TRUE(extension_c);
101 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
102 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
104 extensions::ExtensionToolbarModel* model =
105 extensions::ExtensionToolbarModel::Get(profile());
108 // Order is now A B C.
109 EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(0));
110 EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(1));
111 EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(2));
113 // Move C to first position. Order is C A B.
114 model->MoveExtensionIcon(extension_c, 0);
115 EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(0));
116 EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(1));
117 EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(2));
119 // Move B to third position. Order is still C A B.
120 model->MoveExtensionIcon(extension_b, 2);
121 EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(0));
122 EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(1));
123 EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(2));
125 // Move B to middle position. Order is C B A.
126 model->MoveExtensionIcon(extension_b, 1);
127 EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(0));
128 EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(1));
129 EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(2));
132 // Test that dragging browser actions works, and that dragging a browser action
133 // from the overflow menu results in it "popping" out (growing the container
134 // size by 1), rather than just reordering the extensions.
135 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, DragBrowserActions) {
136 base::FilePath data_dir =
137 test_data_dir_.AppendASCII("api_test").AppendASCII("browser_action");
138 // Load three extensions with browser actions.
139 const extensions::Extension* extension_a =
140 LoadExtension(data_dir.AppendASCII("basics"));
141 ASSERT_TRUE(extension_a);
142 const extensions::Extension* extension_b =
143 LoadExtension(data_dir.AppendASCII("add_popup"));
144 ASSERT_TRUE(extension_b);
145 const extensions::Extension* extension_c =
146 LoadExtension(data_dir.AppendASCII("remove_popup"));
147 ASSERT_TRUE(extension_c);
149 // Sanity check: All extensions showing; order is A B C.
150 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
151 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
152 EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(0));
153 EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(1));
154 EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(2));
156 BrowserActionsContainer* container =
157 BrowserView::GetBrowserViewForBrowser(browser())
158 ->toolbar()->browser_actions();
160 // Simulate a drag and drop to the right.
161 ui::OSExchangeData drop_data;
162 // Drag extension A from index 0...
163 BrowserActionDragData browser_action_drag_data(extension_a->id(), 0u);
164 browser_action_drag_data.Write(profile(), &drop_data);
165 BrowserActionView* view = container->GetViewForExtension(extension_b);
166 // ...to the right of extension B.
167 gfx::Point location(view->x() + view->width(), view->y());
168 ui::DropTargetEvent target_event(
169 drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
172 container->OnDragUpdated(target_event);
173 container->OnPerformDrop(target_event);
175 // The order should now be B A C, since A was dragged to the right of B.
176 EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(0));
177 EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(1));
178 EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(2));
180 // This order should be reflected in the underlying model.
181 extensions::ExtensionToolbarModel* model =
182 extensions::ExtensionToolbarModel::Get(profile());
183 EXPECT_EQ(extension_b, model->toolbar_items()[0].get());
184 EXPECT_EQ(extension_a, model->toolbar_items()[1].get());
185 EXPECT_EQ(extension_c, model->toolbar_items()[2].get());
187 // Simulate a drag and drop to the left.
188 ui::OSExchangeData drop_data2;
189 // Drag extension A from index 1...
190 BrowserActionDragData browser_action_drag_data2(extension_a->id(), 1u);
191 browser_action_drag_data2.Write(profile(), &drop_data2);
192 // ...to the left of extension B (which is now at index 0).
193 location = gfx::Point(view->x(), view->y());
194 ui::DropTargetEvent target_event2(
195 drop_data2, location, location, ui::DragDropTypes::DRAG_MOVE);
198 container->OnDragUpdated(target_event2);
199 container->OnPerformDrop(target_event2);
201 // Order should be restored to A B C.
202 EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(0));
203 EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(1));
204 EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(2));
206 // Shrink the size of the container so we have an overflow menu.
207 model->SetVisibleIconCountForTest(2u);
208 EXPECT_EQ(2u, container->VisibleBrowserActions());
209 ASSERT_TRUE(container->chevron());
210 EXPECT_TRUE(container->chevron()->visible());
212 // Simulate a drag and drop from the overflow menu.
213 ui::OSExchangeData drop_data3;
214 // Drag extension C from index 2 (in the overflow menu)...
215 BrowserActionDragData browser_action_drag_data3(extension_c->id(), 2u);
216 browser_action_drag_data3.Write(profile(), &drop_data3);
217 // ...to the left of extension B (which is back in index 1 on the main bar).
218 location = gfx::Point(view->x(), view->y());
219 ui::DropTargetEvent target_event3(
220 drop_data3, location, location, ui::DragDropTypes::DRAG_MOVE);
223 container->OnDragUpdated(target_event3);
224 container->OnPerformDrop(target_event3);
226 // The order should have changed *and* the container should have grown to
227 // accommodate extension C. The new order should be A C B, and all three
228 // extensions should be visible, with no overflow menu.
229 EXPECT_EQ(extension_a->id(), browser_actions_bar()->GetExtensionId(0));
230 EXPECT_EQ(extension_c->id(), browser_actions_bar()->GetExtensionId(1));
231 EXPECT_EQ(extension_b->id(), browser_actions_bar()->GetExtensionId(2));
232 EXPECT_EQ(3u, container->VisibleBrowserActions());
233 EXPECT_FALSE(container->chevron()->visible());
234 EXPECT_EQ(-1, model->GetVisibleIconCount());
236 // TODO(devlin): Ideally, we'd also have tests for dragging from the legacy
237 // overflow menu (i.e., chevron) to the main bar, but this requires either
238 // having a fairly complicated interactive UI test or finding a good way to
239 // mock up the BrowserActionOverflowMenuController.
242 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, Visibility) {
243 // Load extension A (contains browser action).
244 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
245 .AppendASCII("browser_action")
246 .AppendASCII("basics")));
247 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions());
248 EXPECT_TRUE(browser_actions_bar()->HasIcon(0));
249 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
250 std::string idA = browser_actions_bar()->GetExtensionId(0);
252 // Load extension B (contains browser action).
253 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
254 .AppendASCII("browser_action")
255 .AppendASCII("add_popup")));
256 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
257 EXPECT_TRUE(browser_actions_bar()->HasIcon(0));
258 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
259 std::string idB = browser_actions_bar()->GetExtensionId(1);
263 // Load extension C (contains browser action).
264 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
265 .AppendASCII("browser_action")
266 .AppendASCII("remove_popup")));
267 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
268 EXPECT_TRUE(browser_actions_bar()->HasIcon(2));
269 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
270 std::string idC = browser_actions_bar()->GetExtensionId(2);
272 // Change container to show only one action, rest in overflow: A, [B, C].
273 browser_actions_bar()->SetIconVisibilityCount(1);
274 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
276 // Disable extension A (should disappear). State becomes: B [C].
277 DisableExtension(idA);
278 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
279 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
280 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0));
282 // Enable A again. A should get its spot in the same location and the bar
283 // should not grow (chevron is showing). For details: http://crbug.com/35349.
284 // State becomes: A, [B, C].
285 EnableExtension(idA);
286 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
287 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
288 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
290 // Disable C (in overflow). State becomes: A, [B].
291 DisableExtension(idC);
292 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
293 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
294 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
296 // Enable C again. State becomes: A, [B, C].
297 EnableExtension(idC);
298 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
299 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
300 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
302 // Now we have 3 extensions. Make sure they are all visible. State: A, B, C.
303 browser_actions_bar()->SetIconVisibilityCount(3);
304 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
306 // Disable extension A (should disappear). State becomes: B, C.
307 DisableExtension(idA);
308 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
309 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
310 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0));
312 // Disable extension B (should disappear). State becomes: C.
313 DisableExtension(idB);
314 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions());
315 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
316 EXPECT_EQ(idC, browser_actions_bar()->GetExtensionId(0));
318 // Enable B. State becomes: B, C.
319 EnableExtension(idB);
320 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
321 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
322 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(0));
324 // Enable A. State becomes: A, B, C.
325 EnableExtension(idA);
326 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
327 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
328 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
330 // Shrink the browser actions bar to zero visible icons.
331 // No icons should be visible, but we *should* show the chevron and have a
333 browser_actions_bar()->SetIconVisibilityCount(0);
334 EXPECT_EQ(0, browser_actions_bar()->VisibleBrowserActions());
335 BrowserActionsContainer* container =
336 BrowserView::GetBrowserViewForBrowser(browser())
337 ->toolbar()->browser_actions();
338 ASSERT_TRUE(container->chevron());
339 EXPECT_TRUE(container->chevron()->visible());
340 EXPECT_FALSE(container->GetPreferredSize().IsEmpty());
342 // Reset visibility count to 2. State should be A, B, [C], and the chevron
343 // should be visible.
344 browser_actions_bar()->SetIconVisibilityCount(2);
345 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
346 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
347 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(1));
348 EXPECT_TRUE(container->chevron()->visible());
350 // Disable C (the overflowed extension). State should now be A, B, and the
351 // chevron should be hidden.
352 DisableExtension(idC);
353 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
354 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
355 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(1));
356 EXPECT_FALSE(container->chevron()->visible());
358 // Re-enable C. We should still only have 2 visible icons, and the chevron
359 // should be visible.
360 EnableExtension(idC);
361 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
362 EXPECT_EQ(idA, browser_actions_bar()->GetExtensionId(0));
363 EXPECT_EQ(idB, browser_actions_bar()->GetExtensionId(1));
364 EXPECT_TRUE(container->chevron()->visible());
367 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, ForceHide) {
368 // Load extension A (contains browser action).
369 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
370 .AppendASCII("browser_action")
371 .AppendASCII("basics")));
372 EXPECT_EQ(1, browser_actions_bar()->NumberOfBrowserActions());
373 EXPECT_TRUE(browser_actions_bar()->HasIcon(0));
374 EXPECT_EQ(1, browser_actions_bar()->VisibleBrowserActions());
375 std::string idA = browser_actions_bar()->GetExtensionId(0);
377 // Force hide this browser action.
378 extensions::ExtensionActionAPI::SetBrowserActionVisibility(
379 extensions::ExtensionPrefs::Get(browser()->profile()), idA, false);
380 EXPECT_EQ(0, browser_actions_bar()->VisibleBrowserActions());
383 // Test that the BrowserActionsContainer responds correctly when the underlying
384 // model enters highlight mode, and that browser actions are undraggable in
385 // highlight mode. (Highlight mode itself it tested more thoroughly in the
386 // ExtensionToolbarModel browsertests).
387 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerTest, HighlightMode) {
388 // Load three extensions with browser actions.
389 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
390 .AppendASCII("browser_action")
391 .AppendASCII("basics")));
392 std::string id_a = browser_actions_bar()->GetExtensionId(0);
393 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
394 .AppendASCII("browser_action")
395 .AppendASCII("add_popup")));
396 std::string id_b = browser_actions_bar()->GetExtensionId(1);
397 ASSERT_TRUE(LoadExtension(test_data_dir_.AppendASCII("api_test")
398 .AppendASCII("browser_action")
399 .AppendASCII("remove_popup")));
401 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
402 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
404 BrowserActionsContainer* container = browser()
406 ->GetBrowserWindowTesting()
410 // Currently, dragging should be enabled.
411 BrowserActionView* action_view = container->GetBrowserActionViewAt(0);
412 ASSERT_TRUE(action_view);
413 gfx::Point point(action_view->x(), action_view->y());
414 EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
416 extensions::ExtensionToolbarModel* model =
417 extensions::ExtensionToolbarModel::Get(profile());
419 extensions::ExtensionIdList extension_ids;
420 extension_ids.push_back(id_a);
421 extension_ids.push_back(id_b);
422 model->HighlightExtensions(extension_ids);
424 // Only two browser actions should be visible.
425 EXPECT_EQ(2, browser_actions_bar()->VisibleBrowserActions());
426 EXPECT_EQ(2, browser_actions_bar()->NumberOfBrowserActions());
428 // We shouldn't be able to drag in highlight mode.
429 action_view = container->GetBrowserActionViewAt(0);
430 EXPECT_FALSE(container->CanStartDragForView(action_view, point, point));
432 // We should go back to normal after leaving highlight mode.
433 model->StopHighlighting();
434 EXPECT_EQ(3, browser_actions_bar()->VisibleBrowserActions());
435 EXPECT_EQ(3, browser_actions_bar()->NumberOfBrowserActions());
436 action_view = container->GetBrowserActionViewAt(0);
437 EXPECT_TRUE(container->CanStartDragForView(action_view, point, point));
440 // Test the behavior of the overflow container for Extension Actions.
441 class BrowserActionsContainerOverflowTest : public BrowserActionsContainerTest {
443 BrowserActionsContainerOverflowTest() : main_bar_(NULL), model_(NULL) {
445 virtual ~BrowserActionsContainerOverflowTest() {
449 // Returns true if the order of the BrowserActionViews in |main_bar_|
450 // and |overflow_bar_| match.
451 bool ViewOrdersMatch();
453 // Returns Success if the visible count matches |expected_visible|. This means
454 // that the number of visible browser actions in |main_bar_| is
455 // |expected_visible| and shows the first icons, and that the overflow bar
456 // shows all (and only) the remainder.
457 testing::AssertionResult VerifyVisibleCount(size_t expected_visible);
460 BrowserActionsContainer* main_bar() { return main_bar_; }
461 BrowserActionsContainer* overflow_bar() { return overflow_bar_.get(); }
462 extensions::ExtensionToolbarModel* model() { return model_; }
465 virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE;
466 virtual void SetUpOnMainThread() OVERRIDE;
467 virtual void TearDownOnMainThread() OVERRIDE;
469 // The main BrowserActionsContainer (owned by the browser view).
470 BrowserActionsContainer* main_bar_;
472 // The overflow BrowserActionsContainer. We manufacture this so that we don't
473 // have to open the wrench menu.
474 scoped_ptr<BrowserActionsContainer> overflow_bar_;
476 // The associated toolbar model.
477 extensions::ExtensionToolbarModel* model_;
479 // Enable the feature redesign switch.
480 scoped_ptr<extensions::FeatureSwitch::ScopedOverride> enable_redesign_;
482 DISALLOW_COPY_AND_ASSIGN(BrowserActionsContainerOverflowTest);
485 void BrowserActionsContainerOverflowTest::SetUpCommandLine(
486 base::CommandLine* command_line) {
487 BrowserActionsContainerTest::SetUpCommandLine(command_line);
488 enable_redesign_.reset(new extensions::FeatureSwitch::ScopedOverride(
489 extensions::FeatureSwitch::extension_action_redesign(),
493 void BrowserActionsContainerOverflowTest::SetUpOnMainThread() {
494 BrowserActionsContainerTest::SetUpOnMainThread();
495 main_bar_ = BrowserView::GetBrowserViewForBrowser(browser())
496 ->toolbar()->browser_actions();
497 overflow_bar_.reset(new BrowserActionsContainer(browser(), NULL, main_bar_));
498 overflow_bar_->set_owned_by_client();
499 model_ = extensions::ExtensionToolbarModel::Get(profile());
502 void BrowserActionsContainerOverflowTest::TearDownOnMainThread() {
503 overflow_bar_.reset();
504 enable_redesign_.reset();
505 BrowserActionsContainerTest::TearDownOnMainThread();
508 bool BrowserActionsContainerOverflowTest::ViewOrdersMatch() {
509 if (main_bar_->num_browser_actions() !=
510 overflow_bar_->num_browser_actions())
512 for (size_t i = 0; i < main_bar_->num_browser_actions(); ++i) {
513 if (main_bar_->GetBrowserActionViewAt(i)->extension() !=
514 overflow_bar_->GetBrowserActionViewAt(i)->extension())
520 testing::AssertionResult
521 BrowserActionsContainerOverflowTest::VerifyVisibleCount(
522 size_t expected_visible) {
523 // Views order should always match (as it is based directly off the model).
524 if (!ViewOrdersMatch())
525 return testing::AssertionFailure() << "View orders don't match";
527 // Loop through and check each browser action for proper visibility (which
528 // implicitly also guarantees that the proper number are visible).
529 for (size_t i = 0; i < overflow_bar_->num_browser_actions(); ++i) {
530 bool visible = i < expected_visible;
531 if (main_bar_->GetBrowserActionViewAt(i)->visible() != visible) {
532 return testing::AssertionFailure() << "Index " << i <<
533 " has improper visibility in main: " << !visible;
535 if (overflow_bar_->GetBrowserActionViewAt(i)->visible() == visible) {
536 return testing::AssertionFailure() << "Index " << i <<
537 " has improper visibility in overflow: " << visible;
540 return testing::AssertionSuccess();
543 // Test the basic functionality of the BrowserActionsContainer in overflow mode.
544 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerOverflowTest,
545 TestBasicActionOverflow) {
546 // Load three extensions with browser actions.
547 // TODO(devlin): Make a method to load these, and generate them rather than
549 base::FilePath test_data_path =
550 test_data_dir_.AppendASCII("api_test").AppendASCII("browser_action");
551 const extensions::Extension* extension_a =
552 LoadExtension(test_data_path.AppendASCII("basics"));
553 const extensions::Extension* extension_b =
554 LoadExtension(test_data_path.AppendASCII("add_popup"));
555 const extensions::Extension* extension_c =
556 LoadExtension(test_data_path.AppendASCII("remove_popup"));
558 // Since the overflow bar isn't attached to a view, we have to kick it in
559 // order to retrigger layout each time we change the number of icons in the
561 overflow_bar()->Layout();
564 // All extensions loaded.
565 ASSERT_TRUE(extension_a);
566 ASSERT_TRUE(extension_b);
567 ASSERT_TRUE(extension_c);
569 // All actions are showing, and are in the installation order.
570 EXPECT_EQ(-1, model()->GetVisibleIconCount());
571 ASSERT_EQ(3u, main_bar()->num_browser_actions());
572 EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
573 EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(1)->extension());
574 EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
575 EXPECT_TRUE(VerifyVisibleCount(3u));
577 // Reduce the visible count to 2. Order should be unchanged (A B C), but
578 // only A and B should be visible on the main bar.
579 model()->SetVisibleIconCountForTest(2u);
580 overflow_bar()->Layout(); // Kick.
581 EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
582 EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(1)->extension());
583 EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
584 EXPECT_TRUE(VerifyVisibleCount(2u));
586 // Move extension C to the first position. Order should now be C A B, with
587 // C and A visible in the main bar.
588 model()->MoveExtensionIcon(extension_c, 0);
589 overflow_bar()->Layout(); // Kick.
590 EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(0)->extension());
591 EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(1)->extension());
592 EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(2)->extension());
593 EXPECT_TRUE(VerifyVisibleCount(2u));
595 // Hide action A. This results in it being sent to overflow, and reducing the
596 // visible size to 1, so the order should be C A B, with only C visible in the
598 extensions::ExtensionActionAPI::SetBrowserActionVisibility(
599 extensions::ExtensionPrefs::Get(profile()),
602 overflow_bar()->Layout(); // Kick.
603 EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(0)->extension());
604 EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(1)->extension());
605 EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(2)->extension());
606 EXPECT_TRUE(VerifyVisibleCount(1u));
609 // Test drag and drop between the overflow container and the main container.
610 IN_PROC_BROWSER_TEST_F(BrowserActionsContainerOverflowTest,
611 TestOverflowDragging) {
612 base::FilePath test_data_path =
613 test_data_dir_.AppendASCII("api_test").AppendASCII("browser_action");
614 const extensions::Extension* extension_a =
615 LoadExtension(test_data_path.AppendASCII("basics"));
616 const extensions::Extension* extension_b =
617 LoadExtension(test_data_path.AppendASCII("add_popup"));
618 const extensions::Extension* extension_c =
619 LoadExtension(test_data_path.AppendASCII("remove_popup"));
621 // Start with one extension in overflow.
622 model()->SetVisibleIconCountForTest(2u);
623 overflow_bar()->Layout();
625 // Verify starting state is A B [C].
626 ASSERT_EQ(3u, main_bar()->num_browser_actions());
627 EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
628 EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(1)->extension());
629 EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
630 EXPECT_TRUE(VerifyVisibleCount(2u));
632 // Drag extension A (on the main bar) to the left of extension C (in
634 ui::OSExchangeData drop_data;
635 BrowserActionDragData browser_action_drag_data(extension_a->id(), 0u);
636 browser_action_drag_data.Write(profile(), &drop_data);
637 BrowserActionView* view = overflow_bar()->GetViewForExtension(extension_c);
638 gfx::Point location(view->x(), view->y());
639 ui::DropTargetEvent target_event(
640 drop_data, location, location, ui::DragDropTypes::DRAG_MOVE);
642 overflow_bar()->OnDragUpdated(target_event);
643 overflow_bar()->OnPerformDrop(target_event);
644 overflow_bar()->Layout();
646 // Order should now be B [A C].
647 EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(0)->extension());
648 EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(1)->extension());
649 EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
650 VerifyVisibleCount(1u);
652 // Drag extension A back from overflow to the main bar.
653 ui::OSExchangeData drop_data2;
654 BrowserActionDragData browser_action_drag_data2(extension_a->id(), 1u);
655 browser_action_drag_data2.Write(profile(), &drop_data2);
656 view = main_bar()->GetViewForExtension(extension_b);
657 location = gfx::Point(view->x(), view->y());
658 ui::DropTargetEvent target_event2(
659 drop_data2, location, location, ui::DragDropTypes::DRAG_MOVE);
661 main_bar()->OnDragUpdated(target_event2);
662 main_bar()->OnPerformDrop(target_event2);
664 // Order should be A B [C] again.
665 EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
666 EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(1)->extension());
667 EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(2)->extension());
668 VerifyVisibleCount(2u);
670 // Drag extension C from overflow to the main bar (before extension B).
671 ui::OSExchangeData drop_data3;
672 BrowserActionDragData browser_action_drag_data3(extension_c->id(), 2u);
673 browser_action_drag_data3.Write(profile(), &drop_data3);
674 location = gfx::Point(view->x(), view->y());
675 ui::DropTargetEvent target_event3(
676 drop_data3, location, location, ui::DragDropTypes::DRAG_MOVE);
678 main_bar()->OnDragUpdated(target_event3);
679 main_bar()->OnPerformDrop(target_event3);
681 // Order should be A C B, and there should be no extensions in overflow.
682 EXPECT_EQ(extension_a, main_bar()->GetBrowserActionViewAt(0)->extension());
683 EXPECT_EQ(extension_c, main_bar()->GetBrowserActionViewAt(1)->extension());
684 EXPECT_EQ(extension_b, main_bar()->GetBrowserActionViewAt(2)->extension());
685 VerifyVisibleCount(3u);