Chromium Code Reviews| Index: chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm |
| diff --git a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm |
| index 55149f31f3c1cc25dd0412b32de4ee0eed1bf768..6c0b8197c528901c388b0c00b12db6ae23ecb3a3 100644 |
| --- a/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm |
| +++ b/chrome/browser/ui/cocoa/extensions/browser_action_button_interactive_uitest.mm |
| @@ -5,6 +5,8 @@ |
| #import <Cocoa/Cocoa.h> |
| #include "base/memory/scoped_ptr.h" |
| +#include "base/strings/stringprintf.h" |
| +#include "base/strings/utf_string_conversions.h" |
| #include "chrome/browser/extensions/extension_action_test_util.h" |
| #include "chrome/browser/extensions/extension_browsertest.h" |
| #include "chrome/browser/extensions/extension_service.h" |
| @@ -16,6 +18,9 @@ |
| #import "chrome/browser/ui/cocoa/extensions/browser_actions_controller.h" |
| #import "chrome/browser/ui/cocoa/toolbar/toolbar_controller.h" |
| #import "chrome/browser/ui/cocoa/wrench_menu/wrench_menu_controller.h" |
| +#include "chrome/browser/ui/global_error/global_error.h" |
| +#include "chrome/browser/ui/global_error/global_error_service.h" |
| +#include "chrome/browser/ui/global_error/global_error_service_factory.h" |
| #include "chrome/browser/ui/toolbar/toolbar_actions_bar.h" |
| #include "chrome/test/base/interactive_test_utils.h" |
| #include "extensions/common/feature_switch.h" |
| @@ -23,6 +28,36 @@ |
| namespace { |
| +const int kMenuPadding = 26; |
| + |
| +// A simple error class that has a menu item. |
| +class MenuError : public GlobalError { |
| + public: |
| + MenuError() {} |
| + ~MenuError() override {} |
| + |
| + bool HasMenuItem() override { return true; } |
| + int MenuItemCommandID() override { |
| + // An arbitrary high id so that it's not taken. |
|
Avi (use Gerrit)
2015/07/30 02:50:35
I'm sure one day you will trace down some weird bu
Devlin
2015/07/31 19:48:30
This should only be used when the menu item is use
|
| + return 65536; |
| + } |
| + base::string16 MenuItemLabel() override { |
| + const char kErrorMessage[] = |
| + "This is a really long error message that will cause the wrench menu " |
| + " to have increased width"; |
|
Avi (use Gerrit)
2015/07/30 02:50:35
Did you intend that double space? Drop the space b
Devlin
2015/07/31 19:48:30
Done.
|
| + return base::ASCIIToUTF16(kErrorMessage); |
| + } |
| + void ExecuteMenuItem(Browser* browser) override {} |
| + |
| + bool HasBubbleView() override { return false; } |
| + bool HasShownBubbleView() override { return false; } |
| + void ShowBubbleView(Browser* browser) override {} |
| + GlobalErrorBubbleViewBase* GetBubbleView() override { return nullptr; } |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(MenuError); |
| +}; |
| + |
| // Returns the center point for a particular |view|. |
| NSPoint GetCenterPoint(NSView* view) { |
| NSWindow* window = [view window]; |
| @@ -93,7 +128,20 @@ class BrowserActionButtonUiTest : public ExtensionBrowserTest { |
| BrowserActionButtonUiTest() {} |
| ~BrowserActionButtonUiTest() override {} |
| + void SetUpOnMainThread() override { |
| + ExtensionBrowserTest::SetUpOnMainThread(); |
| + toolbarController_ = |
| + [[BrowserWindowController |
| + browserWindowControllerForWindow:browser()-> |
| + window()->GetNativeWindow()] |
| + toolbarController]; |
| + ASSERT_TRUE(toolbarController_); |
| + wrenchMenuController_ = [toolbarController_ wrenchMenuController]; |
| + model_ = extensions::ExtensionToolbarModel::Get(profile()); |
| + } |
| + |
| void SetUpCommandLine(base::CommandLine* command_line) override { |
| + ExtensionBrowserTest::SetUpCommandLine(command_line); |
| enable_redesign_.reset(new extensions::FeatureSwitch::ScopedOverride( |
| extensions::FeatureSwitch::extension_action_redesign(), true)); |
| ToolbarActionsBar::disable_animations_for_testing_ = true; |
| @@ -102,11 +150,21 @@ class BrowserActionButtonUiTest : public ExtensionBrowserTest { |
| void TearDownOnMainThread() override { |
| enable_redesign_.reset(); |
| ToolbarActionsBar::disable_animations_for_testing_ = false; |
| + ExtensionBrowserTest::TearDownOnMainThread(); |
| } |
| + ToolbarController* toolbarController() { return toolbarController_; } |
| + WrenchMenuController* wrenchMenuController() { return wrenchMenuController_; } |
| + extensions::ExtensionToolbarModel* model() { return model_; } |
| + NSView* wrenchButton() { return [toolbarController_ wrenchButton]; } |
| + |
| private: |
| scoped_ptr<extensions::FeatureSwitch::ScopedOverride> enable_redesign_; |
| + ToolbarController* toolbarController_ = nil; |
| + WrenchMenuController* wrenchMenuController_ = nil; |
| + extensions::ExtensionToolbarModel* model_ = nil; |
|
Avi (use Gerrit)
2015/07/30 02:50:35
nullptr for C++ objects, nil for ObjC ones.
Devlin
2015/07/31 19:48:30
Heh, did that at first, and thought it looked so w
|
| + |
| DISALLOW_COPY_AND_ASSIGN(BrowserActionButtonUiTest); |
| }; |
| @@ -161,19 +219,10 @@ IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest, |
| "browser_action", |
| extensions::extension_action_test_util::BROWSER_ACTION); |
| extension_service()->AddExtension(extension.get()); |
| - extensions::ExtensionToolbarModel* model = |
| - extensions::ExtensionToolbarModel::Get(profile()); |
| - ASSERT_EQ(1u, model->toolbar_items().size()); |
| - |
| - ToolbarController* toolbarController = |
| - [[BrowserWindowController |
| - browserWindowControllerForWindow:browser()-> |
| - window()->GetNativeWindow()] |
| - toolbarController]; |
| - ASSERT_TRUE(toolbarController); |
| + ASSERT_EQ(1u, model()->toolbar_items().size()); |
| BrowserActionsController* actionsController = |
| - [toolbarController browserActionsController]; |
| + [toolbarController() browserActionsController]; |
| BrowserActionButton* actionButton = [actionsController buttonWithIndex:0]; |
| ASSERT_TRUE(actionButton); |
| @@ -210,13 +259,11 @@ IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest, |
| CheckActionIsPoppedOut, actionsController, actionButton)]; |
| // Shrink the visible count to be 0. This should hide the action button. |
| - model->SetVisibleIconCount(0); |
| + model()->SetVisibleIconCount(0); |
| EXPECT_EQ(nil, [actionButton superview]); |
| // Move the mouse over the wrench button. |
| - NSView* wrenchButton = [toolbarController wrenchButton]; |
| - ASSERT_TRUE(wrenchButton); |
| - MoveMouseToCenter(wrenchButton); |
| + MoveMouseToCenter(wrenchButton()); |
| { |
| // No menu yet (on the browser action). |
| @@ -228,7 +275,7 @@ IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest, |
| ui_controls::SendMouseEventsNotifyWhenDone( |
| ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP, |
| base::Bind(&ClickOnOverflowedAction, |
| - base::Unretained(toolbarController), |
| + base::Unretained(toolbarController()), |
| runLoop.QuitClosure())); |
| runLoop.Run(); |
| // The menu should have opened. Note that the menu opened on the main bar's |
| @@ -237,3 +284,119 @@ IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest, |
| EXPECT_TRUE([menuHelper menuOpened]); |
| } |
| } |
| + |
| +// Checks the layout of the overflow bar in the wrench menu. |
| +void CheckWrenchMenuLayout(ToolbarController* toolbarController, |
| + int overflowStartIndex, |
| + const base::Closure& closure) { |
| + WrenchMenuController* wrenchMenuController = |
| + [toolbarController wrenchMenuController]; |
| + // The wrench menu should start as open (since that's where the overflowed |
| + // actions are). |
| + EXPECT_TRUE([wrenchMenuController isMenuOpen]); |
| + BrowserActionsController* overflowController = |
| + [wrenchMenuController browserActionsController]; |
| + ASSERT_TRUE(overflowController); |
| + |
| + ToolbarActionsBar* overflowBar = [overflowController toolbarActionsBar]; |
| + BrowserActionsContainerView* overflowContainer = |
| + [overflowController containerView]; |
| + NSMenu* menu = [wrenchMenuController menu]; |
| + |
| + // The overflow container should be within the bounds of the wrench menu, as |
| + // should its parents. |
| + int menu_width = [menu size].width; |
| + NSRect frame = [overflowContainer frame]; |
| + EXPECT_GE(NSMinX(frame), 0); |
| + // Hierarchy: The overflow container is owned by two different views in the |
| + // wrench menu. Each should have a min x of >= 0. |
| + EXPECT_GE(NSMinX([[overflowContainer superview] frame]), 0); |
| + EXPECT_GE(NSMinX([[[overflowContainer superview] superview] frame]), 0); |
| + // The overflow container should fully fit in the wrench menu, including the |
| + // space taken away for padding, and should have its desired size. |
| + EXPECT_LE(NSWidth(frame), menu_width - kMenuPadding); |
| + EXPECT_EQ(NSWidth(frame), overflowBar->GetPreferredSize().width()); |
| + |
| + // Every button that has an index lower than the overflow start index (i.e., |
| + // every button on the main toolbar) should not be attached to a view. |
| + for (int i = 0; i < overflowStartIndex; ++i) { |
| + BrowserActionButton* button = [overflowController buttonWithIndex:i]; |
| + EXPECT_FALSE([button superview]); |
| + EXPECT_GE(0, NSMaxX([button frame])); |
| + } |
| + |
| + // Every other button should be attached to a view, and should be at the |
| + // proper bounds. Calculating each button's proper bounds here would just be |
| + // a duplication of the logic in the method, but we can test that each button |
| + // a) is within the overflow container's bounds, and |
| + // b) doesn't intersect with another button. |
| + // If both of those are true, then we're probably good. |
| + for (NSUInteger i = overflowStartIndex; |
| + i < [overflowController buttonCount]; ++i) { |
| + BrowserActionButton* button = [overflowController buttonWithIndex:i]; |
| + EXPECT_TRUE([button superview]); |
| + EXPECT_TRUE(NSContainsRect([overflowContainer bounds], [button frame])); |
| + for (NSUInteger j = 0; j < i; ++j) { |
| + EXPECT_FALSE( |
| + NSContainsRect([[overflowController buttonWithIndex:j] frame], |
| + [button frame])); |
| + } |
| + } |
| + |
| + // Close the wrench menu. |
| + [wrenchMenuController cancel]; |
| + EXPECT_FALSE([wrenchMenuController isMenuOpen]); |
| + base::MessageLoop::current()->PostTask(FROM_HERE, closure); |
| +} |
| + |
| +// Tests the layout of the overflow container in the wrench menu. |
| +IN_PROC_BROWSER_TEST_F(BrowserActionButtonUiTest, TestOverflowContainerLayout) { |
| + // Add a bunch of extensions - enough to trigger multiple rows in the overflow |
| + // menu. |
| + const int kNumExtensions = 12; |
| + for (int i = 0; i < kNumExtensions; ++i) { |
| + scoped_refptr<const extensions::Extension> extension = |
| + extensions::extension_action_test_util::CreateActionExtension( |
| + base::StringPrintf("extension%d", i), |
| + extensions::extension_action_test_util::BROWSER_ACTION); |
| + extension_service()->AddExtension(extension.get()); |
| + } |
| + ASSERT_EQ(kNumExtensions, static_cast<int>(model()->toolbar_items().size())); |
| + |
| + // A helper function to open the wrench menu and call the check function. |
| + auto resizeAndActivateWrench = [this](int visible_count) { |
| + model()->SetVisibleIconCount(kNumExtensions - visible_count); |
| + MoveMouseToCenter(wrenchButton()); |
| + |
| + { |
| + base::RunLoop runLoop; |
| + // Click on the wrench menu, and pass in a callback to continue the test |
| + // in CheckWrenchMenuLayout (due to the blocking nature of Cocoa menus, |
| + // passing in runLoop.QuitClosure() is not sufficient here.) |
| + ui_controls::SendMouseEventsNotifyWhenDone( |
| + ui_controls::LEFT, ui_controls::DOWN | ui_controls::UP, |
| + base::Bind(&CheckWrenchMenuLayout, |
| + base::Unretained(toolbarController()), |
| + kNumExtensions - visible_count, |
| + runLoop.QuitClosure())); |
| + runLoop.Run(); |
| + } |
| + }; |
| + |
| + // Test the layout with gradually more extensions hidden. |
| + for (int i = 1; i <= kNumExtensions; ++i) |
| + resizeAndActivateWrench(i); |
| + |
| + // Adding a global error adjusts the wrench menu size, and has been known |
| + // to mess up the overflow container's bounds (crbug.com/511326). |
| + GlobalErrorService* error_service = |
| + GlobalErrorServiceFactory::GetForProfile(profile()); |
| + error_service->AddGlobalError(new MenuError()); |
| + |
| + // It's probably excessive to test every level of the overflow here. Test |
| + // having all actions overflowed, some actions overflowed, and one action |
| + // overflowed. |
| + resizeAndActivateWrench(kNumExtensions); |
| + resizeAndActivateWrench(kNumExtensions / 2); |
| + resizeAndActivateWrench(1); |
| +} |