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. 4 5#import <Carbon/Carbon.h> 6#import <Cocoa/Cocoa.h> 7#import <Foundation/Foundation.h> 8#import <Foundation/NSAppleEventDescriptor.h> 9#import <objc/message.h> 10#import <objc/runtime.h> 11#include <stddef.h> 12 13#include "base/bind.h" 14#include "base/callback_helpers.h" 15#include "base/command_line.h" 16#include "base/mac/foundation_util.h" 17#include "base/mac/scoped_nsobject.h" 18#include "base/run_loop.h" 19#include "base/strings/string16.h" 20#include "base/strings/sys_string_conversions.h" 21#include "base/strings/utf_string_conversions.h" 22#include "base/test/scoped_feature_list.h" 23#include "base/threading/thread_restrictions.h" 24#include "chrome/app/chrome_command_ids.h" 25#import "chrome/browser/app_controller_mac.h" 26#include "chrome/browser/apps/platform_apps/app_browsertest_util.h" 27#include "chrome/browser/bookmarks/bookmark_model_factory.h" 28#include "chrome/browser/browser_process.h" 29#include "chrome/browser/history/history_service_factory.h" 30#include "chrome/browser/lifetime/application_lifetime.h" 31#include "chrome/browser/profiles/profile_attributes_entry.h" 32#include "chrome/browser/profiles/profile_attributes_storage.h" 33#include "chrome/browser/profiles/profile_manager.h" 34#include "chrome/browser/signin/signin_util.h" 35#include "chrome/browser/ui/browser.h" 36#include "chrome/browser/ui/browser_finder.h" 37#include "chrome/browser/ui/browser_list.h" 38#include "chrome/browser/ui/browser_navigator_params.h" 39#include "chrome/browser/ui/browser_window.h" 40#include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h" 41#include "chrome/browser/ui/cocoa/history_menu_bridge.h" 42#include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h" 43#include "chrome/browser/ui/cocoa/test/run_loop_testing.h" 44#include "chrome/browser/ui/profile_picker.h" 45#include "chrome/browser/ui/search/local_ntp_test_utils.h" 46#include "chrome/browser/ui/tabs/tab_strip_model.h" 47#include "chrome/browser/ui/ui_features.h" 48#include "chrome/browser/ui/user_manager.h" 49#include "chrome/browser/ui/webui/welcome/helpers.h" 50#include "chrome/common/chrome_constants.h" 51#include "chrome/common/chrome_switches.h" 52#include "chrome/common/pref_names.h" 53#include "chrome/common/url_constants.h" 54#include "chrome/test/base/in_process_browser_test.h" 55#include "chrome/test/base/ui_test_utils.h" 56#include "components/account_id/account_id.h" 57#include "components/bookmarks/browser/bookmark_model.h" 58#include "components/bookmarks/test/bookmark_test_helpers.h" 59#include "components/prefs/pref_service.h" 60#include "content/public/browser/navigation_controller.h" 61#include "content/public/browser/web_contents.h" 62#include "content/public/test/browser_test.h" 63#include "content/public/test/browser_test_utils.h" 64#include "content/public/test/test_navigation_observer.h" 65#include "extensions/browser/app_window/app_window_registry.h" 66#include "extensions/common/extension.h" 67#include "extensions/test/extension_test_message_listener.h" 68#include "net/test/embedded_test_server/embedded_test_server.h" 69#import "ui/events/test/cocoa_test_event_utils.h" 70 71using base::SysUTF16ToNSString; 72 73@interface AppController (ForTesting) 74- (void)getUrl:(NSAppleEventDescriptor*)event 75 withReply:(NSAppleEventDescriptor*)reply; 76@end 77 78namespace { 79 80GURL g_open_shortcut_url = GURL::EmptyGURL(); 81 82// Returns an Apple Event that instructs the application to open |url|. 83NSAppleEventDescriptor* AppleEventToOpenUrl(const GURL& url) { 84 NSAppleEventDescriptor* shortcut_event = [[[NSAppleEventDescriptor alloc] 85 initWithEventClass:kASAppleScriptSuite 86 eventID:kASSubroutineEvent 87 targetDescriptor:nil 88 returnID:kAutoGenerateReturnID 89 transactionID:kAnyTransactionID] autorelease]; 90 NSString* url_string = [NSString stringWithUTF8String:url.spec().c_str()]; 91 [shortcut_event setParamDescriptor:[NSAppleEventDescriptor 92 descriptorWithString:url_string] 93 forKeyword:keyDirectObject]; 94 return shortcut_event; 95} 96 97// Instructs the NSApp's delegate to open |url|. 98void SendAppleEventToOpenUrlToAppController(const GURL& url) { 99 AppController* controller = 100 base::mac::ObjCCast<AppController>([NSApp delegate]); 101 [controller getUrl:AppleEventToOpenUrl(url) withReply:nullptr]; 102} 103 104void RunClosureWhenProfileInitialized(const base::RepeatingClosure& closure, 105 Profile* profile, 106 Profile::CreateStatus status) { 107 // This will be called multiple times. Wait until the profile is initialized 108 // fully to quit the loop. 109 if (status == Profile::CREATE_STATUS_INITIALIZED) 110 closure.Run(); 111} 112 113} // namespace 114 115@interface TestOpenShortcutOnStartup : NSObject 116- (void)applicationWillFinishLaunching:(NSNotification*)notification; 117@end 118 119@implementation TestOpenShortcutOnStartup 120 121- (void)applicationWillFinishLaunching:(NSNotification*)notification { 122 if (!g_open_shortcut_url.is_valid()) 123 return; 124 125 SendAppleEventToOpenUrlToAppController(g_open_shortcut_url); 126} 127 128@end 129 130namespace { 131 132using AppControllerBrowserTest = InProcessBrowserTest; 133 134// Returns whether a window's pixels are actually on the screen, which is the 135// case when it and all of its parents are marked visible. 136bool IsReallyVisible(NSWindow* window) { 137 while (window) { 138 if (!window.visible) 139 return false; 140 window = [window parentWindow]; 141 } 142 return true; 143} 144 145size_t CountVisibleWindows() { 146 size_t count = 0; 147 for (NSWindow* w in [NSApp windows]) 148 count = count + (IsReallyVisible(w) ? 1 : 0); 149 return count; 150} 151 152// Returns how many visible NSWindows are expected for a given count of browser 153// windows. 154size_t ExpectedWindowCountForBrowserCount(size_t browsers) { 155 return browsers; 156} 157 158// Test browser shutdown with a command in the message queue. 159IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest, CommandDuringShutdown) { 160 EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); 161 EXPECT_EQ(ExpectedWindowCountForBrowserCount(1), CountVisibleWindows()); 162 163 chrome::AttemptExit(); // Set chrome::IsTryingToQuit and close all windows. 164 165 // Opening a new window here is fine (unload handlers can also interrupt 166 // exit). But closing the window posts an autorelease on 167 // BrowserWindowController, which calls ~Browser() and, if that was the last 168 // Browser, it invokes applicationWillTerminate: (because IsTryingToQuit is 169 // set). So, verify assumptions then process that autorelease. 170 171 EXPECT_EQ(1u, chrome::GetTotalBrowserCount()); 172 EXPECT_EQ(ExpectedWindowCountForBrowserCount(0), CountVisibleWindows()); 173 174 base::RunLoop().RunUntilIdle(); 175 176 EXPECT_EQ(0u, chrome::GetTotalBrowserCount()); 177 EXPECT_EQ(ExpectedWindowCountForBrowserCount(0), CountVisibleWindows()); 178 179 NSEvent* cmd_n = cocoa_test_event_utils::KeyEventWithKeyCode( 180 'n', 'n', NSKeyDown, NSCommandKeyMask); 181 [[NSApp mainMenu] performSelector:@selector(performKeyEquivalent:) 182 withObject:cmd_n 183 afterDelay:0]; 184 // Let the run loop get flushed, during process cleanup and try not to crash. 185} 186 187class AppControllerPlatformAppBrowserTest 188 : public extensions::PlatformAppBrowserTest { 189 protected: 190 AppControllerPlatformAppBrowserTest() 191 : active_browser_list_(BrowserList::GetInstance()) {} 192 193 void SetUpCommandLine(base::CommandLine* command_line) override { 194 PlatformAppBrowserTest::SetUpCommandLine(command_line); 195 command_line->AppendSwitchASCII(switches::kAppId, 196 "1234"); 197 } 198 199 const BrowserList* active_browser_list_; 200}; 201 202// Test that if only a platform app window is open and no browser windows are 203// open then a reopen event does nothing. 204IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest, 205 DISABLED_PlatformAppReopenWithWindows) { 206 AppController* ac = base::mac::ObjCCast<AppController>( 207 [[NSApplication sharedApplication] delegate]); 208 ASSERT_TRUE(ac); 209 210 NSUInteger old_window_count = [[NSApp windows] count]; 211 EXPECT_EQ(1u, active_browser_list_->size()); 212 [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:YES]; 213 // We do not EXPECT_TRUE the result here because the method 214 // deminiaturizes windows manually rather than return YES and have 215 // AppKit do it. 216 217 EXPECT_EQ(old_window_count, [[NSApp windows] count]); 218 EXPECT_EQ(1u, active_browser_list_->size()); 219} 220 221IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest, 222 DISABLED_ActivationFocusesBrowserWindow) { 223 AppController* app_controller = base::mac::ObjCCast<AppController>( 224 [[NSApplication sharedApplication] delegate]); 225 ASSERT_TRUE(app_controller); 226 227 ExtensionTestMessageListener listener("Launched", false); 228 const extensions::Extension* app = 229 InstallAndLaunchPlatformApp("minimal"); 230 ASSERT_TRUE(listener.WaitUntilSatisfied()); 231 232 NSWindow* app_window = extensions::AppWindowRegistry::Get(profile()) 233 ->GetAppWindowsForApp(app->id()) 234 .front() 235 ->GetNativeWindow() 236 .GetNativeNSWindow(); 237 NSWindow* browser_window = 238 browser()->window()->GetNativeWindow().GetNativeNSWindow(); 239 240 chrome::testing::NSRunLoopRunAllPending(); 241 EXPECT_LE([[NSApp orderedWindows] indexOfObject:app_window], 242 [[NSApp orderedWindows] indexOfObject:browser_window]); 243 [app_controller applicationShouldHandleReopen:NSApp 244 hasVisibleWindows:YES]; 245 chrome::testing::NSRunLoopRunAllPending(); 246 EXPECT_LE([[NSApp orderedWindows] indexOfObject:browser_window], 247 [[NSApp orderedWindows] indexOfObject:app_window]); 248} 249 250class AppControllerWebAppBrowserTest : public InProcessBrowserTest { 251 protected: 252 AppControllerWebAppBrowserTest() 253 : active_browser_list_(BrowserList::GetInstance()) {} 254 255 void SetUpCommandLine(base::CommandLine* command_line) override { 256 command_line->AppendSwitchASCII(switches::kApp, GetAppURL()); 257 } 258 259 std::string GetAppURL() const { 260 return "http://example.com/"; 261 } 262 263 const BrowserList* active_browser_list_; 264}; 265 266// Test that in web app mode a reopen event opens the app URL. 267IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest, 268 WebAppReopenWithNoWindows) { 269 AppController* ac = base::mac::ObjCCast<AppController>( 270 [[NSApplication sharedApplication] delegate]); 271 ASSERT_TRUE(ac); 272 273 EXPECT_EQ(1u, active_browser_list_->size()); 274 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO]; 275 276 EXPECT_FALSE(result); 277 EXPECT_EQ(2u, active_browser_list_->size()); 278 279 Browser* browser = active_browser_list_->get(0); 280 GURL current_url = 281 browser->tab_strip_model()->GetActiveWebContents()->GetURL(); 282 EXPECT_EQ(GetAppURL(), current_url.spec()); 283} 284 285// Called when the ProfileManager has created a profile. 286void CreateProfileCallback(const base::RepeatingClosure& quit_closure, 287 Profile* profile, 288 Profile::CreateStatus status) { 289 EXPECT_TRUE(profile); 290 EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status); 291 EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status); 292 // This will be called multiple times. Wait until the profile is initialized 293 // fully to quit the loop. 294 if (status == Profile::CREATE_STATUS_INITIALIZED) 295 quit_closure.Run(); 296} 297 298void CreateAndWaitForSystemProfile() { 299 ProfileManager::CreateCallback create_callback = base::BindRepeating( 300 &CreateProfileCallback, 301 base::RunLoop::QuitCurrentWhenIdleClosureDeprecated()); 302 g_browser_process->profile_manager()->CreateProfileAsync( 303 ProfileManager::GetSystemProfilePath(), 304 create_callback, 305 base::string16(), 306 std::string()); 307 base::RunLoop().Run(); 308} 309 310class AppControllerNewProfileManagementBrowserTest 311 : public InProcessBrowserTest { 312 protected: 313 AppControllerNewProfileManagementBrowserTest() 314 : active_browser_list_(BrowserList::GetInstance()) {} 315 316 const BrowserList* active_browser_list_; 317}; 318 319// Test that for a regular last profile, a reopen event opens a browser. 320IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest, 321 RegularProfileReopenWithNoWindows) { 322 AppController* ac = base::mac::ObjCCast<AppController>( 323 [[NSApplication sharedApplication] delegate]); 324 ASSERT_TRUE(ac); 325 326 EXPECT_EQ(1u, active_browser_list_->size()); 327 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO]; 328 329 EXPECT_FALSE(result); 330 EXPECT_EQ(2u, active_browser_list_->size()); 331 EXPECT_FALSE(UserManager::IsShowing()); 332} 333 334// Test that for a locked last profile, a reopen event opens the User Manager. 335IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest, 336 LockedProfileReopenWithNoWindows) { 337 // The User Manager uses the system profile as its underlying profile. To 338 // minimize flakiness due to the scheduling/descheduling of tasks on the 339 // different threads, pre-initialize the guest profile before it is needed. 340 CreateAndWaitForSystemProfile(); 341 AppController* ac = base::mac::ObjCCast<AppController>( 342 [[NSApplication sharedApplication] delegate]); 343 ASSERT_TRUE(ac); 344 345 // Lock the active profile. 346 base::ScopedAllowBlockingForTesting allow_blocking; 347 Profile* profile = [ac lastProfile]; 348 ProfileAttributesEntry* entry; 349 ASSERT_TRUE(g_browser_process->profile_manager()-> 350 GetProfileAttributesStorage(). 351 GetProfileAttributesWithPath(profile->GetPath(), &entry)); 352 entry->SetIsSigninRequired(true); 353 EXPECT_TRUE(entry->IsSigninRequired()); 354 355 EXPECT_EQ(1u, active_browser_list_->size()); 356 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO]; 357 EXPECT_FALSE(result); 358 359 base::RunLoop().RunUntilIdle(); 360 EXPECT_EQ(1u, active_browser_list_->size()); 361 EXPECT_TRUE(UserManager::IsShowing()); 362 UserManager::Hide(); 363} 364 365// Test that for a guest last profile, commandDispatch should open UserManager 366// if guest mode is disabled. Note that this test might be flaky under ASAN 367// due to https://crbug.com/674475. Please disable this test under ASAN 368// as the tests below if that happened. 369IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest, 370 OpenGuestProfileOnlyIfGuestModeIsEnabled) { 371 CreateAndWaitForSystemProfile(); 372 PrefService* local_state = g_browser_process->local_state(); 373 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir); 374 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false); 375 376 AppController* ac = base::mac::ObjCCast<AppController>( 377 [[NSApplication sharedApplication] delegate]); 378 ASSERT_TRUE(ac); 379 380 base::ScopedAllowBlockingForTesting allow_blocking; 381 Profile* profile = [ac lastProfile]; 382 EXPECT_TRUE(profile->IsGuestSession()); 383 384 NSMenu* menu = [ac applicationDockMenu:NSApp]; 385 ASSERT_TRUE(menu); 386 NSMenuItem* item = [menu itemWithTag:IDC_NEW_WINDOW]; 387 ASSERT_TRUE(item); 388 EXPECT_EQ(1u, active_browser_list_->size()); 389 390 [ac commandDispatch:item]; 391 392 base::RunLoop().RunUntilIdle(); 393 394 EXPECT_EQ(1u, active_browser_list_->size()); 395 EXPECT_TRUE(UserManager::IsShowing()); 396 UserManager::Hide(); 397 398 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, true); 399 [ac commandDispatch:item]; 400 base::RunLoop().RunUntilIdle(); 401 EXPECT_EQ(2u, active_browser_list_->size()); 402 EXPECT_FALSE(UserManager::IsShowing()); 403} 404 405// Test that for a guest last profile, a reopen event opens the User Manager. 406IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest, 407 GuestProfileReopenWithNoWindows) { 408 // Create the system profile. Set the guest as the last used profile so the 409 // app controller can use it on init. 410 CreateAndWaitForSystemProfile(); 411 PrefService* local_state = g_browser_process->local_state(); 412 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir); 413 414 AppController* ac = base::mac::ObjCCast<AppController>( 415 [[NSApplication sharedApplication] delegate]); 416 ASSERT_TRUE(ac); 417 418 base::ScopedAllowBlockingForTesting allow_blocking; 419 Profile* profile = [ac lastProfile]; 420 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath()); 421 EXPECT_TRUE(profile->IsGuestSession()); 422 423 EXPECT_EQ(1u, active_browser_list_->size()); 424 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO]; 425 EXPECT_FALSE(result); 426 427 base::RunLoop().RunUntilIdle(); 428 429 EXPECT_EQ(1u, active_browser_list_->size()); 430 EXPECT_TRUE(UserManager::IsShowing()); 431 UserManager::Hide(); 432} 433 434IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest, 435 AboutChromeForcesUserManager) { 436 AppController* ac = base::mac::ObjCCast<AppController>( 437 [[NSApplication sharedApplication] delegate]); 438 ASSERT_TRUE(ac); 439 440 // Create the guest profile, and set it as the last used profile so the 441 // app controller can use it on init. 442 CreateAndWaitForSystemProfile(); 443 PrefService* local_state = g_browser_process->local_state(); 444 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir); 445 446 // Prohibiting guest mode forces the user manager flow for About Chrome. 447 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false); 448 449 base::ScopedAllowBlockingForTesting allow_blocking; 450 Profile* guest_profile = [ac lastProfile]; 451 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), guest_profile->GetPath()); 452 EXPECT_TRUE(guest_profile->IsGuestSession()); 453 454 // Tell the browser to open About Chrome. 455 EXPECT_EQ(1u, active_browser_list_->size()); 456 [ac orderFrontStandardAboutPanel:NSApp]; 457 458 base::RunLoop().RunUntilIdle(); 459 460 // No new browser is opened; the User Manager opens instead. 461 EXPECT_EQ(1u, active_browser_list_->size()); 462 EXPECT_TRUE(UserManager::IsShowing()); 463 464 UserManager::Hide(); 465} 466 467class AppControllerProfilePickerBrowserTest 468 : public AppControllerNewProfileManagementBrowserTest { 469 public: 470 AppControllerProfilePickerBrowserTest() { 471 feature_list_.InitAndEnableFeature(features::kNewProfilePicker); 472 } 473 474 ~AppControllerProfilePickerBrowserTest() override { 475 signin_util::ResetForceSigninForTesting(); 476 } 477 478 private: 479 base::test::ScopedFeatureList feature_list_; 480}; 481 482// Test that for a regular last profile, a reopen event opens a browser. 483IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest, 484 RegularProfileReopenWithNoWindows) { 485 AppController* ac = base::mac::ObjCCastStrict<AppController>( 486 [[NSApplication sharedApplication] delegate]); 487 488 EXPECT_EQ(1u, active_browser_list_->size()); 489 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO]; 490 491 EXPECT_FALSE(result); 492 EXPECT_EQ(2u, active_browser_list_->size()); 493 EXPECT_FALSE(UserManager::IsShowing()); 494 EXPECT_FALSE(ProfilePicker::IsOpen()); 495} 496 497// Test that for a locked last profile, a reopen event opens the User Manager, 498// because the profile picker does not support locked profiles yet. 499IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest, 500 LockedProfileReopenWithNoWindows) { 501 signin_util::SetForceSigninForTesting(true); 502 // The User Manager uses the system profile as its underlying profile. To 503 // minimize flakiness due to the scheduling/descheduling of tasks on the 504 // different threads, pre-initialize the guest profile before it is needed. 505 CreateAndWaitForSystemProfile(); 506 AppController* ac = base::mac::ObjCCastStrict<AppController>( 507 [[NSApplication sharedApplication] delegate]); 508 509 // Lock the active profile. 510 base::ScopedAllowBlockingForTesting allow_blocking; 511 Profile* profile = [ac lastProfile]; 512 ProfileAttributesEntry* entry; 513 ASSERT_TRUE(g_browser_process->profile_manager() 514 ->GetProfileAttributesStorage() 515 .GetProfileAttributesWithPath(profile->GetPath(), &entry)); 516 entry->SetIsSigninRequired(true); 517 EXPECT_TRUE(entry->IsSigninRequired()); 518 519 EXPECT_EQ(1u, active_browser_list_->size()); 520 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO]; 521 EXPECT_FALSE(result); 522 523 base::RunLoop().RunUntilIdle(); 524 EXPECT_EQ(1u, active_browser_list_->size()); 525 EXPECT_TRUE(UserManager::IsShowing()); 526 UserManager::Hide(); 527} 528 529// Test that for a guest last profile, a reopen event opens the ProfilePicker. 530IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest, 531 GuestProfileReopenWithNoWindows) { 532 // Create the system profile. Set the guest as the last used profile so the 533 // app controller can use it on init. 534 CreateAndWaitForSystemProfile(); 535 PrefService* local_state = g_browser_process->local_state(); 536 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir); 537 538 AppController* ac = base::mac::ObjCCastStrict<AppController>( 539 [[NSApplication sharedApplication] delegate]); 540 541 base::ScopedAllowBlockingForTesting allow_blocking; 542 Profile* profile = [ac lastProfile]; 543 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath()); 544 EXPECT_TRUE(profile->IsGuestSession()); 545 546 EXPECT_EQ(1u, active_browser_list_->size()); 547 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO]; 548 EXPECT_FALSE(result); 549 550 base::RunLoop().RunUntilIdle(); 551 552 EXPECT_EQ(1u, active_browser_list_->size()); 553 EXPECT_TRUE(ProfilePicker::IsOpen()); 554 ProfilePicker::Hide(); 555} 556 557// Test that the ProfilePicker is shown when there are multiple profiles. 558IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest, 559 MultiProfilePickerShown) { 560 CreateAndWaitForSystemProfile(); 561 AppController* ac = base::mac::ObjCCastStrict<AppController>( 562 [[NSApplication sharedApplication] delegate]); 563 564 // Add a profile in the cache (simulate another profile on disk). 565 base::ScopedAllowBlockingForTesting allow_blocking; 566 ProfileManager* profile_manager = g_browser_process->profile_manager(); 567 ProfileAttributesStorage* profile_storage = 568 &profile_manager->GetProfileAttributesStorage(); 569 const base::FilePath profile_path = 570 profile_manager->GenerateNextProfileDirectoryPath(); 571 profile_storage->AddProfile( 572 profile_path, base::ASCIIToUTF16("name_1"), "12345", base::string16(), 573 /*is_consented_primary_account=*/false, /*icon_index=*/0, 574 /*supervised_user_id*/ std::string(), EmptyAccountId()); 575 576 EXPECT_EQ(1u, active_browser_list_->size()); 577 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO]; 578 EXPECT_FALSE(result); 579 580 base::RunLoop().RunUntilIdle(); 581 EXPECT_EQ(1u, active_browser_list_->size()); 582 EXPECT_TRUE(ProfilePicker::IsOpen()); 583 EXPECT_FALSE(UserManager::IsShowing()); 584 ProfilePicker::Hide(); 585} 586 587class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest { 588 protected: 589 AppControllerOpenShortcutBrowserTest() { 590 scoped_feature_list_.InitWithFeatures({welcome::kForceEnabled}, {}); 591 } 592 593 void SetUpInProcessBrowserTestFixture() override { 594 // In order to mimic opening shortcut during browser startup, we need to 595 // send the event before -applicationDidFinishLaunching is called, but 596 // after AppController is loaded. 597 // 598 // Since -applicationWillFinishLaunching does nothing now, we swizzle it to 599 // our function to send the event. We need to do this early before running 600 // the main message loop. 601 // 602 // NSApp does not exist yet. We need to get the AppController using 603 // reflection. 604 Class appControllerClass = NSClassFromString(@"AppController"); 605 Class openShortcutClass = NSClassFromString(@"TestOpenShortcutOnStartup"); 606 607 ASSERT_TRUE(appControllerClass != nil); 608 ASSERT_TRUE(openShortcutClass != nil); 609 610 SEL targetMethod = @selector(applicationWillFinishLaunching:); 611 Method original = class_getInstanceMethod(appControllerClass, 612 targetMethod); 613 Method destination = class_getInstanceMethod(openShortcutClass, 614 targetMethod); 615 616 ASSERT_TRUE(original != NULL); 617 ASSERT_TRUE(destination != NULL); 618 619 method_exchangeImplementations(original, destination); 620 621 ASSERT_TRUE(embedded_test_server()->Start()); 622 g_open_shortcut_url = embedded_test_server()->GetURL("/simple.html"); 623 } 624 625 void SetUpCommandLine(base::CommandLine* command_line) override { 626 // If the arg is empty, PrepareTestCommandLine() after this function will 627 // append about:blank as default url. 628 command_line->AppendArg(chrome::kChromeUINewTabURL); 629 } 630 631 private: 632 base::test::ScopedFeatureList scoped_feature_list_; 633}; 634 635IN_PROC_BROWSER_TEST_F(AppControllerOpenShortcutBrowserTest, 636 OpenShortcutOnStartup) { 637 // The two tabs expected are the Welcome page and the desired URL. 638 EXPECT_EQ(2, browser()->tab_strip_model()->count()); 639 EXPECT_EQ(g_open_shortcut_url, 640 browser()->tab_strip_model()->GetActiveWebContents() 641 ->GetLastCommittedURL()); 642} 643 644class AppControllerReplaceNTPBrowserTest : public InProcessBrowserTest { 645 protected: 646 AppControllerReplaceNTPBrowserTest() {} 647 648 void SetUpInProcessBrowserTestFixture() override { 649 ASSERT_TRUE(embedded_test_server()->Start()); 650 } 651 652 void SetUpCommandLine(base::CommandLine* command_line) override { 653 // If the arg is empty, PrepareTestCommandLine() after this function will 654 // append about:blank as default url. 655 command_line->AppendArg(chrome::kChromeUINewTabURL); 656 } 657}; 658 659// Tests that when a GURL is opened after startup, it replaces the NTP. 660IN_PROC_BROWSER_TEST_F(AppControllerReplaceNTPBrowserTest, 661 ReplaceNTPAfterStartup) { 662 // Depending on network connectivity, the NTP URL can either be 663 // chrome://newtab/ or chrome-search://local-ntp/local-ntp.html. See 664 // local_ntp_test_utils::GetFinalNtpUrl for more details. 665 std::string expected_url = 666 local_ntp_test_utils::GetFinalNtpUrl(browser()->profile()).spec(); 667 668 // Ensure that there is exactly 1 tab showing, and the tab is the NTP. 669 GURL ntp(expected_url); 670 EXPECT_EQ(1, browser()->tab_strip_model()->count()); 671 browser()->tab_strip_model()->GetActiveWebContents()->GetController().LoadURL( 672 GURL(expected_url), content::Referrer(), 673 ui::PageTransition::PAGE_TRANSITION_LINK, std::string()); 674 675 // Wait for one navigation on the active web contents. 676 content::TestNavigationObserver ntp_navigation_observer( 677 browser()->tab_strip_model()->GetActiveWebContents()); 678 ntp_navigation_observer.Wait(); 679 680 EXPECT_EQ(ntp, 681 browser() 682 ->tab_strip_model() 683 ->GetActiveWebContents() 684 ->GetLastCommittedURL()); 685 686 GURL simple(embedded_test_server()->GetURL("/simple.html")); 687 SendAppleEventToOpenUrlToAppController(simple); 688 689 EXPECT_EQ(1, browser()->tab_strip_model()->count()); 690 content::TestNavigationObserver event_navigation_observer( 691 browser()->tab_strip_model()->GetActiveWebContents()); 692 event_navigation_observer.Wait(); 693 694 EXPECT_EQ(simple, 695 browser() 696 ->tab_strip_model() 697 ->GetActiveWebContents() 698 ->GetLastCommittedURL()); 699} 700 701// Tests that when a GURL is opened, it is not opened in incognito mode. 702IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest, OpenInRegularBrowser) { 703 ASSERT_TRUE(embedded_test_server()->Start()); 704 // Create an incognito browser. 705 Browser* incognito_browser = CreateIncognitoBrowser(browser()->profile()); 706 EXPECT_EQ(incognito_browser, chrome::GetLastActiveBrowser()); 707 EXPECT_EQ(1, browser()->tab_strip_model()->count()); 708 EXPECT_EQ(1, incognito_browser->tab_strip_model()->count()); 709 // Open a url. 710 GURL simple(embedded_test_server()->GetURL("/simple.html")); 711 SendAppleEventToOpenUrlToAppController(simple); 712 // It should be opened in the regular browser. 713 content::TestNavigationObserver event_navigation_observer( 714 browser()->tab_strip_model()->GetActiveWebContents()); 715 event_navigation_observer.Wait(); 716 EXPECT_EQ(2, browser()->tab_strip_model()->count()); 717 EXPECT_EQ(1, incognito_browser->tab_strip_model()->count()); 718 EXPECT_EQ(simple, browser() 719 ->tab_strip_model() 720 ->GetActiveWebContents() 721 ->GetLastCommittedURL()); 722} 723 724class AppControllerMainMenuBrowserTest : public InProcessBrowserTest { 725 protected: 726 AppControllerMainMenuBrowserTest() { 727 } 728}; 729 730IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest, 731 HistoryMenuResetAfterProfileDeletion) { 732 ProfileManager* profile_manager = g_browser_process->profile_manager(); 733 AppController* ac = 734 base::mac::ObjCCastStrict<AppController>([NSApp delegate]); 735 736 // Use the existing profile as profile 1. 737 Profile* profile1 = browser()->profile(); 738 739 // Create profile 2. 740 base::FilePath profile2_path = 741 profile_manager->GenerateNextProfileDirectoryPath(); 742 base::RunLoop run_loop; 743 profile_manager->CreateProfileAsync( 744 profile2_path, 745 base::BindRepeating(&RunClosureWhenProfileInitialized, 746 run_loop.QuitClosure()), 747 base::string16(), std::string()); 748 run_loop.Run(); 749 Profile* profile2 = profile_manager->GetProfileByPath(profile2_path); 750 ASSERT_TRUE(profile2); 751 752 // Load profile1's History Service backend so it will be assigned to the 753 // HistoryMenuBridge when windowChangedToProfile is called, or else this test 754 // will fail flaky. 755 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile( 756 profile1, ServiceAccessType::EXPLICIT_ACCESS)); 757 // Switch the controller to profile1. 758 [ac windowChangedToProfile:profile1]; 759 base::RunLoop().RunUntilIdle(); 760 761 // Verify the controller's History Menu corresponds to profile1. 762 EXPECT_TRUE([ac historyMenuBridge]->service()); 763 EXPECT_EQ([ac historyMenuBridge]->service(), 764 HistoryServiceFactory::GetForProfile(profile1, 765 ServiceAccessType::EXPLICIT_ACCESS)); 766 767 // Load profile2's History Service backend so it will be assigned to the 768 // HistoryMenuBridge when windowChangedToProfile is called, or else this test 769 // will fail flaky. 770 ui_test_utils::WaitForHistoryToLoad( 771 HistoryServiceFactory::GetForProfile(profile2, 772 ServiceAccessType::EXPLICIT_ACCESS)); 773 // Switch the controller to profile2. 774 [ac windowChangedToProfile:profile2]; 775 base::RunLoop().RunUntilIdle(); 776 777 // Verify the controller's History Menu has changed. 778 EXPECT_TRUE([ac historyMenuBridge]->service()); 779 EXPECT_EQ([ac historyMenuBridge]->service(), 780 HistoryServiceFactory::GetForProfile(profile2, 781 ServiceAccessType::EXPLICIT_ACCESS)); 782 EXPECT_NE( 783 HistoryServiceFactory::GetForProfile(profile1, 784 ServiceAccessType::EXPLICIT_ACCESS), 785 HistoryServiceFactory::GetForProfile(profile2, 786 ServiceAccessType::EXPLICIT_ACCESS)); 787 788 // Delete profile2. 789 profile_manager->ScheduleProfileForDeletion(profile2->GetPath(), 790 base::DoNothing()); 791 base::RunLoop().RunUntilIdle(); 792 793 // Verify the controller's history is back to profile1. 794 EXPECT_EQ([ac historyMenuBridge]->service(), 795 HistoryServiceFactory::GetForProfile(profile1, 796 ServiceAccessType::EXPLICIT_ACCESS)); 797} 798 799IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest, 800 BookmarksMenuIsRestoredAfterProfileSwitch) { 801 ProfileManager* profile_manager = g_browser_process->profile_manager(); 802 AppController* ac = base::mac::ObjCCast<AppController>( 803 [[NSApplication sharedApplication] delegate]); 804 ASSERT_TRUE(ac); 805 806 [ac mainMenuCreated]; 807 808 // Constants for bookmarks that we will create later. 809 const base::string16 title1(base::ASCIIToUTF16("Dinosaur Comics")); 810 const GURL url1("http://qwantz.com//"); 811 812 const base::string16 title2(base::ASCIIToUTF16("XKCD")); 813 const GURL url2("https://www.xkcd.com/"); 814 815 // Use the existing profile as profile 1. 816 Profile* profile1 = browser()->profile(); 817 bookmarks::test::WaitForBookmarkModelToLoad( 818 BookmarkModelFactory::GetForBrowserContext(profile1)); 819 820 // Create profile 2. 821 base::ScopedAllowBlockingForTesting allow_blocking; 822 base::FilePath path2 = profile_manager->GenerateNextProfileDirectoryPath(); 823 std::unique_ptr<Profile> profile2 = 824 Profile::CreateProfile(path2, NULL, Profile::CREATE_MODE_SYNCHRONOUS); 825 Profile* profile2_ptr = profile2.get(); 826 profile_manager->RegisterTestingProfile(std::move(profile2), false); 827 bookmarks::test::WaitForBookmarkModelToLoad( 828 BookmarkModelFactory::GetForBrowserContext(profile2_ptr)); 829 830 // Switch to profile 1, create bookmark 1 and force the menu to build. 831 [ac windowChangedToProfile:profile1]; 832 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL( 833 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(), 834 0, title1, url1); 835 NSMenu* profile1_submenu = [ac bookmarkMenuBridge]->BookmarkMenu(); 836 [[profile1_submenu delegate] menuNeedsUpdate:profile1_submenu]; 837 838 // Switch to profile 2, create bookmark 2 and force the menu to build. 839 [ac windowChangedToProfile:profile2_ptr]; 840 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL( 841 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(), 842 0, title2, url2); 843 NSMenu* profile2_submenu = [ac bookmarkMenuBridge]->BookmarkMenu(); 844 [[profile2_submenu delegate] menuNeedsUpdate:profile2_submenu]; 845 EXPECT_NE(profile1_submenu, profile2_submenu); 846 847 // Test that only bookmark 2 is shown. 848 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle: 849 SysUTF16ToNSString(title1)]); 850 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle: 851 SysUTF16ToNSString(title2)]); 852 853 // Switch *back* to profile 1 and *don't* force the menu to build. 854 [ac windowChangedToProfile:profile1]; 855 856 // Test that only bookmark 1 is shown in the restored menu. 857 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle: 858 SysUTF16ToNSString(title1)]); 859 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle: 860 SysUTF16ToNSString(title2)]); 861 862 // Ensure a cached menu was used. 863 EXPECT_EQ(profile1_submenu, [ac bookmarkMenuBridge]->BookmarkMenu()); 864} 865 866} // namespace 867 868//--------------------------AppControllerHandoffBrowserTest--------------------- 869 870static GURL g_handoff_url; 871 872@interface AppController (BrowserTest) 873- (void)new_passURLToHandoffManager:(const GURL&)handoffURL; 874@end 875 876@implementation AppController (BrowserTest) 877- (void)new_passURLToHandoffManager:(const GURL&)handoffURL { 878 g_handoff_url = handoffURL; 879} 880@end 881 882namespace { 883 884class AppControllerHandoffBrowserTest : public InProcessBrowserTest { 885 protected: 886 AppControllerHandoffBrowserTest() {} 887 888 // Exchanges the implementations of the two selectors on the class 889 // AppController. 890 void ExchangeSelectors(SEL originalMethod, SEL newMethod) { 891 Class appControllerClass = NSClassFromString(@"AppController"); 892 893 ASSERT_TRUE(appControllerClass != nil); 894 895 Method original = 896 class_getInstanceMethod(appControllerClass, originalMethod); 897 Method destination = class_getInstanceMethod(appControllerClass, newMethod); 898 899 ASSERT_TRUE(original != NULL); 900 ASSERT_TRUE(destination != NULL); 901 902 method_exchangeImplementations(original, destination); 903 } 904 905 // Swizzle Handoff related implementations. 906 void SetUpInProcessBrowserTestFixture() override { 907 // This swizzle intercepts the URL that would be sent to the Handoff 908 // Manager, and instead puts it into a variable accessible to this test. 909 SEL originalMethod = @selector(passURLToHandoffManager:); 910 SEL newMethod = @selector(new_passURLToHandoffManager:); 911 ExchangeSelectors(originalMethod, newMethod); 912 } 913 914 // Closes the tab, and waits for the close to finish. 915 void CloseTab(Browser* browser, int index) { 916 content::WebContentsDestroyedWatcher destroyed_watcher( 917 browser->tab_strip_model()->GetWebContentsAt(index)); 918 browser->tab_strip_model()->CloseWebContentsAt( 919 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB); 920 destroyed_watcher.Wait(); 921 } 922}; 923 924// Tests that as a user switches between tabs, navigates within a tab, and 925// switches between browser windows, the correct URL is being passed to the 926// Handoff. 927IN_PROC_BROWSER_TEST_F(AppControllerHandoffBrowserTest, TestHandoffURLs) { 928 ASSERT_TRUE(embedded_test_server()->Start()); 929 EXPECT_EQ(g_handoff_url, GURL(url::kAboutBlankURL)); 930 931 // Test that navigating to a URL updates the handoff URL. 932 GURL test_url1 = embedded_test_server()->GetURL("/title1.html"); 933 ui_test_utils::NavigateToURL(browser(), test_url1); 934 EXPECT_EQ(g_handoff_url, test_url1); 935 936 // Test that opening a new tab updates the handoff URL. 937 GURL test_url2 = embedded_test_server()->GetURL("/title2.html"); 938 NavigateParams params(browser(), test_url2, ui::PAGE_TRANSITION_LINK); 939 params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; 940 ui_test_utils::NavigateToURL(¶ms); 941 EXPECT_EQ(g_handoff_url, test_url2); 942 943 // Test that switching tabs updates the handoff URL. 944 browser()->tab_strip_model()->ActivateTabAt( 945 0, {TabStripModel::GestureType::kOther}); 946 EXPECT_EQ(g_handoff_url, test_url1); 947 948 // Test that closing the current tab updates the handoff URL. 949 CloseTab(browser(), 0); 950 EXPECT_EQ(g_handoff_url, test_url2); 951 952 // Test that opening a new browser window updates the handoff URL. 953 GURL test_url3 = embedded_test_server()->GetURL("/title3.html"); 954 ui_test_utils::NavigateToURLWithDisposition( 955 browser(), GURL(test_url3), WindowOpenDisposition::NEW_WINDOW, 956 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER); 957 EXPECT_EQ(g_handoff_url, test_url3); 958 959 // Check that there are exactly 2 browsers. 960 BrowserList* active_browser_list = BrowserList::GetInstance(); 961 EXPECT_EQ(2u, active_browser_list->size()); 962 963 // Close the second browser window (which only has 1 tab left). 964 Browser* browser2 = active_browser_list->get(1); 965 CloseBrowserSynchronously(browser2); 966 EXPECT_EQ(g_handoff_url, test_url2); 967 968 // The URLs of incognito windows should not be passed to Handoff. 969 GURL test_url4 = embedded_test_server()->GetURL("/simple.html"); 970 ui_test_utils::NavigateToURLWithDisposition( 971 browser(), GURL(test_url4), WindowOpenDisposition::OFF_THE_RECORD, 972 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER); 973 EXPECT_EQ(g_handoff_url, GURL()); 974 975 // Open a new tab in the incognito window. 976 EXPECT_EQ(2u, active_browser_list->size()); 977 Browser* browser3 = active_browser_list->get(1); 978 ui_test_utils::NavigateToURLWithDisposition( 979 browser3, test_url4, WindowOpenDisposition::NEW_FOREGROUND_TAB, 980 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB); 981 EXPECT_EQ(g_handoff_url, GURL()); 982 983 // Navigate the current tab in the incognito window. 984 ui_test_utils::NavigateToURL(browser3, test_url1); 985 EXPECT_EQ(g_handoff_url, GURL()); 986 987 // Activate the original browser window. 988 Browser* browser1 = active_browser_list->get(0); 989 browser1->window()->Show(); 990 EXPECT_EQ(g_handoff_url, test_url2); 991} 992 993} // namespace 994