blob: c30415124e02ab0f26a16fee76eee2b15ba86790 [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>
[email protected]fc44f242012-02-14 16:54:3911
12#include "base/command_line.h"
[email protected]66791aff2014-04-29 09:45:3813#include "base/mac/foundation_util.h"
[email protected]a8522032013-06-24 22:51:4614#include "base/mac/scoped_nsobject.h"
[email protected]7108d912014-01-30 08:10:4515#include "base/prefs/pref_service.h"
thestigaf7f4152014-10-31 23:19:1516#include "base/run_loop.h"
lgarron9e6dee22014-11-18 01:03:3917#include "base/strings/sys_string_conversions.h"
18#include "base/strings/utf_string_conversions.h"
[email protected]fc44f242012-02-14 16:54:3919#include "chrome/app/chrome_command_ids.h"
20#import "chrome/browser/app_controller_mac.h"
[email protected]bb4bec02013-08-15 11:26:5821#include "chrome/browser/apps/app_browsertest_util.h"
lgarron9e6dee22014-11-18 01:03:3922#include "chrome/browser/bookmarks/bookmark_model_factory.h"
[email protected]dbb03fb2014-02-15 05:36:3323#include "chrome/browser/browser_process.h"
mlerman8ae56aa2015-04-24 13:56:2724#include "chrome/browser/history/history_service_factory.h"
[email protected]7108d912014-01-30 08:10:4525#include "chrome/browser/profiles/profile_manager.h"
[email protected]52877dbc62012-06-29 22:22:0326#include "chrome/browser/ui/browser.h"
27#include "chrome/browser/ui/browser_list.h"
thestige80821242015-09-30 23:46:0828#include "chrome/browser/ui/browser_navigator_params.h"
[email protected]ee9ccfd42013-07-23 02:31:4729#include "chrome/browser/ui/browser_window.h"
lgarron9e6dee22014-11-18 01:03:3930#include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
mlerman8ae56aa2015-04-24 13:56:2731#include "chrome/browser/ui/cocoa/history_menu_bridge.h"
andybons346c7c62015-08-13 15:18:0332#include "chrome/browser/ui/cocoa/run_loop_testing.h"
[email protected]b4207c42013-02-12 06:44:2033#include "chrome/browser/ui/host_desktop.h"
[email protected]617ee962013-01-29 20:49:1234#include "chrome/browser/ui/tabs/tab_strip_model.h"
mlermane29d0032014-09-24 19:31:2635#include "chrome/browser/ui/user_manager.h"
[email protected]7108d912014-01-30 08:10:4536#include "chrome/common/chrome_constants.h"
37#include "chrome/common/chrome_switches.h"
38#include "chrome/common/pref_names.h"
[email protected]66791aff2014-04-29 09:45:3839#include "chrome/common/url_constants.h"
[email protected]fc44f242012-02-14 16:54:3940#include "chrome/test/base/in_process_browser_test.h"
erikchen600f7962014-12-12 00:17:3841#include "chrome/test/base/ui_test_utils.h"
tapted574f09c2015-05-19 13:08:0842#include "components/bookmarks/browser/bookmark_model.h"
lgarron9e6dee22014-11-18 01:03:3943#include "components/bookmarks/test/bookmark_test_helpers.h"
[email protected]29896ee2014-06-17 17:20:5344#include "components/signin/core/common/profile_management_switches.h"
[email protected]fc44f242012-02-14 16:54:3945#include "content/public/browser/web_contents.h"
erikchen600f7962014-12-12 00:17:3846#include "content/public/test/browser_test_utils.h"
erikchen19ee3922014-10-31 19:14:2247#include "content/public/test/test_navigation_observer.h"
hashimotoad3c6872014-08-29 09:46:5748#include "extensions/browser/app_window/app_window_registry.h"
[email protected]e4452d32013-11-15 23:07:4149#include "extensions/common/extension.h"
lfg910f2f92014-09-19 05:31:0950#include "extensions/test/extension_test_message_listener.h"
[email protected]66791aff2014-04-29 09:45:3851#include "net/test/embedded_test_server/embedded_test_server.h"
52
53namespace {
54
55GURL g_open_shortcut_url = GURL::EmptyGURL();
56
erikchen19ee3922014-10-31 19:14:2257// Returns an Apple Event that instructs the application to open |url|.
58NSAppleEventDescriptor* AppleEventToOpenUrl(const GURL& url) {
59 NSAppleEventDescriptor* shortcut_event = [[[NSAppleEventDescriptor alloc]
60 initWithEventClass:kASAppleScriptSuite
61 eventID:kASSubroutineEvent
62 targetDescriptor:nil
63 returnID:kAutoGenerateReturnID
64 transactionID:kAnyTransactionID] autorelease];
65 NSString* url_string = [NSString stringWithUTF8String:url.spec().c_str()];
66 [shortcut_event setParamDescriptor:[NSAppleEventDescriptor
67 descriptorWithString:url_string]
68 forKeyword:keyDirectObject];
69 return shortcut_event;
70}
71
72// Instructs the NSApp's delegate to open |url|.
73void SendAppleEventToOpenUrlToAppController(const GURL& url) {
74 AppController* controller =
75 base::mac::ObjCCast<AppController>([NSApp delegate]);
76 Method get_url =
77 class_getInstanceMethod([controller class], @selector(getUrl:withReply:));
78
79 ASSERT_TRUE(get_url);
80
81 NSAppleEventDescriptor* shortcut_event = AppleEventToOpenUrl(url);
82
83 method_invoke(controller, get_url, shortcut_event, NULL);
84}
85
mlerman8ae56aa2015-04-24 13:56:2786void RunClosureWhenProfileInitialized(const base::Closure& closure,
87 Profile* profile,
88 Profile::CreateStatus status) {
89 if (status == Profile::CREATE_STATUS_INITIALIZED)
90 closure.Run();
91}
92
[email protected]66791aff2014-04-29 09:45:3893} // namespace
94
95@interface TestOpenShortcutOnStartup : NSObject
96- (void)applicationWillFinishLaunching:(NSNotification*)notification;
97@end
98
99@implementation TestOpenShortcutOnStartup
100
101- (void)applicationWillFinishLaunching:(NSNotification*)notification {
102 if (!g_open_shortcut_url.is_valid())
103 return;
104
erikchen19ee3922014-10-31 19:14:22105 SendAppleEventToOpenUrlToAppController(g_open_shortcut_url);
[email protected]66791aff2014-04-29 09:45:38106}
107
108@end
[email protected]fc44f242012-02-14 16:54:39109
110namespace {
111
[email protected]ee9ccfd42013-07-23 02:31:47112class AppControllerPlatformAppBrowserTest
113 : public extensions::PlatformAppBrowserTest {
[email protected]fc44f242012-02-14 16:54:39114 protected:
[email protected]b4207c42013-02-12 06:44:20115 AppControllerPlatformAppBrowserTest()
[email protected]7d1a810b2013-06-26 19:51:59116 : active_browser_list_(BrowserList::GetInstance(
[email protected]ed2fa722013-06-25 20:37:34117 chrome::GetActiveDesktop())) {
[email protected]b4207c42013-02-12 06:44:20118 }
[email protected]fc44f242012-02-14 16:54:39119
avi3ef9ec9e2014-12-22 22:50:17120 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]ee9ccfd42013-07-23 02:31:47121 PlatformAppBrowserTest::SetUpCommandLine(command_line);
[email protected]fc44f242012-02-14 16:54:39122 command_line->AppendSwitchASCII(switches::kAppId,
123 "1234");
124 }
[email protected]b4207c42013-02-12 06:44:20125
[email protected]7d1a810b2013-06-26 19:51:59126 const BrowserList* active_browser_list_;
[email protected]fc44f242012-02-14 16:54:39127};
128
129// Test that if only a platform app window is open and no browser windows are
130// open then a reopen event does nothing.
131IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
132 PlatformAppReopenWithWindows) {
[email protected]a8522032013-06-24 22:51:46133 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
[email protected]fc44f242012-02-14 16:54:39134 NSUInteger old_window_count = [[NSApp windows] count];
[email protected]7d1a810b2013-06-26 19:51:59135 EXPECT_EQ(1u, active_browser_list_->size());
[email protected]a25920ee2013-09-05 19:38:49136 [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:YES];
137 // We do not EXPECT_TRUE the result here because the method
138 // deminiaturizes windows manually rather than return YES and have
139 // AppKit do it.
[email protected]fc44f242012-02-14 16:54:39140
[email protected]fc44f242012-02-14 16:54:39141 EXPECT_EQ(old_window_count, [[NSApp windows] count]);
[email protected]7d1a810b2013-06-26 19:51:59142 EXPECT_EQ(1u, active_browser_list_->size());
[email protected]fc44f242012-02-14 16:54:39143}
144
[email protected]2e29e2232013-07-26 10:40:59145IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
146 ActivationFocusesBrowserWindow) {
147 base::scoped_nsobject<AppController> app_controller(
148 [[AppController alloc] init]);
149
150 ExtensionTestMessageListener listener("Launched", false);
151 const extensions::Extension* app =
152 InstallAndLaunchPlatformApp("minimal");
153 ASSERT_TRUE(listener.WaitUntilSatisfied());
154
hashimotoad3c6872014-08-29 09:46:57155 NSWindow* app_window = extensions::AppWindowRegistry::Get(profile())
[email protected]dbb03fb2014-02-15 05:36:33156 ->GetAppWindowsForApp(app->id())
157 .front()
158 ->GetNativeWindow();
[email protected]2e29e2232013-07-26 10:40:59159 NSWindow* browser_window = browser()->window()->GetNativeWindow();
160
andybons346c7c62015-08-13 15:18:03161 chrome::testing::NSRunLoopRunAllPending();
[email protected]2e29e2232013-07-26 10:40:59162 EXPECT_LE([[NSApp orderedWindows] indexOfObject:app_window],
163 [[NSApp orderedWindows] indexOfObject:browser_window]);
164 [app_controller applicationShouldHandleReopen:NSApp
165 hasVisibleWindows:YES];
andybons346c7c62015-08-13 15:18:03166 chrome::testing::NSRunLoopRunAllPending();
[email protected]2e29e2232013-07-26 10:40:59167 EXPECT_LE([[NSApp orderedWindows] indexOfObject:browser_window],
168 [[NSApp orderedWindows] indexOfObject:app_window]);
169}
170
[email protected]fc44f242012-02-14 16:54:39171class AppControllerWebAppBrowserTest : public InProcessBrowserTest {
172 protected:
[email protected]b4207c42013-02-12 06:44:20173 AppControllerWebAppBrowserTest()
[email protected]7d1a810b2013-06-26 19:51:59174 : active_browser_list_(BrowserList::GetInstance(
[email protected]ed2fa722013-06-25 20:37:34175 chrome::GetActiveDesktop())) {
[email protected]b4207c42013-02-12 06:44:20176 }
[email protected]fc44f242012-02-14 16:54:39177
avi3ef9ec9e2014-12-22 22:50:17178 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]90ca44272012-07-18 18:15:48179 command_line->AppendSwitchASCII(switches::kApp, GetAppURL());
[email protected]fc44f242012-02-14 16:54:39180 }
181
182 std::string GetAppURL() const {
183 return "http://example.com/";
184 }
[email protected]b4207c42013-02-12 06:44:20185
[email protected]7d1a810b2013-06-26 19:51:59186 const BrowserList* active_browser_list_;
[email protected]fc44f242012-02-14 16:54:39187};
188
189// Test that in web app mode a reopen event opens the app URL.
190IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest,
191 WebAppReopenWithNoWindows) {
[email protected]a8522032013-06-24 22:51:46192 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
[email protected]7d1a810b2013-06-26 19:51:59193 EXPECT_EQ(1u, active_browser_list_->size());
[email protected]fc44f242012-02-14 16:54:39194 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
195
196 EXPECT_FALSE(result);
[email protected]7d1a810b2013-06-26 19:51:59197 EXPECT_EQ(2u, active_browser_list_->size());
[email protected]fc44f242012-02-14 16:54:39198
[email protected]7d1a810b2013-06-26 19:51:59199 Browser* browser = active_browser_list_->get(0);
[email protected]617ee962013-01-29 20:49:12200 GURL current_url =
201 browser->tab_strip_model()->GetActiveWebContents()->GetURL();
[email protected]fc44f242012-02-14 16:54:39202 EXPECT_EQ(GetAppURL(), current_url.spec());
203}
204
[email protected]7108d912014-01-30 08:10:45205// Called when the ProfileManager has created a profile.
206void CreateProfileCallback(const base::Closure& quit_closure,
207 Profile* profile,
208 Profile::CreateStatus status) {
209 EXPECT_TRUE(profile);
210 EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status);
211 EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status);
212 // This will be called multiple times. Wait until the profile is initialized
213 // fully to quit the loop.
214 if (status == Profile::CREATE_STATUS_INITIALIZED)
215 quit_closure.Run();
216}
217
mlermanb8df6e82015-01-23 19:55:34218void CreateAndWaitForSystemProfile() {
[email protected]7108d912014-01-30 08:10:45219 ProfileManager::CreateCallback create_callback =
220 base::Bind(&CreateProfileCallback,
221 base::MessageLoop::current()->QuitClosure());
222 g_browser_process->profile_manager()->CreateProfileAsync(
mlermanb8df6e82015-01-23 19:55:34223 ProfileManager::GetSystemProfilePath(),
[email protected]7108d912014-01-30 08:10:45224 create_callback,
225 base::string16(),
226 base::string16(),
227 std::string());
228 base::RunLoop().Run();
229}
230
231class AppControllerNewProfileManagementBrowserTest
232 : public InProcessBrowserTest {
233 protected:
234 AppControllerNewProfileManagementBrowserTest()
235 : active_browser_list_(BrowserList::GetInstance(
236 chrome::GetActiveDesktop())) {
237 }
238
avi3ef9ec9e2014-12-22 22:50:17239 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]29896ee2014-06-17 17:20:53240 switches::EnableNewProfileManagementForTesting(command_line);
[email protected]7108d912014-01-30 08:10:45241 }
242
243 const BrowserList* active_browser_list_;
244};
245
246// Test that for a regular last profile, a reopen event opens a browser.
247IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
248 RegularProfileReopenWithNoWindows) {
249 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
250 EXPECT_EQ(1u, active_browser_list_->size());
251 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
252
253 EXPECT_FALSE(result);
254 EXPECT_EQ(2u, active_browser_list_->size());
mlermane29d0032014-09-24 19:31:26255 EXPECT_FALSE(UserManager::IsShowing());
[email protected]7108d912014-01-30 08:10:45256}
257
258// Test that for a locked last profile, a reopen event opens the User Manager.
259IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
260 LockedProfileReopenWithNoWindows) {
mlermanb8df6e82015-01-23 19:55:34261 // The User Manager uses the system profile as its underlying profile. To
[email protected]7108d912014-01-30 08:10:45262 // minimize flakiness due to the scheduling/descheduling of tasks on the
263 // different threads, pre-initialize the guest profile before it is needed.
mlermanb8df6e82015-01-23 19:55:34264 CreateAndWaitForSystemProfile();
[email protected]7108d912014-01-30 08:10:45265 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
266
267 // Lock the active profile.
268 Profile* profile = [ac lastProfile];
269 ProfileInfoCache& cache =
270 g_browser_process->profile_manager()->GetProfileInfoCache();
271 size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
272 cache.SetProfileSigninRequiredAtIndex(profile_index, true);
273 EXPECT_TRUE(cache.ProfileIsSigninRequiredAtIndex(profile_index));
274
275 EXPECT_EQ(1u, active_browser_list_->size());
276 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
277 EXPECT_FALSE(result);
278
279 base::RunLoop().RunUntilIdle();
280 EXPECT_EQ(1u, active_browser_list_->size());
mlermane29d0032014-09-24 19:31:26281 EXPECT_TRUE(UserManager::IsShowing());
282 UserManager::Hide();
[email protected]7108d912014-01-30 08:10:45283}
284
285// Test that for a guest last profile, a reopen event opens the User Manager.
286IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
287 GuestProfileReopenWithNoWindows) {
mlermanb8df6e82015-01-23 19:55:34288 // Create the system profile. Set the guest as the last used profile so the
[email protected]7108d912014-01-30 08:10:45289 // app controller can use it on init.
mlermanb8df6e82015-01-23 19:55:34290 CreateAndWaitForSystemProfile();
[email protected]7108d912014-01-30 08:10:45291 PrefService* local_state = g_browser_process->local_state();
292 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
293
294 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
295
296 Profile* profile = [ac lastProfile];
297 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath());
298 EXPECT_TRUE(profile->IsGuestSession());
299
300 EXPECT_EQ(1u, active_browser_list_->size());
301 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
302 EXPECT_FALSE(result);
303
304 base::RunLoop().RunUntilIdle();
305
306 EXPECT_EQ(1u, active_browser_list_->size());
mlermane29d0032014-09-24 19:31:26307 EXPECT_TRUE(UserManager::IsShowing());
308 UserManager::Hide();
[email protected]7108d912014-01-30 08:10:45309}
310
mlermane6e040a2014-10-31 00:53:21311IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
312 AboutChromeForcesUserManager) {
313 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
314
315 // Create the guest profile, and set it as the last used profile so the
316 // app controller can use it on init.
mlermanb8df6e82015-01-23 19:55:34317 CreateAndWaitForSystemProfile();
mlermane6e040a2014-10-31 00:53:21318 PrefService* local_state = g_browser_process->local_state();
319 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
320
321 // Prohibiting guest mode forces the user manager flow for About Chrome.
322 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
323
324 Profile* guest_profile = [ac lastProfile];
325 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), guest_profile->GetPath());
326 EXPECT_TRUE(guest_profile->IsGuestSession());
327
328 // Tell the browser to open About Chrome.
329 EXPECT_EQ(1u, active_browser_list_->size());
330 [ac orderFrontStandardAboutPanel:NSApp];
331
332 base::RunLoop().RunUntilIdle();
333
334 // No new browser is opened; the User Manager opens instead.
335 EXPECT_EQ(1u, active_browser_list_->size());
336 EXPECT_TRUE(UserManager::IsShowing());
337
338 UserManager::Hide();
339}
340
[email protected]66791aff2014-04-29 09:45:38341class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest {
342 protected:
343 AppControllerOpenShortcutBrowserTest() {
344 }
345
Daniel Chenga542fca2014-10-21 09:51:29346 void SetUpInProcessBrowserTestFixture() override {
[email protected]66791aff2014-04-29 09:45:38347 // In order to mimic opening shortcut during browser startup, we need to
348 // send the event before -applicationDidFinishLaunching is called, but
349 // after AppController is loaded.
350 //
351 // Since -applicationWillFinishLaunching does nothing now, we swizzle it to
352 // our function to send the event. We need to do this early before running
353 // the main message loop.
354 //
355 // NSApp does not exist yet. We need to get the AppController using
356 // reflection.
357 Class appControllerClass = NSClassFromString(@"AppController");
358 Class openShortcutClass = NSClassFromString(@"TestOpenShortcutOnStartup");
359
360 ASSERT_TRUE(appControllerClass != nil);
361 ASSERT_TRUE(openShortcutClass != nil);
362
363 SEL targetMethod = @selector(applicationWillFinishLaunching:);
364 Method original = class_getInstanceMethod(appControllerClass,
365 targetMethod);
366 Method destination = class_getInstanceMethod(openShortcutClass,
367 targetMethod);
368
369 ASSERT_TRUE(original != NULL);
370 ASSERT_TRUE(destination != NULL);
371
372 method_exchangeImplementations(original, destination);
373
374 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
375 g_open_shortcut_url = embedded_test_server()->GetURL("/simple.html");
376 }
377
avi3ef9ec9e2014-12-22 22:50:17378 void SetUpCommandLine(base::CommandLine* command_line) override {
[email protected]66791aff2014-04-29 09:45:38379 // If the arg is empty, PrepareTestCommandLine() after this function will
380 // append about:blank as default url.
381 command_line->AppendArg(chrome::kChromeUINewTabURL);
382 }
383};
384
385IN_PROC_BROWSER_TEST_F(AppControllerOpenShortcutBrowserTest,
386 OpenShortcutOnStartup) {
387 EXPECT_EQ(1, browser()->tab_strip_model()->count());
388 EXPECT_EQ(g_open_shortcut_url,
389 browser()->tab_strip_model()->GetActiveWebContents()
390 ->GetLastCommittedURL());
391}
392
erikchen19ee3922014-10-31 19:14:22393class AppControllerReplaceNTPBrowserTest : public InProcessBrowserTest {
394 protected:
395 AppControllerReplaceNTPBrowserTest() {}
396
397 void SetUpInProcessBrowserTestFixture() override {
398 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
399 }
400
avi3ef9ec9e2014-12-22 22:50:17401 void SetUpCommandLine(base::CommandLine* command_line) override {
erikchen19ee3922014-10-31 19:14:22402 // If the arg is empty, PrepareTestCommandLine() after this function will
403 // append about:blank as default url.
404 command_line->AppendArg(chrome::kChromeUINewTabURL);
405 }
406};
407
408// Tests that when a GURL is opened after startup, it replaces the NTP.
409IN_PROC_BROWSER_TEST_F(AppControllerReplaceNTPBrowserTest,
410 ReplaceNTPAfterStartup) {
411 // Ensure that there is exactly 1 tab showing, and the tab is the NTP.
412 GURL ntp(chrome::kChromeUINewTabURL);
413 EXPECT_EQ(1, browser()->tab_strip_model()->count());
414 EXPECT_EQ(ntp,
415 browser()
416 ->tab_strip_model()
417 ->GetActiveWebContents()
418 ->GetLastCommittedURL());
419
420 GURL simple(embedded_test_server()->GetURL("/simple.html"));
421 SendAppleEventToOpenUrlToAppController(simple);
422
423 // Wait for one navigation on the active web contents.
424 EXPECT_EQ(1, browser()->tab_strip_model()->count());
425 content::TestNavigationObserver obs(
426 browser()->tab_strip_model()->GetActiveWebContents(), 1);
427 obs.Wait();
428
429 EXPECT_EQ(simple,
430 browser()
431 ->tab_strip_model()
432 ->GetActiveWebContents()
433 ->GetLastCommittedURL());
434}
435
lgarron9e6dee22014-11-18 01:03:39436class AppControllerMainMenuBrowserTest : public InProcessBrowserTest {
437 protected:
438 AppControllerMainMenuBrowserTest() {
439 }
440};
441
442IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
mlerman8ae56aa2015-04-24 13:56:27443 HistoryMenuResetAfterProfileDeletion) {
444 ProfileManager* profile_manager = g_browser_process->profile_manager();
445 AppController* ac = [NSApp delegate];
446
447 // Use the existing profile as profile 1.
448 Profile* profile1 = browser()->profile();
449
450 // Create profile 2.
451 base::FilePath profile2_path =
452 profile_manager->GenerateNextProfileDirectoryPath();
453 base::RunLoop run_loop;
454 profile_manager->CreateProfileAsync(
455 profile2_path,
456 base::Bind(&RunClosureWhenProfileInitialized,
457 run_loop.QuitClosure()),
458 base::string16(),
459 base::string16(),
460 std::string());
461 run_loop.Run();
462 Profile* profile2 = profile_manager->GetProfileByPath(profile2_path);
463 ASSERT_TRUE(profile2);
464
465 // Switch the controller to profile1.
466 [ac windowChangedToProfile:profile1];
467 base::RunLoop().RunUntilIdle();
468
469 // Verify the controller's History Menu corresponds to profile1.
470 EXPECT_TRUE([ac historyMenuBridge]->service());
471 EXPECT_EQ([ac historyMenuBridge]->service(),
472 HistoryServiceFactory::GetForProfile(profile1,
473 ServiceAccessType::EXPLICIT_ACCESS));
474
475 // Load profile2's History Service backend so it will be assigned to the
476 // HistoryMenuBridge when windowChangedToProfile is called, or else this test
477 // will fail flaky.
478 ui_test_utils::WaitForHistoryToLoad(
479 HistoryServiceFactory::GetForProfile(profile2,
480 ServiceAccessType::EXPLICIT_ACCESS));
481 // Switch the controller to profile2.
482 [ac windowChangedToProfile:profile2];
483 base::RunLoop().RunUntilIdle();
484
485 // Verify the controller's History Menu has changed.
486 EXPECT_TRUE([ac historyMenuBridge]->service());
487 EXPECT_EQ([ac historyMenuBridge]->service(),
488 HistoryServiceFactory::GetForProfile(profile2,
489 ServiceAccessType::EXPLICIT_ACCESS));
490 EXPECT_NE(
491 HistoryServiceFactory::GetForProfile(profile1,
492 ServiceAccessType::EXPLICIT_ACCESS),
493 HistoryServiceFactory::GetForProfile(profile2,
494 ServiceAccessType::EXPLICIT_ACCESS));
495
496 // Delete profile2.
497 profile_manager->ScheduleProfileForDeletion(
498 profile2->GetPath(), ProfileManager::CreateCallback());
499 base::RunLoop().RunUntilIdle();
500
501 // Verify the controller's history is back to profile1.
502 EXPECT_EQ([ac historyMenuBridge]->service(),
503 HistoryServiceFactory::GetForProfile(profile1,
504 ServiceAccessType::EXPLICIT_ACCESS));
505}
506
507IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
lgarron9e6dee22014-11-18 01:03:39508 BookmarksMenuIsRestoredAfterProfileSwitch) {
509 ProfileManager* profile_manager = g_browser_process->profile_manager();
510 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
511 [ac awakeFromNib];
512
513 // Constants for bookmarks that we will create later.
514 const base::string16 title1(base::ASCIIToUTF16("Dinosaur Comics"));
515 const GURL url1("http://qwantz.com//");
516
517 const base::string16 title2(base::ASCIIToUTF16("XKCD"));
518 const GURL url2("https://www.xkcd.com/");
519
520 // Use the existing profile as profile 1.
521 Profile* profile1 = browser()->profile();
522 bookmarks::test::WaitForBookmarkModelToLoad(
523 BookmarkModelFactory::GetForProfile(profile1));
524
525 // Create profile 2.
526 base::FilePath path2 = profile_manager->GenerateNextProfileDirectoryPath();
527 Profile* profile2 =
528 Profile::CreateProfile(path2, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
529 profile_manager->RegisterTestingProfile(profile2, false, true);
530 bookmarks::test::WaitForBookmarkModelToLoad(
531 BookmarkModelFactory::GetForProfile(profile2));
532
533 // Switch to profile 1, create bookmark 1 and force the menu to build.
534 [ac windowChangedToProfile:profile1];
535 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
536 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
537 0, title1, url1);
538 [ac bookmarkMenuBridge]->BuildMenu();
539
540 // Switch to profile 2, create bookmark 2 and force the menu to build.
541 [ac windowChangedToProfile:profile2];
542 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
543 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
544 0, title2, url2);
545 [ac bookmarkMenuBridge]->BuildMenu();
546
547 // Test that only bookmark 2 is shown.
548 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
549 SysUTF16ToNSString(title1)]);
550 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
551 SysUTF16ToNSString(title2)]);
552
553 // Switch *back* to profile 1 and *don't* force the menu to build.
554 [ac windowChangedToProfile:profile1];
555
556 // Test that only bookmark 1 is shown in the restored menu.
557 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
558 SysUTF16ToNSString(title1)]);
559 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
560 SysUTF16ToNSString(title2)]);
561}
562
[email protected]fc44f242012-02-14 16:54:39563} // namespace
erikchen600f7962014-12-12 00:17:38564
565//--------------------------AppControllerHandoffBrowserTest---------------------
566
567static GURL g_handoff_url;
568
569@interface AppController (BrowserTest)
570- (BOOL)new_shouldUseHandoff;
571- (void)new_passURLToHandoffManager:(const GURL&)handoffURL;
572@end
573
574@implementation AppController (BrowserTest)
575- (BOOL)new_shouldUseHandoff {
576 return YES;
577}
578
579- (void)new_passURLToHandoffManager:(const GURL&)handoffURL {
580 g_handoff_url = handoffURL;
581}
582@end
583
584namespace {
585
586class AppControllerHandoffBrowserTest : public InProcessBrowserTest {
587 protected:
588 AppControllerHandoffBrowserTest() {}
589
590 // Exchanges the implementations of the two selectors on the class
591 // AppController.
592 void ExchangeSelectors(SEL originalMethod, SEL newMethod) {
593 Class appControllerClass = NSClassFromString(@"AppController");
594
595 ASSERT_TRUE(appControllerClass != nil);
596
597 Method original =
598 class_getInstanceMethod(appControllerClass, originalMethod);
599 Method destination = class_getInstanceMethod(appControllerClass, newMethod);
600
601 ASSERT_TRUE(original != NULL);
602 ASSERT_TRUE(destination != NULL);
603
604 method_exchangeImplementations(original, destination);
605 }
606
607 // Swizzle Handoff related implementations.
608 void SetUpInProcessBrowserTestFixture() override {
609 // Handoff is only available on OSX 10.10+. This swizzle makes the logic
610 // run on all OSX versions.
611 SEL originalMethod = @selector(shouldUseHandoff);
612 SEL newMethod = @selector(new_shouldUseHandoff);
613 ExchangeSelectors(originalMethod, newMethod);
614
615 // This swizzle intercepts the URL that would be sent to the Handoff
616 // Manager, and instead puts it into a variable accessible to this test.
617 originalMethod = @selector(passURLToHandoffManager:);
618 newMethod = @selector(new_passURLToHandoffManager:);
619 ExchangeSelectors(originalMethod, newMethod);
620 }
621
622 // Closes the tab, and waits for the close to finish.
623 void CloseTab(Browser* browser, int index) {
624 content::WebContentsDestroyedWatcher destroyed_watcher(
625 browser->tab_strip_model()->GetWebContentsAt(index));
626 browser->tab_strip_model()->CloseWebContentsAt(
627 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
628 destroyed_watcher.Wait();
629 }
630};
631
632// Tests that as a user switches between tabs, navigates within a tab, and
633// switches between browser windows, the correct URL is being passed to the
634// Handoff.
635IN_PROC_BROWSER_TEST_F(AppControllerHandoffBrowserTest, TestHandoffURLs) {
636 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
637 EXPECT_EQ(g_handoff_url, GURL(url::kAboutBlankURL));
638
639 // Test that navigating to a URL updates the handoff URL.
640 GURL test_url1 = embedded_test_server()->GetURL("/title1.html");
641 ui_test_utils::NavigateToURL(browser(), test_url1);
642 EXPECT_EQ(g_handoff_url, test_url1);
643
644 // Test that opening a new tab updates the handoff URL.
645 GURL test_url2 = embedded_test_server()->GetURL("/title2.html");
646 chrome::NavigateParams params(browser(), test_url2, ui::PAGE_TRANSITION_LINK);
647 params.disposition = NEW_FOREGROUND_TAB;
648 ui_test_utils::NavigateToURL(&params);
649 EXPECT_EQ(g_handoff_url, test_url2);
650
651 // Test that switching tabs updates the handoff URL.
652 browser()->tab_strip_model()->ActivateTabAt(0, true);
653 EXPECT_EQ(g_handoff_url, test_url1);
654
655 // Test that closing the current tab updates the handoff URL.
656 CloseTab(browser(), 0);
657 EXPECT_EQ(g_handoff_url, test_url2);
658
659 // Test that opening a new browser window updates the handoff URL.
660 GURL test_url3 = embedded_test_server()->GetURL("/title3.html");
661 ui_test_utils::NavigateToURLWithDisposition(
662 browser(), GURL(test_url3), NEW_WINDOW,
663 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
664 EXPECT_EQ(g_handoff_url, test_url3);
665
666 // Check that there are exactly 2 browsers.
667 BrowserList* active_browser_list =
668 BrowserList::GetInstance(chrome::GetActiveDesktop());
669 EXPECT_EQ(2u, active_browser_list->size());
670
erikchen64a6d442015-07-10 19:38:20671 // Close the second browser window (which only has 1 tab left).
erikchen600f7962014-12-12 00:17:38672 Browser* browser2 = active_browser_list->get(1);
erikchen64a6d442015-07-10 19:38:20673 CloseBrowserSynchronously(browser2);
erikchen600f7962014-12-12 00:17:38674 EXPECT_EQ(g_handoff_url, test_url2);
675
676 // The URLs of incognito windows should not be passed to Handoff.
677 GURL test_url4 = embedded_test_server()->GetURL("/simple.html");
678 ui_test_utils::NavigateToURLWithDisposition(
679 browser(), GURL(test_url4), OFF_THE_RECORD,
680 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
681 EXPECT_EQ(g_handoff_url, GURL());
682
683 // Open a new tab in the incognito window.
684 EXPECT_EQ(2u, active_browser_list->size());
685 Browser* browser3 = active_browser_list->get(1);
686 ui_test_utils::NavigateToURLWithDisposition(
687 browser3, test_url4, NEW_FOREGROUND_TAB,
688 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
689 EXPECT_EQ(g_handoff_url, GURL());
690
691 // Navigate the current tab in the incognito window.
thestig53986dc2014-12-16 06:09:18692 ui_test_utils::NavigateToURL(browser3, test_url1);
erikchen600f7962014-12-12 00:17:38693 EXPECT_EQ(g_handoff_url, GURL());
694
695 // Activate the original browser window.
696 Browser* browser1 = active_browser_list->get(0);
697 browser1->window()->Show();
698 EXPECT_EQ(g_handoff_url, test_url2);
699}
700
701} // namespace