OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #import "chrome/browser/ui/cocoa/extensions/browser_action_button.h" | 5 #import "chrome/browser/ui/cocoa/extensions/browser_action_button.h" |
6 | 6 |
7 #import <Cocoa/Cocoa.h> | 7 #import <Cocoa/Cocoa.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 | 10 |
(...skipping 11 matching lines...) Expand all Loading... | |
22 #include "chrome/browser/ui/browser_window.h" | 22 #include "chrome/browser/ui/browser_window.h" |
23 #import "chrome/browser/ui/cocoa/app_menu/app_menu_controller.h" | 23 #import "chrome/browser/ui/cocoa/app_menu/app_menu_controller.h" |
24 #import "chrome/browser/ui/cocoa/browser_window_controller.h" | 24 #import "chrome/browser/ui/cocoa/browser_window_controller.h" |
25 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h" | 25 #import "chrome/browser/ui/cocoa/extensions/browser_actions_container_view.h" |
26 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h" | 26 #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h" |
27 #import "chrome/browser/ui/cocoa/test/run_loop_testing.h" | 27 #import "chrome/browser/ui/cocoa/test/run_loop_testing.h" |
28 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" | 28 #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" |
29 #include "chrome/browser/ui/global_error/global_error.h" | 29 #include "chrome/browser/ui/global_error/global_error.h" |
30 #include "chrome/browser/ui/global_error/global_error_service.h" | 30 #include "chrome/browser/ui/global_error/global_error_service.h" |
31 #include "chrome/browser/ui/global_error/global_error_service_factory.h" | 31 #include "chrome/browser/ui/global_error/global_error_service_factory.h" |
32 #include "chrome/browser/ui/toolbar/component_toolbar_actions_factory.h" | |
33 #include "chrome/browser/ui/toolbar/media_router_action.h" | |
32 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h" | 34 #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h" |
33 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h" | 35 #include "chrome/browser/ui/toolbar/toolbar_actions_model.h" |
34 #include "chrome/test/base/interactive_test_utils.h" | 36 #include "chrome/test/base/interactive_test_utils.h" |
35 #include "extensions/common/feature_switch.h" | 37 #include "extensions/common/feature_switch.h" |
36 #include "ui/base/cocoa/cocoa_base_utils.h" | 38 #include "ui/base/cocoa/cocoa_base_utils.h" |
37 #import "ui/events/test/cocoa_test_event_utils.h" | 39 #import "ui/events/test/cocoa_test_event_utils.h" |
38 | 40 |
39 namespace { | 41 namespace { |
40 | 42 |
41 const int kMenuPadding = 26; | 43 const int kMenuPadding = 26; |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
85 | 87 |
86 // Moves the mouse (synchronously) to the center of the given |view|. | 88 // Moves the mouse (synchronously) to the center of the given |view|. |
87 void MoveMouseToCenter(NSView* view) { | 89 void MoveMouseToCenter(NSView* view) { |
88 NSPoint centerPoint = GetCenterPoint(view); | 90 NSPoint centerPoint = GetCenterPoint(view); |
89 base::RunLoop runLoop; | 91 base::RunLoop runLoop; |
90 ui_controls::SendMouseMoveNotifyWhenDone( | 92 ui_controls::SendMouseMoveNotifyWhenDone( |
91 centerPoint.x, centerPoint.y, runLoop.QuitClosure()); | 93 centerPoint.x, centerPoint.y, runLoop.QuitClosure()); |
92 runLoop.Run(); | 94 runLoop.Run(); |
93 } | 95 } |
94 | 96 |
97 // Simulates a click on the action button in the overflow menu, and runs | |
98 // |closure| upon completion. | |
99 void ClickOnOverflowedAction(ToolbarController* toolbarController, | |
100 const base::Closure& closure) { | |
101 AppMenuController* appMenuController = [toolbarController appMenuController]; | |
102 // The app menu should start as open (since that's where the overflowed | |
103 // actions are). | |
104 EXPECT_TRUE([appMenuController isMenuOpen]); | |
105 BrowserActionsController* overflowController = | |
106 [appMenuController browserActionsController]; | |
107 | |
108 ASSERT_TRUE(overflowController); | |
109 BrowserActionButton* actionButton = [overflowController buttonWithIndex:0]; | |
110 // The action should be attached to a superview. | |
111 EXPECT_TRUE([actionButton superview]); | |
112 | |
113 // ui_controls:: methods don't play nice when there is an open menu (like the | |
114 // app menu). Instead, simulate a right click by feeding the event directly to | |
115 // the button. | |
116 NSPoint centerPoint = GetCenterPoint(actionButton); | |
117 NSEvent* mouseEvent = cocoa_test_event_utils::RightMouseDownAtPointInWindow( | |
118 centerPoint, [actionButton window]); | |
119 [actionButton rightMouseDown:mouseEvent]; | |
120 | |
121 // This should close the app menu. | |
122 EXPECT_FALSE([appMenuController isMenuOpen]); | |
123 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure); | |
124 } | |
125 | |
95 } // namespace | 126 } // namespace |
96 | 127 |
97 // A simple helper menu delegate that will keep track of if a menu is opened, | 128 // A simple helper menu delegate that will keep track of if a menu is opened, |
98 // and closes them immediately (which is useful because message loops with | 129 // and closes them immediately (which is useful because message loops with |
99 // menus open in Cocoa don't play nicely with testing). | 130 // menus open in Cocoa don't play nicely with testing). |
100 @interface MenuHelper : NSObject<NSMenuDelegate> { | 131 @interface MenuHelper : NSObject<NSMenuDelegate> { |
101 // Whether or not a menu has been opened. This can be reset so the helper can | 132 // Whether or not a menu has been opened. This can be reset so the helper can |
102 // be used multiple times. | 133 // be used multiple times. |
103 BOOL menuOpened_; | 134 BOOL menuOpened_; |
104 | 135 |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
222 extensions::FeatureSwitch::extension_action_redesign(), true)); | 253 extensions::FeatureSwitch::extension_action_redesign(), true)); |
223 ToolbarActionsBar::disable_animations_for_testing_ = true; | 254 ToolbarActionsBar::disable_animations_for_testing_ = true; |
224 } | 255 } |
225 | 256 |
226 void TearDownOnMainThread() override { | 257 void TearDownOnMainThread() override { |
227 enable_redesign_.reset(); | 258 enable_redesign_.reset(); |
228 ToolbarActionsBar::disable_animations_for_testing_ = false; | 259 ToolbarActionsBar::disable_animations_for_testing_ = false; |
229 ExtensionBrowserTest::TearDownOnMainThread(); | 260 ExtensionBrowserTest::TearDownOnMainThread(); |
230 } | 261 } |
231 | 262 |
263 // Opens the app menu and the context menu of the overflowed action, and | |
264 // checks that the menus get opened/closed properly. |menuHelper| must be set | |
265 // as the delegate for the context menu. | |
266 void OpenAppMenuAndActionContextMenu(MenuHelper* menuHelper) { | |
267 // Move the mouse over the app menu button. | |
268 MoveMouseToCenter(appMenuButton()); | |
269 | |
270 // No menu yet (on the browser action). | |
271 EXPECT_FALSE([menuHelper menuOpened]); | |
272 base::RunLoop runLoop; | |
273 // Click on the app menu, and pass in a callback to continue the test in | |
274 // ClickOnOverflowedAction. Due to the blocking nature of Cocoa menus, we | |
275 // can't test the menu synchronously here by quitting the run loop when it | |
276 // opens, and instead need to test through a callback. | |
277 base::scoped_nsobject<MenuWatcher> menuWatcher( | |
278 [[MenuWatcher alloc] initWithController:appMenuController()]); | |
279 [menuWatcher | |
280 setOpenClosure:base::Bind(&ClickOnOverflowedAction, | |
281 base::Unretained(toolbarController()), | |
282 runLoop.QuitClosure())]; | |
283 ui_controls::SendMouseEvents(ui_controls::LEFT, | |
284 ui_controls::DOWN | ui_controls::UP); | |
285 runLoop.Run(); | |
286 | |
287 // The menu opened on the main bar's action button rather than the | |
288 // overflow's since Cocoa does not support running a menu within a menu. | |
289 EXPECT_TRUE([menuHelper menuOpened]); | |
290 } | |
291 | |
232 ToolbarController* toolbarController() { return toolbarController_; } | 292 ToolbarController* toolbarController() { return toolbarController_; } |
233 AppMenuController* appMenuController() { return appMenuController_; } | 293 AppMenuController* appMenuController() { return appMenuController_; } |
234 ToolbarActionsModel* model() { return model_; } | 294 ToolbarActionsModel* model() { return model_; } |
235 NSView* appMenuButton() { return [toolbarController_ appMenuButton]; } | 295 NSView* appMenuButton() { return [toolbarController_ appMenuButton]; } |
236 | 296 |
237 private: | 297 private: |
238 std::unique_ptr<extensions::FeatureSwitch::ScopedOverride> enable_redesign_; | 298 std::unique_ptr<extensions::FeatureSwitch::ScopedOverride> enable_redesign_; |
239 | 299 |
240 ToolbarController* toolbarController_ = nil; | 300 ToolbarController* toolbarController_ = nil; |
241 AppMenuController* appMenuController_ = nil; | 301 AppMenuController* appMenuController_ = nil; |
242 ToolbarActionsModel* model_ = nullptr; | 302 ToolbarActionsModel* model_ = nullptr; |
243 | 303 |
244 DISALLOW_COPY_AND_ASSIGN(BrowserActionButtonUiTest); | 304 DISALLOW_COPY_AND_ASSIGN(BrowserActionButtonUiTest); |
245 }; | 305 }; |
246 | 306 |
247 // Simulates a clicks on the action button in the overflow menu, and runs | |
248 // |closure| upon completion. | |
249 void ClickOnOverflowedAction(ToolbarController* toolbarController, | |
250 const base::Closure& closure) { | |
251 AppMenuController* appMenuController = | |
252 [toolbarController appMenuController]; | |
253 // The app menu should start as open (since that's where the overflowed | |
254 // actions are). | |
255 EXPECT_TRUE([appMenuController isMenuOpen]); | |
256 BrowserActionsController* overflowController = | |
257 [appMenuController browserActionsController]; | |
258 | |
259 ASSERT_TRUE(overflowController); | |
260 BrowserActionButton* actionButton = | |
261 [overflowController buttonWithIndex:0]; | |
262 // The action should be attached to a superview. | |
263 EXPECT_TRUE([actionButton superview]); | |
264 | |
265 // ui_controls:: methods don't play nice when there is an open menu (like the | |
266 // app menu). Instead, simulate a right click by feeding the event directly to | |
267 // the button. | |
268 NSPoint centerPoint = GetCenterPoint(actionButton); | |
269 NSEvent* mouseEvent = cocoa_test_event_utils::RightMouseDownAtPointInWindow( | |
270 centerPoint, [actionButton window]); | |
271 [actionButton rightMouseDown:mouseEvent]; | |
272 | |
273 // This should close the app menu. | |
274 EXPECT_FALSE([appMenuController isMenuOpen]); | |
275 base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, closure); | |
276 } | |
277 | |
278 // Verifies that the action is "popped out" of overflow; that is, it is visible | 307 // Verifies that the action is "popped out" of overflow; that is, it is visible |
279 // on the main bar, and is set as the popped out action on the controlling | 308 // on the main bar, and is set as the popped out action on the controlling |
280 // ToolbarActionsBar. | 309 // ToolbarActionsBar. |
281 void CheckActionIsPoppedOut(BrowserActionsController* actionsController, | 310 void CheckActionIsPoppedOut(BrowserActionsController* actionsController, |
282 BrowserActionButton* actionButton) { | 311 BrowserActionButton* actionButton) { |
283 EXPECT_EQ([actionsController containerView], [actionButton superview]); | 312 EXPECT_EQ([actionsController containerView], [actionButton superview]); |
284 EXPECT_EQ([actionButton viewController], | 313 EXPECT_EQ([actionButton viewController], |
285 [actionsController toolbarActionsBar]->popped_out_action()); | 314 [actionsController toolbarActionsBar]->popped_out_action()); |
286 // Since the button is popped out for a popup or context menu, it should be | 315 // Since the button is popped out for a popup or context menu, it should be |
287 // highlighted. | 316 // highlighted. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
335 | 364 |
336 // Reset the menu helper so we can use it again. | 365 // Reset the menu helper so we can use it again. |
337 [menuHelper setMenuOpened:NO]; | 366 [menuHelper setMenuOpened:NO]; |
338 [menuHelper setVerify:base::Bind( | 367 [menuHelper setVerify:base::Bind( |
339 CheckActionIsPoppedOut, actionsController, actionButton)]; | 368 CheckActionIsPoppedOut, actionsController, actionButton)]; |
340 | 369 |
341 // Shrink the visible count to be 0. This should hide the action button. | 370 // Shrink the visible count to be 0. This should hide the action button. |
342 model()->SetVisibleIconCount(0); | 371 model()->SetVisibleIconCount(0); |
343 EXPECT_EQ(nil, [actionButton superview]); | 372 EXPECT_EQ(nil, [actionButton superview]); |
344 | 373 |
345 // Move the mouse over the app menu button. | 374 OpenAppMenuAndActionContextMenu(menuHelper.get()); |
346 MoveMouseToCenter(appMenuButton()); | 375 } |
347 | 376 |
348 { | 377 IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest, |
349 // No menu yet (on the browser action). | 378 MediaRouterActionContextMenuInOverflow) { |
350 EXPECT_FALSE([menuHelper menuOpened]); | 379 model()->AddComponentAction( |
351 base::RunLoop runLoop; | 380 ComponentToolbarActionsFactory::kMediaRouterActionId); |
352 // Click on the app menu, and pass in a callback to continue the test in | 381 ASSERT_EQ(1u, model()->toolbar_items().size()); |
353 // ClickOnOverflowedAction (Due to the blocking nature of Cocoa menus, | |
354 // passing in runLoop.QuitClosure() is not sufficient here.) | |
355 base::scoped_nsobject<MenuWatcher> menuWatcher( | |
356 [[MenuWatcher alloc] initWithController:appMenuController()]); | |
357 [menuWatcher setOpenClosure: | |
358 base::Bind(&ClickOnOverflowedAction, | |
359 base::Unretained(toolbarController()), | |
360 runLoop.QuitClosure())]; | |
361 ui_controls::SendMouseEvents(ui_controls::LEFT, | |
362 ui_controls::DOWN | ui_controls::UP); | |
363 runLoop.Run(); | |
364 | 382 |
365 // The menu should have opened. Note that the menu opened on the main bar's | 383 BrowserActionButton* actionButton = |
366 // action button, not the overflow's. Since Cocoa doesn't support running | 384 [[toolbarController() browserActionsController] buttonWithIndex:0]; |
367 // a menu-within-a-menu, this is what has to happen. | 385 ASSERT_TRUE(actionButton); |
368 EXPECT_TRUE([menuHelper menuOpened]); | 386 |
369 EXPECT_FALSE([actionButton isHighlighted]); | 387 // Stub out the action button's normal context menu with a fake one so we |
370 } | 388 // can track when it opens. |
389 base::scoped_nsobject<NSMenu> testContextMenu( | |
390 [[NSMenu alloc] initWithTitle:@""]); | |
391 base::scoped_nsobject<MenuHelper> menuHelper([[MenuHelper alloc] init]); | |
392 [testContextMenu setDelegate:menuHelper.get()]; | |
393 [actionButton setTestContextMenu:testContextMenu.get()]; | |
394 | |
395 model()->SetActionVisibility( | |
396 ComponentToolbarActionsFactory::kMediaRouterActionId, false); | |
397 | |
398 OpenAppMenuAndActionContextMenu(menuHelper.get()); | |
399 | |
400 ToolbarActionsBar* actions_bar = | |
Robert Sesek
2017/01/03 21:42:22
nit: while under_scores are correct for this funct
takumif
2017/01/03 22:09:37
Done.
| |
401 [[toolbarController() browserActionsController] toolbarActionsBar]; | |
402 // The action should be back in the overflow. | |
403 EXPECT_FALSE( | |
404 actions_bar->IsActionVisibleOnMainBar(actions_bar->GetActions()[0])); | |
371 } | 405 } |
372 | 406 |
373 // Checks the layout of the overflow bar in the app menu. | 407 // Checks the layout of the overflow bar in the app menu. |
374 void CheckAppMenuLayout(ToolbarController* toolbarController, | 408 void CheckAppMenuLayout(ToolbarController* toolbarController, |
375 int overflowStartIndex, | 409 int overflowStartIndex, |
376 const std::string& error_message, | 410 const std::string& error_message, |
377 const base::Closure& closure) { | 411 const base::Closure& closure) { |
378 AppMenuController* appMenuController = | 412 AppMenuController* appMenuController = |
379 [toolbarController appMenuController]; | 413 [toolbarController appMenuController]; |
380 // The app menu should start as open (since that's where the overflowed | 414 // The app menu should start as open (since that's where the overflowed |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
643 openAndCloseAppMenu(appMenuController()); | 677 openAndCloseAppMenu(appMenuController()); |
644 | 678 |
645 // Move the extension back to the main bar, so an overflow bar is no longer | 679 // Move the extension back to the main bar, so an overflow bar is no longer |
646 // needed. Then open and close the app menu a couple times. | 680 // needed. Then open and close the app menu a couple times. |
647 // This tests that the menu properly cleans up after itself when an overflow | 681 // This tests that the menu properly cleans up after itself when an overflow |
648 // was present, and is no longer (fix for crbug.com/603241). | 682 // was present, and is no longer (fix for crbug.com/603241). |
649 model()->SetVisibleIconCount(1); | 683 model()->SetVisibleIconCount(1); |
650 openAndCloseAppMenu(appMenuController()); | 684 openAndCloseAppMenu(appMenuController()); |
651 openAndCloseAppMenu(appMenuController()); | 685 openAndCloseAppMenu(appMenuController()); |
652 } | 686 } |
OLD | NEW |