blob: 02823f790a659db49e4b51dd6afbc6b89d81199f [file] [log] [blame]
[email protected]fc44f242012-02-14 16:54:391// 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.
4
[email protected]66791aff2014-04-29 09:45:385#import <Carbon/Carbon.h>
[email protected]fc44f242012-02-14 16:54:396#import <Cocoa/Cocoa.h>
[email protected]66791aff2014-04-29 09:45:387#import <Foundation/Foundation.h>
8#import <Foundation/NSAppleEventDescriptor.h>
9#import <objc/message.h>
10#import <objc/runtime.h>
avie4d7b6f2015-12-26 00:59:1811#include <stddef.h>
[email protected]fc44f242012-02-14 16:54:3912
13#include "base/command_line.h"
[email protected]66791aff2014-04-29 09:45:3814#include "base/mac/foundation_util.h"
[email protected]a8522032013-06-24 22:51:4615#include "base/mac/scoped_nsobject.h"
gabf64a25e2017-05-12 19:42:5616#include "base/message_loop/message_loop.h"
thestigaf7f4152014-10-31 23:19:1517#include "base/run_loop.h"
lgarron9e6dee22014-11-18 01:03:3918#include "base/strings/sys_string_conversions.h"
19#include "base/strings/utf_string_conversions.h"
jam3f2d3932017-04-26 20:28:5120#include "base/threading/thread_restrictions.h"
[email protected]fc44f242012-02-14 16:54:3921#include "chrome/app/chrome_command_ids.h"
22#import "chrome/browser/app_controller_mac.h"
[email protected]bb4bec02013-08-15 11:26:5823#include "chrome/browser/apps/app_browsertest_util.h"
lgarron9e6dee22014-11-18 01:03:3924#include "chrome/browser/bookmarks/bookmark_model_factory.h"
[email protected]dbb03fb2014-02-15 05:36:3325#include "chrome/browser/browser_process.h"
mlerman8ae56aa2015-04-24 13:56:2726#include "chrome/browser/history/history_service_factory.h"
Trent Apted45d9ae22017-11-09 23:12:3227#include "chrome/browser/lifetime/application_lifetime.h"
lwchkg498e92492016-04-23 11:04:1228#include "chrome/browser/profiles/profile_attributes_entry.h"
29#include "chrome/browser/profiles/profile_attributes_storage.h"
[email protected]7108d912014-01-30 08:10:4530#include "chrome/browser/profiles/profile_manager.h"
[email protected]52877dbc62012-06-29 22:22:0331#include "chrome/browser/ui/browser.h"
Trent Apted45d9ae22017-11-09 23:12:3232#include "chrome/browser/ui/browser_finder.h"
[email protected]52877dbc62012-06-29 22:22:0333#include "chrome/browser/ui/browser_list.h"
thestige80821242015-09-30 23:46:0834#include "chrome/browser/ui/browser_navigator_params.h"
[email protected]ee9ccfd42013-07-23 02:31:4735#include "chrome/browser/ui/browser_window.h"
lgarron9e6dee22014-11-18 01:03:3936#include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
mlerman8ae56aa2015-04-24 13:56:2737#include "chrome/browser/ui/cocoa/history_menu_bridge.h"
lgrey92aad3c2016-12-10 01:22:1838#include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
kristiparka34b247a2018-03-09 19:05:3439#include "chrome/browser/ui/search/local_ntp_test_utils.h"
[email protected]617ee962013-01-29 20:49:1240#include "chrome/browser/ui/tabs/tab_strip_model.h"
mlermane29d0032014-09-24 19:31:2641#include "chrome/browser/ui/user_manager.h"
[email protected]7108d912014-01-30 08:10:4542#include "chrome/common/chrome_constants.h"
43#include "chrome/common/chrome_switches.h"
44#include "chrome/common/pref_names.h"
[email protected]66791aff2014-04-29 09:45:3845#include "chrome/common/url_constants.h"
[email protected]fc44f242012-02-14 16:54:3946#include "chrome/test/base/in_process_browser_test.h"
erikchen600f7962014-12-12 00:17:3847#include "chrome/test/base/ui_test_utils.h"
tapted574f09c2015-05-19 13:08:0848#include "components/bookmarks/browser/bookmark_model.h"
lgarron9e6dee22014-11-18 01:03:3949#include "components/bookmarks/test/bookmark_test_helpers.h"
brettwb1fc1b82016-02-02 00:19:0850#include "components/prefs/pref_service.h"
tmartino82e55782017-01-10 22:30:1751#include "content/public/browser/navigation_controller.h"
[email protected]fc44f242012-02-14 16:54:3952#include "content/public/browser/web_contents.h"
erikchen600f7962014-12-12 00:17:3853#include "content/public/test/browser_test_utils.h"
erikchen19ee3922014-10-31 19:14:2254#include "content/public/test/test_navigation_observer.h"
hashimotoad3c6872014-08-29 09:46:5755#include "extensions/browser/app_window/app_window_registry.h"
[email protected]e4452d32013-11-15 23:07:4156#include "extensions/common/extension.h"
lfg910f2f92014-09-19 05:31:0957#include "extensions/test/extension_test_message_listener.h"
[email protected]66791aff2014-04-29 09:45:3858#include "net/test/embedded_test_server/embedded_test_server.h"
Trent Apted45d9ae22017-11-09 23:12:3259#import "ui/events/test/cocoa_test_event_utils.h"
[email protected]66791aff2014-04-29 09:45:3860
Adam Riceff26dcf2017-08-14 05:01:5261using base::SysUTF16ToNSString;
62
[email protected]66791aff2014-04-29 09:45:3863namespace {
64
Scott Violet1f106b582017-07-12 15:49:5865GURL g_open_shortcut_url = GURL::EmptyGURL();
[email protected]66791aff2014-04-29 09:45:3866
erikchen19ee3922014-10-31 19:14:2267// Returns an Apple Event that instructs the application to open |url|.
68NSAppleEventDescriptor* AppleEventToOpenUrl(const GURL& url) {
69 NSAppleEventDescriptor* shortcut_event = [[[NSAppleEventDescriptor alloc]
70 initWithEventClass:kASAppleScriptSuite
71 eventID:kASSubroutineEvent
72 targetDescriptor:nil
73 returnID:kAutoGenerateReturnID
74 transactionID:kAnyTransactionID] autorelease];
75 NSString* url_string = [NSString stringWithUTF8String:url.spec().c_str()];
76 [shortcut_event setParamDescriptor:[NSAppleEventDescriptor
77 descriptorWithString:url_string]
78 forKeyword:keyDirectObject];
79 return shortcut_event;
80}
81
82// Instructs the NSApp's delegate to open |url|.
83void SendAppleEventToOpenUrlToAppController(const GURL& url) {
84 AppController* controller =
85 base::mac::ObjCCast<AppController>([NSApp delegate]);
86 Method get_url =
87 class_getInstanceMethod([controller class], @selector(getUrl:withReply:));
88
89 ASSERT_TRUE(get_url);
90
91 NSAppleEventDescriptor* shortcut_event = AppleEventToOpenUrl(url);
92
93 method_invoke(controller, get_url, shortcut_event, NULL);
94}
95
mlerman8ae56aa2015-04-24 13:56:2796void RunClosureWhenProfileInitialized(const base::Closure& closure,
97 Profile* profile,
98 Profile::CreateStatus status) {
99 if (status == Profile::CREATE_STATUS_INITIALIZED)
100 closure.Run();
101}
102
[email protected]66791aff2014-04-29 09:45:38103} // namespace
104
105@interface TestOpenShortcutOnStartup : NSObject
106- (void)applicationWillFinishLaunching:(NSNotification*)notification;
107@end
108
109@implementation TestOpenShortcutOnStartup
110
111- (void)applicationWillFinishLaunching:(NSNotification*)notification {
Scott Violet1f106b582017-07-12 15:49:58112 if (!g_open_shortcut_url.is_valid())
113 return;
114
erikchen19ee3922014-10-31 19:14:22115 SendAppleEventToOpenUrlToAppController(g_open_shortcut_url);
[email protected]66791aff2014-04-29 09:45:38116}
117
118@end
[email protected]fc44f242012-02-14 16:54:39119
120namespace {
121
Trent Apted45d9ae22017-11-09 23:12:32122using AppControllerBrowserTest = InProcessBrowserTest;
123
124size_t CountVisibleWindows() {
125 size_t count = 0;
126 for (NSWindow* w in [NSApp windows])
127 count = count + ([w isVisible] ? 1 : 0);
128 return count;
129}
130
131// Test browser shutdown with a command in the message queue.
132IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest, CommandDuringShutdown) {
133 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
134 EXPECT_EQ(1u, CountVisibleWindows());
135
136 chrome::AttemptExit(); // Set chrome::IsTryingToQuit and close all windows.
137
138 // Opening a new window here is fine (unload handlers can also interrupt
139 // exit). But closing the window posts an autorelease on
140 // BrowserWindowController, which calls ~Browser() and, if that was the last
141 // Browser, it invokes applicationWillTerminate: (because IsTryingToQuit is
142 // set). So, verify assumptions then process that autorelease.
143
144 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
145 EXPECT_EQ(0u, CountVisibleWindows());
146
147 base::RunLoop().RunUntilIdle();
148
149 EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
150 EXPECT_EQ(0u, CountVisibleWindows());
151
152 NSEvent* cmd_n = cocoa_test_event_utils::KeyEventWithKeyCode(
153 'n', 'n', NSKeyDown, NSCommandKeyMask);
154 [[NSApp mainMenu] performSelector:@selector(performKeyEquivalent:)
155 withObject:cmd_n
156 afterDelay:0];
157 // Let the run loop get flushed, during process cleanup and try not to crash.
158}
159
[email protected]ee9ccfd42013-07-23 02:31:47160class AppControllerPlatformAppBrowserTest
161 : public extensions::PlatformAppBrowserTest {
[email protected]fc44f242012-02-14 16:54:39162 protected:
[email protected]b4207c42013-02-12 06:44:20163 AppControllerPlatformAppBrowserTest()
scottmg0d8e4ab2016-01-28 00:34:55164 : active_browser_list_(BrowserList::GetInstance()) {}
[email protected]fc44f242012-02-14 16:54:39165
avi3ef9ec9e2014-12-22 22:50:17166 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]ee9ccfd42013-07-23 02:31:47167 PlatformAppBrowserTest::SetUpCommandLine(command_line);
[email protected]fc44f242012-02-14 16:54:39168 command_line->AppendSwitchASCII(switches::kAppId,
169 "1234");
170 }
[email protected]b4207c42013-02-12 06:44:20171
[email protected]7d1a810b2013-06-26 19:51:59172 const BrowserList* active_browser_list_;
[email protected]fc44f242012-02-14 16:54:39173};
174
175// Test that if only a platform app window is open and no browser windows are
176// open then a reopen event does nothing.
177IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
178 PlatformAppReopenWithWindows) {
[email protected]a8522032013-06-24 22:51:46179 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
[email protected]fc44f242012-02-14 16:54:39180 NSUInteger old_window_count = [[NSApp windows] count];
[email protected]7d1a810b2013-06-26 19:51:59181 EXPECT_EQ(1u, active_browser_list_->size());
[email protected]a25920ee2013-09-05 19:38:49182 [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:YES];
183 // We do not EXPECT_TRUE the result here because the method
184 // deminiaturizes windows manually rather than return YES and have
185 // AppKit do it.
[email protected]fc44f242012-02-14 16:54:39186
[email protected]fc44f242012-02-14 16:54:39187 EXPECT_EQ(old_window_count, [[NSApp windows] count]);
[email protected]7d1a810b2013-06-26 19:51:59188 EXPECT_EQ(1u, active_browser_list_->size());
[email protected]fc44f242012-02-14 16:54:39189}
190
[email protected]2e29e2232013-07-26 10:40:59191IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
192 ActivationFocusesBrowserWindow) {
193 base::scoped_nsobject<AppController> app_controller(
194 [[AppController alloc] init]);
195
196 ExtensionTestMessageListener listener("Launched", false);
197 const extensions::Extension* app =
198 InstallAndLaunchPlatformApp("minimal");
199 ASSERT_TRUE(listener.WaitUntilSatisfied());
200
hashimotoad3c6872014-08-29 09:46:57201 NSWindow* app_window = extensions::AppWindowRegistry::Get(profile())
[email protected]dbb03fb2014-02-15 05:36:33202 ->GetAppWindowsForApp(app->id())
203 .front()
204 ->GetNativeWindow();
[email protected]2e29e2232013-07-26 10:40:59205 NSWindow* browser_window = browser()->window()->GetNativeWindow();
206
andybons346c7c62015-08-13 15:18:03207 chrome::testing::NSRunLoopRunAllPending();
[email protected]2e29e2232013-07-26 10:40:59208 EXPECT_LE([[NSApp orderedWindows] indexOfObject:app_window],
209 [[NSApp orderedWindows] indexOfObject:browser_window]);
210 [app_controller applicationShouldHandleReopen:NSApp
211 hasVisibleWindows:YES];
andybons346c7c62015-08-13 15:18:03212 chrome::testing::NSRunLoopRunAllPending();
[email protected]2e29e2232013-07-26 10:40:59213 EXPECT_LE([[NSApp orderedWindows] indexOfObject:browser_window],
214 [[NSApp orderedWindows] indexOfObject:app_window]);
215}
216
[email protected]fc44f242012-02-14 16:54:39217class AppControllerWebAppBrowserTest : public InProcessBrowserTest {
218 protected:
[email protected]b4207c42013-02-12 06:44:20219 AppControllerWebAppBrowserTest()
scottmg0d8e4ab2016-01-28 00:34:55220 : active_browser_list_(BrowserList::GetInstance()) {}
[email protected]fc44f242012-02-14 16:54:39221
avi3ef9ec9e2014-12-22 22:50:17222 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]90ca44272012-07-18 18:15:48223 command_line->AppendSwitchASCII(switches::kApp, GetAppURL());
[email protected]fc44f242012-02-14 16:54:39224 }
225
226 std::string GetAppURL() const {
227 return "http://example.com/";
228 }
[email protected]b4207c42013-02-12 06:44:20229
[email protected]7d1a810b2013-06-26 19:51:59230 const BrowserList* active_browser_list_;
[email protected]fc44f242012-02-14 16:54:39231};
232
233// Test that in web app mode a reopen event opens the app URL.
234IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest,
235 WebAppReopenWithNoWindows) {
[email protected]a8522032013-06-24 22:51:46236 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
[email protected]7d1a810b2013-06-26 19:51:59237 EXPECT_EQ(1u, active_browser_list_->size());
[email protected]fc44f242012-02-14 16:54:39238 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
239
240 EXPECT_FALSE(result);
[email protected]7d1a810b2013-06-26 19:51:59241 EXPECT_EQ(2u, active_browser_list_->size());
[email protected]fc44f242012-02-14 16:54:39242
[email protected]7d1a810b2013-06-26 19:51:59243 Browser* browser = active_browser_list_->get(0);
[email protected]617ee962013-01-29 20:49:12244 GURL current_url =
245 browser->tab_strip_model()->GetActiveWebContents()->GetURL();
[email protected]fc44f242012-02-14 16:54:39246 EXPECT_EQ(GetAppURL(), current_url.spec());
247}
248
[email protected]7108d912014-01-30 08:10:45249// Called when the ProfileManager has created a profile.
250void CreateProfileCallback(const base::Closure& quit_closure,
251 Profile* profile,
252 Profile::CreateStatus status) {
253 EXPECT_TRUE(profile);
254 EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status);
255 EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status);
256 // This will be called multiple times. Wait until the profile is initialized
257 // fully to quit the loop.
258 if (status == Profile::CREATE_STATUS_INITIALIZED)
259 quit_closure.Run();
260}
261
mlermanb8df6e82015-01-23 19:55:34262void CreateAndWaitForSystemProfile() {
[email protected]7108d912014-01-30 08:10:45263 ProfileManager::CreateCallback create_callback =
264 base::Bind(&CreateProfileCallback,
ki.stfuc4f8e242015-10-09 20:40:20265 base::MessageLoop::current()->QuitWhenIdleClosure());
[email protected]7108d912014-01-30 08:10:45266 g_browser_process->profile_manager()->CreateProfileAsync(
mlermanb8df6e82015-01-23 19:55:34267 ProfileManager::GetSystemProfilePath(),
[email protected]7108d912014-01-30 08:10:45268 create_callback,
269 base::string16(),
lwchkg1f62d242015-10-29 00:50:43270 std::string(),
[email protected]7108d912014-01-30 08:10:45271 std::string());
272 base::RunLoop().Run();
273}
274
275class AppControllerNewProfileManagementBrowserTest
276 : public InProcessBrowserTest {
277 protected:
278 AppControllerNewProfileManagementBrowserTest()
scottmg0d8e4ab2016-01-28 00:34:55279 : active_browser_list_(BrowserList::GetInstance()) {}
[email protected]7108d912014-01-30 08:10:45280
[email protected]7108d912014-01-30 08:10:45281 const BrowserList* active_browser_list_;
282};
283
284// Test that for a regular last profile, a reopen event opens a browser.
285IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
286 RegularProfileReopenWithNoWindows) {
287 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
288 EXPECT_EQ(1u, active_browser_list_->size());
289 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
290
291 EXPECT_FALSE(result);
292 EXPECT_EQ(2u, active_browser_list_->size());
mlermane29d0032014-09-24 19:31:26293 EXPECT_FALSE(UserManager::IsShowing());
[email protected]7108d912014-01-30 08:10:45294}
295
296// Test that for a locked last profile, a reopen event opens the User Manager.
297IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
298 LockedProfileReopenWithNoWindows) {
mlermanb8df6e82015-01-23 19:55:34299 // The User Manager uses the system profile as its underlying profile. To
[email protected]7108d912014-01-30 08:10:45300 // minimize flakiness due to the scheduling/descheduling of tasks on the
301 // different threads, pre-initialize the guest profile before it is needed.
mlermanb8df6e82015-01-23 19:55:34302 CreateAndWaitForSystemProfile();
[email protected]7108d912014-01-30 08:10:45303 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
304
305 // Lock the active profile.
Francois Doraye6fb2d02017-10-18 21:29:13306 base::ScopedAllowBlockingForTesting allow_blocking;
[email protected]7108d912014-01-30 08:10:45307 Profile* profile = [ac lastProfile];
lwchkg9c183942016-03-13 06:29:54308 ProfileAttributesEntry* entry;
309 ASSERT_TRUE(g_browser_process->profile_manager()->
310 GetProfileAttributesStorage().
311 GetProfileAttributesWithPath(profile->GetPath(), &entry));
312 entry->SetIsSigninRequired(true);
313 EXPECT_TRUE(entry->IsSigninRequired());
[email protected]7108d912014-01-30 08:10:45314
315 EXPECT_EQ(1u, active_browser_list_->size());
316 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
317 EXPECT_FALSE(result);
318
319 base::RunLoop().RunUntilIdle();
320 EXPECT_EQ(1u, active_browser_list_->size());
mlermane29d0032014-09-24 19:31:26321 EXPECT_TRUE(UserManager::IsShowing());
322 UserManager::Hide();
[email protected]7108d912014-01-30 08:10:45323}
324
guidoubbb4787a2016-12-15 12:34:43325#if defined(ADDRESS_SANITIZER)
326// Flaky under ASAN. See https://crbug.com/674475.
327#define MAYBE_GuestProfileReopenWithNoWindows DISABLED_GuestProfileReopenWithNoWindows
328#else
329#define MAYBE_GuestProfileReopenWithNoWindows GuestProfileReopenWithNoWindows
330#endif
[email protected]7108d912014-01-30 08:10:45331// Test that for a guest last profile, a reopen event opens the User Manager.
332IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
guidoubbb4787a2016-12-15 12:34:43333 MAYBE_GuestProfileReopenWithNoWindows) {
mlermanb8df6e82015-01-23 19:55:34334 // Create the system profile. Set the guest as the last used profile so the
[email protected]7108d912014-01-30 08:10:45335 // app controller can use it on init.
mlermanb8df6e82015-01-23 19:55:34336 CreateAndWaitForSystemProfile();
[email protected]7108d912014-01-30 08:10:45337 PrefService* local_state = g_browser_process->local_state();
338 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
339
340 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
341
Francois Doraye6fb2d02017-10-18 21:29:13342 base::ScopedAllowBlockingForTesting allow_blocking;
[email protected]7108d912014-01-30 08:10:45343 Profile* profile = [ac lastProfile];
344 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath());
345 EXPECT_TRUE(profile->IsGuestSession());
346
347 EXPECT_EQ(1u, active_browser_list_->size());
348 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
349 EXPECT_FALSE(result);
350
351 base::RunLoop().RunUntilIdle();
352
353 EXPECT_EQ(1u, active_browser_list_->size());
mlermane29d0032014-09-24 19:31:26354 EXPECT_TRUE(UserManager::IsShowing());
355 UserManager::Hide();
[email protected]7108d912014-01-30 08:10:45356}
357
guidoubbb4787a2016-12-15 12:34:43358#if defined(ADDRESS_SANITIZER)
359// Flaky under ASAN. See https://crbug.com/674475.
360#define MAYBE_AboutChromeForcesUserManager DISABLED_AboutChromeForcesUserManager
361#else
362#define MAYBE_AboutChromeForcesUserManager AboutChromeForcesUserManager
363#endif
mlermane6e040a2014-10-31 00:53:21364IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
guidoubbb4787a2016-12-15 12:34:43365 MAYBE_AboutChromeForcesUserManager) {
mlermane6e040a2014-10-31 00:53:21366 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
367
368 // Create the guest profile, and set it as the last used profile so the
369 // app controller can use it on init.
mlermanb8df6e82015-01-23 19:55:34370 CreateAndWaitForSystemProfile();
mlermane6e040a2014-10-31 00:53:21371 PrefService* local_state = g_browser_process->local_state();
372 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
373
374 // Prohibiting guest mode forces the user manager flow for About Chrome.
375 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
376
Francois Doraye6fb2d02017-10-18 21:29:13377 base::ScopedAllowBlockingForTesting allow_blocking;
mlermane6e040a2014-10-31 00:53:21378 Profile* guest_profile = [ac lastProfile];
379 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), guest_profile->GetPath());
380 EXPECT_TRUE(guest_profile->IsGuestSession());
381
382 // Tell the browser to open About Chrome.
383 EXPECT_EQ(1u, active_browser_list_->size());
384 [ac orderFrontStandardAboutPanel:NSApp];
385
386 base::RunLoop().RunUntilIdle();
387
388 // No new browser is opened; the User Manager opens instead.
389 EXPECT_EQ(1u, active_browser_list_->size());
390 EXPECT_TRUE(UserManager::IsShowing());
391
392 UserManager::Hide();
393}
394
[email protected]66791aff2014-04-29 09:45:38395class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest {
396 protected:
397 AppControllerOpenShortcutBrowserTest() {
398 }
399
Daniel Chenga542fca2014-10-21 09:51:29400 void SetUpInProcessBrowserTestFixture() override {
[email protected]66791aff2014-04-29 09:45:38401 // In order to mimic opening shortcut during browser startup, we need to
402 // send the event before -applicationDidFinishLaunching is called, but
403 // after AppController is loaded.
404 //
405 // Since -applicationWillFinishLaunching does nothing now, we swizzle it to
406 // our function to send the event. We need to do this early before running
407 // the main message loop.
408 //
409 // NSApp does not exist yet. We need to get the AppController using
410 // reflection.
411 Class appControllerClass = NSClassFromString(@"AppController");
412 Class openShortcutClass = NSClassFromString(@"TestOpenShortcutOnStartup");
413
414 ASSERT_TRUE(appControllerClass != nil);
415 ASSERT_TRUE(openShortcutClass != nil);
416
417 SEL targetMethod = @selector(applicationWillFinishLaunching:);
418 Method original = class_getInstanceMethod(appControllerClass,
419 targetMethod);
420 Method destination = class_getInstanceMethod(openShortcutClass,
421 targetMethod);
422
423 ASSERT_TRUE(original != NULL);
424 ASSERT_TRUE(destination != NULL);
425
426 method_exchangeImplementations(original, destination);
Scott Violet1f106b582017-07-12 15:49:58427
428 ASSERT_TRUE(embedded_test_server()->Start());
429 g_open_shortcut_url = embedded_test_server()->GetURL("/simple.html");
[email protected]66791aff2014-04-29 09:45:38430 }
431
avi3ef9ec9e2014-12-22 22:50:17432 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]66791aff2014-04-29 09:45:38433 // If the arg is empty, PrepareTestCommandLine() after this function will
434 // append about:blank as default url.
435 command_line->AppendArg(chrome::kChromeUINewTabURL);
436 }
437};
438
439IN_PROC_BROWSER_TEST_F(AppControllerOpenShortcutBrowserTest,
440 OpenShortcutOnStartup) {
tmartino82e55782017-01-10 22:30:17441 // The two tabs expected are the Welcome page and the desired URL.
442 EXPECT_EQ(2, browser()->tab_strip_model()->count());
[email protected]66791aff2014-04-29 09:45:38443 EXPECT_EQ(g_open_shortcut_url,
444 browser()->tab_strip_model()->GetActiveWebContents()
445 ->GetLastCommittedURL());
446}
447
erikchen19ee3922014-10-31 19:14:22448class AppControllerReplaceNTPBrowserTest : public InProcessBrowserTest {
449 protected:
450 AppControllerReplaceNTPBrowserTest() {}
451
452 void SetUpInProcessBrowserTestFixture() override {
svaldeza01f7d92015-11-18 17:47:56453 ASSERT_TRUE(embedded_test_server()->Start());
erikchen19ee3922014-10-31 19:14:22454 }
455
avi3ef9ec9e2014-12-22 22:50:17456 void SetUpCommandLine(base::CommandLine* command_line) override {
erikchen19ee3922014-10-31 19:14:22457 // If the arg is empty, PrepareTestCommandLine() after this function will
458 // append about:blank as default url.
459 command_line->AppendArg(chrome::kChromeUINewTabURL);
460 }
461};
462
463// Tests that when a GURL is opened after startup, it replaces the NTP.
464IN_PROC_BROWSER_TEST_F(AppControllerReplaceNTPBrowserTest,
465 ReplaceNTPAfterStartup) {
kristiparka34b247a2018-03-09 19:05:34466 // Depending on network connectivity, the NTP URL can either be
467 // chrome://newtab/ or chrome-search://local-ntp/local-ntp.html. See
468 // local_ntp_test_utils::GetFinalNtpUrl for more details.
469 std::string expected_url =
470 local_ntp_test_utils::GetFinalNtpUrl(browser()->profile()).spec();
471
erikchen19ee3922014-10-31 19:14:22472 // Ensure that there is exactly 1 tab showing, and the tab is the NTP.
kristiparka34b247a2018-03-09 19:05:34473 GURL ntp(expected_url);
erikchen19ee3922014-10-31 19:14:22474 EXPECT_EQ(1, browser()->tab_strip_model()->count());
tmartino82e55782017-01-10 22:30:17475 browser()->tab_strip_model()->GetActiveWebContents()->GetController().LoadURL(
kristiparka34b247a2018-03-09 19:05:34476 GURL(expected_url), content::Referrer(),
tmartino82e55782017-01-10 22:30:17477 ui::PageTransition::PAGE_TRANSITION_LINK, std::string());
478
479 // Wait for one navigation on the active web contents.
480 content::TestNavigationObserver ntp_navigation_observer(
481 browser()->tab_strip_model()->GetActiveWebContents());
482 ntp_navigation_observer.Wait();
483
erikchen19ee3922014-10-31 19:14:22484 EXPECT_EQ(ntp,
485 browser()
486 ->tab_strip_model()
487 ->GetActiveWebContents()
488 ->GetLastCommittedURL());
489
490 GURL simple(embedded_test_server()->GetURL("/simple.html"));
491 SendAppleEventToOpenUrlToAppController(simple);
492
erikchen19ee3922014-10-31 19:14:22493 EXPECT_EQ(1, browser()->tab_strip_model()->count());
tmartino82e55782017-01-10 22:30:17494 content::TestNavigationObserver event_navigation_observer(
495 browser()->tab_strip_model()->GetActiveWebContents());
496 event_navigation_observer.Wait();
erikchen19ee3922014-10-31 19:14:22497
498 EXPECT_EQ(simple,
499 browser()
500 ->tab_strip_model()
501 ->GetActiveWebContents()
502 ->GetLastCommittedURL());
503}
504
lgarron9e6dee22014-11-18 01:03:39505class AppControllerMainMenuBrowserTest : public InProcessBrowserTest {
506 protected:
507 AppControllerMainMenuBrowserTest() {
508 }
509};
510
511IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
mlerman8ae56aa2015-04-24 13:56:27512 HistoryMenuResetAfterProfileDeletion) {
513 ProfileManager* profile_manager = g_browser_process->profile_manager();
tapted676995d2016-04-18 11:32:29514 AppController* ac =
515 base::mac::ObjCCastStrict<AppController>([NSApp delegate]);
mlerman8ae56aa2015-04-24 13:56:27516
517 // Use the existing profile as profile 1.
518 Profile* profile1 = browser()->profile();
519
520 // Create profile 2.
521 base::FilePath profile2_path =
522 profile_manager->GenerateNextProfileDirectoryPath();
523 base::RunLoop run_loop;
524 profile_manager->CreateProfileAsync(
525 profile2_path,
526 base::Bind(&RunClosureWhenProfileInitialized,
527 run_loop.QuitClosure()),
lwchkg1f62d242015-10-29 00:50:43528 base::string16(),
529 std::string(),
530 std::string());
mlerman8ae56aa2015-04-24 13:56:27531 run_loop.Run();
532 Profile* profile2 = profile_manager->GetProfileByPath(profile2_path);
533 ASSERT_TRUE(profile2);
534
535 // Switch the controller to profile1.
536 [ac windowChangedToProfile:profile1];
537 base::RunLoop().RunUntilIdle();
538
539 // Verify the controller's History Menu corresponds to profile1.
540 EXPECT_TRUE([ac historyMenuBridge]->service());
541 EXPECT_EQ([ac historyMenuBridge]->service(),
542 HistoryServiceFactory::GetForProfile(profile1,
543 ServiceAccessType::EXPLICIT_ACCESS));
544
545 // Load profile2's History Service backend so it will be assigned to the
546 // HistoryMenuBridge when windowChangedToProfile is called, or else this test
547 // will fail flaky.
548 ui_test_utils::WaitForHistoryToLoad(
549 HistoryServiceFactory::GetForProfile(profile2,
550 ServiceAccessType::EXPLICIT_ACCESS));
551 // Switch the controller to profile2.
552 [ac windowChangedToProfile:profile2];
553 base::RunLoop().RunUntilIdle();
554
555 // Verify the controller's History Menu has changed.
556 EXPECT_TRUE([ac historyMenuBridge]->service());
557 EXPECT_EQ([ac historyMenuBridge]->service(),
558 HistoryServiceFactory::GetForProfile(profile2,
559 ServiceAccessType::EXPLICIT_ACCESS));
560 EXPECT_NE(
561 HistoryServiceFactory::GetForProfile(profile1,
562 ServiceAccessType::EXPLICIT_ACCESS),
563 HistoryServiceFactory::GetForProfile(profile2,
564 ServiceAccessType::EXPLICIT_ACCESS));
565
566 // Delete profile2.
567 profile_manager->ScheduleProfileForDeletion(
568 profile2->GetPath(), ProfileManager::CreateCallback());
569 base::RunLoop().RunUntilIdle();
570
571 // Verify the controller's history is back to profile1.
572 EXPECT_EQ([ac historyMenuBridge]->service(),
573 HistoryServiceFactory::GetForProfile(profile1,
574 ServiceAccessType::EXPLICIT_ACCESS));
575}
576
577IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
lgarron9e6dee22014-11-18 01:03:39578 BookmarksMenuIsRestoredAfterProfileSwitch) {
579 ProfileManager* profile_manager = g_browser_process->profile_manager();
580 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
581 [ac awakeFromNib];
582
583 // Constants for bookmarks that we will create later.
584 const base::string16 title1(base::ASCIIToUTF16("Dinosaur Comics"));
585 const GURL url1("http://qwantz.com//");
586
587 const base::string16 title2(base::ASCIIToUTF16("XKCD"));
588 const GURL url2("https://www.xkcd.com/");
589
590 // Use the existing profile as profile 1.
591 Profile* profile1 = browser()->profile();
592 bookmarks::test::WaitForBookmarkModelToLoad(
pke3e0d5c92016-08-08 09:07:30593 BookmarkModelFactory::GetForBrowserContext(profile1));
lgarron9e6dee22014-11-18 01:03:39594
595 // Create profile 2.
Francois Doraye6fb2d02017-10-18 21:29:13596 base::ScopedAllowBlockingForTesting allow_blocking;
lgarron9e6dee22014-11-18 01:03:39597 base::FilePath path2 = profile_manager->GenerateNextProfileDirectoryPath();
598 Profile* profile2 =
599 Profile::CreateProfile(path2, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
600 profile_manager->RegisterTestingProfile(profile2, false, true);
601 bookmarks::test::WaitForBookmarkModelToLoad(
pke3e0d5c92016-08-08 09:07:30602 BookmarkModelFactory::GetForBrowserContext(profile2));
lgarron9e6dee22014-11-18 01:03:39603
604 // Switch to profile 1, create bookmark 1 and force the menu to build.
605 [ac windowChangedToProfile:profile1];
606 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
607 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
608 0, title1, url1);
Trent Aptedcf95689a2017-11-22 00:01:10609 NSMenu* profile1_submenu = [ac bookmarkMenuBridge]->BookmarkMenu();
610 [[profile1_submenu delegate] menuNeedsUpdate:profile1_submenu];
lgarron9e6dee22014-11-18 01:03:39611
612 // Switch to profile 2, create bookmark 2 and force the menu to build.
613 [ac windowChangedToProfile:profile2];
614 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
615 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
616 0, title2, url2);
Trent Aptedcf95689a2017-11-22 00:01:10617 NSMenu* profile2_submenu = [ac bookmarkMenuBridge]->BookmarkMenu();
618 [[profile2_submenu delegate] menuNeedsUpdate:profile2_submenu];
619 EXPECT_NE(profile1_submenu, profile2_submenu);
lgarron9e6dee22014-11-18 01:03:39620
621 // Test that only bookmark 2 is shown.
622 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
623 SysUTF16ToNSString(title1)]);
624 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
625 SysUTF16ToNSString(title2)]);
626
627 // Switch *back* to profile 1 and *don't* force the menu to build.
628 [ac windowChangedToProfile:profile1];
629
630 // Test that only bookmark 1 is shown in the restored menu.
631 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
632 SysUTF16ToNSString(title1)]);
633 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
634 SysUTF16ToNSString(title2)]);
Trent Aptedcf95689a2017-11-22 00:01:10635
636 // Ensure a cached menu was used.
637 EXPECT_EQ(profile1_submenu, [ac bookmarkMenuBridge]->BookmarkMenu());
lgarron9e6dee22014-11-18 01:03:39638}
639
[email protected]fc44f242012-02-14 16:54:39640} // namespace
erikchen600f7962014-12-12 00:17:38641
642//--------------------------AppControllerHandoffBrowserTest---------------------
643
644static GURL g_handoff_url;
645
646@interface AppController (BrowserTest)
647- (BOOL)new_shouldUseHandoff;
648- (void)new_passURLToHandoffManager:(const GURL&)handoffURL;
649@end
650
651@implementation AppController (BrowserTest)
652- (BOOL)new_shouldUseHandoff {
653 return YES;
654}
655
656- (void)new_passURLToHandoffManager:(const GURL&)handoffURL {
657 g_handoff_url = handoffURL;
658}
659@end
660
661namespace {
662
663class AppControllerHandoffBrowserTest : public InProcessBrowserTest {
664 protected:
665 AppControllerHandoffBrowserTest() {}
666
667 // Exchanges the implementations of the two selectors on the class
668 // AppController.
669 void ExchangeSelectors(SEL originalMethod, SEL newMethod) {
670 Class appControllerClass = NSClassFromString(@"AppController");
671
672 ASSERT_TRUE(appControllerClass != nil);
673
674 Method original =
675 class_getInstanceMethod(appControllerClass, originalMethod);
676 Method destination = class_getInstanceMethod(appControllerClass, newMethod);
677
678 ASSERT_TRUE(original != NULL);
679 ASSERT_TRUE(destination != NULL);
680
681 method_exchangeImplementations(original, destination);
682 }
683
684 // Swizzle Handoff related implementations.
685 void SetUpInProcessBrowserTestFixture() override {
686 // Handoff is only available on OSX 10.10+. This swizzle makes the logic
687 // run on all OSX versions.
688 SEL originalMethod = @selector(shouldUseHandoff);
689 SEL newMethod = @selector(new_shouldUseHandoff);
690 ExchangeSelectors(originalMethod, newMethod);
691
692 // This swizzle intercepts the URL that would be sent to the Handoff
693 // Manager, and instead puts it into a variable accessible to this test.
694 originalMethod = @selector(passURLToHandoffManager:);
695 newMethod = @selector(new_passURLToHandoffManager:);
696 ExchangeSelectors(originalMethod, newMethod);
697 }
698
699 // Closes the tab, and waits for the close to finish.
700 void CloseTab(Browser* browser, int index) {
701 content::WebContentsDestroyedWatcher destroyed_watcher(
702 browser->tab_strip_model()->GetWebContentsAt(index));
703 browser->tab_strip_model()->CloseWebContentsAt(
704 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
705 destroyed_watcher.Wait();
706 }
707};
708
709// Tests that as a user switches between tabs, navigates within a tab, and
710// switches between browser windows, the correct URL is being passed to the
711// Handoff.
712IN_PROC_BROWSER_TEST_F(AppControllerHandoffBrowserTest, TestHandoffURLs) {
svaldeza01f7d92015-11-18 17:47:56713 ASSERT_TRUE(embedded_test_server()->Start());
erikchen600f7962014-12-12 00:17:38714 EXPECT_EQ(g_handoff_url, GURL(url::kAboutBlankURL));
715
716 // Test that navigating to a URL updates the handoff URL.
717 GURL test_url1 = embedded_test_server()->GetURL("/title1.html");
718 ui_test_utils::NavigateToURL(browser(), test_url1);
719 EXPECT_EQ(g_handoff_url, test_url1);
720
721 // Test that opening a new tab updates the handoff URL.
722 GURL test_url2 = embedded_test_server()->GetURL("/title2.html");
cm.sanchi2522bc92017-12-04 08:04:13723 NavigateParams params(browser(), test_url2, ui::PAGE_TRANSITION_LINK);
nick3b04f322016-08-31 19:29:19724 params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
erikchen600f7962014-12-12 00:17:38725 ui_test_utils::NavigateToURL(&params);
726 EXPECT_EQ(g_handoff_url, test_url2);
727
728 // Test that switching tabs updates the handoff URL.
729 browser()->tab_strip_model()->ActivateTabAt(0, true);
730 EXPECT_EQ(g_handoff_url, test_url1);
731
732 // Test that closing the current tab updates the handoff URL.
733 CloseTab(browser(), 0);
734 EXPECT_EQ(g_handoff_url, test_url2);
735
736 // Test that opening a new browser window updates the handoff URL.
737 GURL test_url3 = embedded_test_server()->GetURL("/title3.html");
738 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19739 browser(), GURL(test_url3), WindowOpenDisposition::NEW_WINDOW,
erikchen600f7962014-12-12 00:17:38740 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
741 EXPECT_EQ(g_handoff_url, test_url3);
742
743 // Check that there are exactly 2 browsers.
scottmg0d8e4ab2016-01-28 00:34:55744 BrowserList* active_browser_list = BrowserList::GetInstance();
erikchen600f7962014-12-12 00:17:38745 EXPECT_EQ(2u, active_browser_list->size());
746
erikchen64a6d442015-07-10 19:38:20747 // Close the second browser window (which only has 1 tab left).
erikchen600f7962014-12-12 00:17:38748 Browser* browser2 = active_browser_list->get(1);
erikchen64a6d442015-07-10 19:38:20749 CloseBrowserSynchronously(browser2);
erikchen600f7962014-12-12 00:17:38750 EXPECT_EQ(g_handoff_url, test_url2);
751
752 // The URLs of incognito windows should not be passed to Handoff.
753 GURL test_url4 = embedded_test_server()->GetURL("/simple.html");
754 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19755 browser(), GURL(test_url4), WindowOpenDisposition::OFF_THE_RECORD,
erikchen600f7962014-12-12 00:17:38756 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
757 EXPECT_EQ(g_handoff_url, GURL());
758
759 // Open a new tab in the incognito window.
760 EXPECT_EQ(2u, active_browser_list->size());
761 Browser* browser3 = active_browser_list->get(1);
762 ui_test_utils::NavigateToURLWithDisposition(
nick3b04f322016-08-31 19:29:19763 browser3, test_url4, WindowOpenDisposition::NEW_FOREGROUND_TAB,
erikchen600f7962014-12-12 00:17:38764 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
765 EXPECT_EQ(g_handoff_url, GURL());
766
767 // Navigate the current tab in the incognito window.
thestig53986dc2014-12-16 06:09:18768 ui_test_utils::NavigateToURL(browser3, test_url1);
erikchen600f7962014-12-12 00:17:38769 EXPECT_EQ(g_handoff_url, GURL());
770
771 // Activate the original browser window.
772 Browser* browser1 = active_browser_list->get(0);
773 browser1->window()->Show();
774 EXPECT_EQ(g_handoff_url, test_url2);
775}
776
777} // namespace