Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / panels / panel_cocoa_browsertest.mm
blobd0c82bd2a2efb45a181550f0fb4c6bc7bd4fafd3
1 // Copyright (c) 2012 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 #import <Cocoa/Cocoa.h>
7 #import "base/mac/scoped_nsobject.h"
8 #include "base/run_loop.h"
9 #include "base/test/test_timeouts.h"
10 #include "chrome/app/chrome_command_ids.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/ui/browser_commands.h"
13 #include "chrome/browser/ui/browser_finder.h"
14 #include "chrome/browser/ui/browser_window.h"
15 #include "chrome/browser/ui/panels/base_panel_browser_test.h"
16 #include "chrome/browser/ui/panels/panel.h"
17 #include "content/public/test/test_utils.h"
19 // Class that spins a run loop until an NSWindow gains key status.
20 @interface CocoaActivationWaiter : NSObject {
21  @private
22   base::RunLoop* runLoop_;
23   BOOL observed_;
26 - (id)initWithWindow:(NSWindow*)window;
27 - (void)windowDidBecomeKey:(NSNotification*)notification;
28 - (BOOL)waitUntilActive;
30 @end
32 @implementation CocoaActivationWaiter
34 - (id)initWithWindow:(NSWindow*)window {
35   EXPECT_FALSE([window isKeyWindow]);
36   if ((self = [super init])) {
37     [[NSNotificationCenter defaultCenter]
38         addObserver:self
39            selector:@selector(windowDidBecomeKey:)
40                name:NSWindowDidBecomeKeyNotification
41              object:window];
42   }
43   return self;
46 - (void)dealloc {
47   [[NSNotificationCenter defaultCenter] removeObserver:self];
48   [super dealloc];
51 - (void)windowDidBecomeKey:(NSNotification*)notification {
52   observed_ = YES;
53   if (runLoop_)
54     runLoop_->Quit();
57 - (BOOL)waitUntilActive {
58   if (observed_)
59     return YES;
61   base::RunLoop runLoop;
62   base::MessageLoop::current()->task_runner()->PostDelayedTask(
63       FROM_HERE, runLoop.QuitClosure(), TestTimeouts::action_timeout());
64   runLoop_ = &runLoop;
65   runLoop.Run();
66   runLoop_ = nullptr;
67   return observed_;
70 @end
72 typedef BasePanelBrowserTest PanelCocoaBrowserTest;
74 IN_PROC_BROWSER_TEST_F(PanelCocoaBrowserTest, MenuItems) {
75   Panel* panel = CreatePanel("Panel");
77   // Close main tabbed window.
78   content::WindowedNotificationObserver signal(
79       chrome::NOTIFICATION_BROWSER_CLOSED,
80       content::Source<Browser>(browser()));
81   chrome::CloseWindow(browser());
82   signal.Wait();
84   // There should be no browser windows.
85   EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
87   // There should be one panel.
88   EXPECT_EQ(1, PanelManager::GetInstance()->num_panels());
90   NSMenu* mainMenu = [NSApp mainMenu];
91   EXPECT_TRUE(mainMenu);
93   // Chrome(0) File(1) ....
94   // Get File submenu. It doesn't have a command id, fetch it by index.
95   NSMenu* fileSubmenu = [[[mainMenu itemArray] objectAtIndex:1] submenu];
96   EXPECT_TRUE(fileSubmenu);
97   [fileSubmenu update];
99   // Verify the items normally enabled for "all windows closed" case are
100   // also enabled when there is a panel but no browser windows on the screen.
101   NSMenuItem* item = [fileSubmenu itemWithTag:IDC_NEW_TAB];
102   EXPECT_TRUE(item);
103   EXPECT_TRUE([item isEnabled]);
105   item = [fileSubmenu itemWithTag:IDC_NEW_WINDOW];
106   EXPECT_TRUE(item);
107   EXPECT_TRUE([item isEnabled]);
109   item = [fileSubmenu itemWithTag:IDC_NEW_INCOGNITO_WINDOW];
110   EXPECT_TRUE(item);
111   EXPECT_TRUE([item isEnabled]);
113   NSMenu* historySubmenu = [[mainMenu itemWithTag:IDC_HISTORY_MENU] submenu];
114   EXPECT_TRUE(historySubmenu);
115   [historySubmenu update];
117   // These should be disabled.
118   item = [historySubmenu itemWithTag:IDC_HOME];
119   EXPECT_TRUE(item);
120   EXPECT_FALSE([item isEnabled]);
122   item = [historySubmenu itemWithTag:IDC_BACK];
123   EXPECT_TRUE(item);
124   EXPECT_FALSE([item isEnabled]);
126   item = [historySubmenu itemWithTag:IDC_FORWARD];
127   EXPECT_TRUE(item);
128   EXPECT_FALSE([item isEnabled]);
130   // 'Close Window' should be enabled because the remaining Panel is a Responder
131   // which implements performClose:, the 'action' of 'Close Window'.
132   for (NSMenuItem *i in [fileSubmenu itemArray]) {
133     if ([i action] == @selector(performClose:)) {
134       item = i;
135       break;
136     }
137   }
138   EXPECT_TRUE(item);
139   EXPECT_TRUE([item isEnabled]);
141   panel->Close();
144 // Test that panels do not become active when closing a window, even when a
145 // panel is otherwise the topmost window.
146 IN_PROC_BROWSER_TEST_F(PanelCocoaBrowserTest, InactivePanelsNotActivated) {
147   // Note CreateDockedPanel() sets wait_for_fully_created and SHOW_AS_ACTIVE,
148   // so the following spins a run loop until the respective panel is activated.
149   Panel* docked_panel_1 = CreateDockedPanel("Panel1", gfx::Rect());
150   EXPECT_TRUE([docked_panel_1->GetNativeWindow() isKeyWindow]);
152   // Activate the browser. Otherwise closing the second panel will correctly
153   // raise the first panel since panels are allowed to become key if they were
154   // actually the most recently focused window (as opposed to being merely the
155   // topmost window on the z-order stack).
156   NSWindow* browser_window = browser()->window()->GetNativeWindow();
157   base::scoped_nsobject<CocoaActivationWaiter> waiter(
158       [[CocoaActivationWaiter alloc] initWithWindow:browser_window]);
159   browser()->window()->Activate();
160   EXPECT_TRUE([waiter waitUntilActive]);
162   // Creating a second panel will activate it (and make it topmost).
163   Panel* docked_panel_2 = CreateDockedPanel("Panel2", gfx::Rect());
164   EXPECT_TRUE([docked_panel_2->GetNativeWindow() isKeyWindow]);
166   // Verify the assumptions that the panels are actually topmost.
167   EXPECT_EQ(docked_panel_2->GetNativeWindow(),
168             [[NSApp orderedWindows] objectAtIndex:0]);
169   EXPECT_EQ(docked_panel_1->GetNativeWindow(),
170             [[NSApp orderedWindows] objectAtIndex:1]);
172   // Close the second panel and wait for the browser to become active.
173   waiter.reset([[CocoaActivationWaiter alloc] initWithWindow:browser_window]);
174   docked_panel_2->Close();
176   EXPECT_TRUE([waiter waitUntilActive]);
177   EXPECT_TRUE([browser_window isKeyWindow]);