1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import <Cocoa/Cocoa.h>
6 #import <Foundation/Foundation.h>
7 #import <objc/runtime.h>
12 #include "base/apple/foundation_util.h"
13 #include "base/apple/scoped_objc_class_swizzler.h"
14 #include "base/command_line.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback_helpers.h"
17 #include "base/memory/raw_ptr.h"
18 #include "base/path_service.h"
19 #include "base/run_loop.h"
20 #include "base/scoped_observation.h"
21 #include "base/strings/string_util.h"
22 #include "base/strings/sys_string_conversions.h"
23 #include "base/strings/utf_string_conversions.h"
24 #include "base/test/metrics/histogram_tester.h"
25 #include "base/test/scoped_feature_list.h"
26 #include "base/threading/thread_restrictions.h"
27 #include "chrome/app/chrome_command_ids.h"
28 #import "chrome/browser/app_controller_mac.h"
29 #include "chrome/browser/apps/platform_apps/app_browsertest_util.h"
30 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
31 #include "chrome/browser/browser_features.h"
32 #include "chrome/browser/browser_process.h"
33 #include "chrome/browser/first_run/first_run.h"
34 #include "chrome/browser/history/history_service_factory.h"
35 #include "chrome/browser/lifetime/application_lifetime.h"
36 #include "chrome/browser/lifetime/application_lifetime_desktop.h"
37 #include "chrome/browser/prefs/incognito_mode_prefs.h"
38 #include "chrome/browser/profiles/delete_profile_helper.h"
39 #include "chrome/browser/profiles/keep_alive/profile_keep_alive_types.h"
40 #include "chrome/browser/profiles/profile_attributes_entry.h"
41 #include "chrome/browser/profiles/profile_attributes_init_params.h"
42 #include "chrome/browser/profiles/profile_attributes_storage.h"
43 #include "chrome/browser/profiles/profile_manager.h"
44 #include "chrome/browser/profiles/profile_metrics.h"
45 #include "chrome/browser/profiles/profile_observer.h"
46 #include "chrome/browser/profiles/profile_test_util.h"
47 #include "chrome/browser/signin/signin_features.h"
48 #include "chrome/browser/signin/signin_util.h"
49 #include "chrome/browser/ui/browser.h"
50 #include "chrome/browser/ui/browser_finder.h"
51 #include "chrome/browser/ui/browser_list.h"
52 #include "chrome/browser/ui/browser_navigator_params.h"
53 #include "chrome/browser/ui/browser_window.h"
54 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
55 #include "chrome/browser/ui/cocoa/history_menu_bridge.h"
56 #include "chrome/browser/ui/cocoa/last_active_browser_cocoa.h"
57 #include "chrome/browser/ui/cocoa/test/run_loop_testing.h"
58 #include "chrome/browser/ui/profiles/profile_picker.h"
59 #include "chrome/browser/ui/profiles/profile_ui_test_utils.h"
60 #include "chrome/browser/ui/search/ntp_test_utils.h"
61 #include "chrome/browser/ui/startup/first_run_service.h"
62 #include "chrome/browser/ui/tabs/tab_enums.h"
63 #include "chrome/browser/ui/tabs/tab_strip_model.h"
64 #include "chrome/browser/ui/ui_features.h"
65 #include "chrome/browser/ui/webui/welcome/helpers.h"
66 #include "chrome/common/chrome_constants.h"
67 #include "chrome/common/chrome_features.h"
68 #include "chrome/common/chrome_paths.h"
69 #include "chrome/common/chrome_switches.h"
70 #include "chrome/common/pref_names.h"
71 #include "chrome/common/url_constants.h"
72 #include "chrome/test/base/in_process_browser_test.h"
73 #include "chrome/test/base/ui_test_utils.h"
74 #include "components/account_id/account_id.h"
75 #include "components/bookmarks/browser/bookmark_model.h"
76 #include "components/bookmarks/test/bookmark_test_helpers.h"
77 #include "components/policy/core/common/policy_pref_names.h"
78 #include "components/prefs/pref_service.h"
79 #include "content/public/browser/navigation_controller.h"
80 #include "content/public/browser/web_contents.h"
81 #include "content/public/test/browser_test.h"
82 #include "content/public/test/browser_test_utils.h"
83 #include "content/public/test/prerender_test_util.h"
84 #include "content/public/test/test_navigation_observer.h"
85 #include "extensions/browser/app_window/app_window_registry.h"
86 #include "extensions/browser/extension_dialog_auto_confirm.h"
87 #include "extensions/common/extension.h"
88 #include "extensions/test/extension_test_message_listener.h"
89 #include "net/base/mac/url_conversions.h"
90 #include "net/dns/mock_host_resolver.h"
91 #include "net/test/embedded_test_server/embedded_test_server.h"
92 #include "third_party/blink/public/common/features.h"
93 #import "ui/events/test/cocoa_test_event_utils.h"
94 #include "ui/views/test/dialog_test.h"
95 #include "ui/views/widget/any_widget_observer.h"
96 #include "ui/views/widget/widget.h"
100 GURL g_open_shortcut_url = GURL::EmptyGURL();
102 // Instructs the NSApp's delegate to open |url|.
103 void SendOpenUrlToAppController(const GURL& url) {
104 [NSApp.delegate application:NSApp openURLs:@[ net::NSURLWithGURL(url) ]];
107 Profile& CreateAndWaitForProfile(const base::FilePath& profile_dir) {
108 Profile& profile = profiles::testing::CreateProfileSync(
109 g_browser_process->profile_manager(), profile_dir);
113 void CreateAndWaitForSystemProfile() {
114 CreateAndWaitForProfile(ProfileManager::GetSystemProfilePath());
117 Profile& CreateAndWaitForGuestProfile() {
118 return CreateAndWaitForProfile(ProfileManager::GetGuestProfilePath());
121 void SetGuestProfileAsLastProfile() {
122 AppController* app_controller = AppController.sharedController;
124 // Create the guest profile, and set it as the last used profile.
125 Profile& guest_profile = CreateAndWaitForGuestProfile();
126 [app_controller setLastProfile:&guest_profile];
128 Profile* profile = [app_controller lastProfileIfLoaded];
129 ASSERT_TRUE(profile);
130 EXPECT_EQ(guest_profile.GetPath(), profile->GetPath());
131 EXPECT_TRUE(profile->IsGuestSession());
133 // Also set the last used profile path preference. If the profile does need to
134 // be read from disk for some reason this acts as a backstop.
135 g_browser_process->local_state()->SetString(
136 prefs::kProfileLastUsed, guest_profile.GetPath().BaseName().value());
139 // Key for ProfileDestroyedData user data.
140 const char kProfileDestructionWaiterUserDataKey = 0;
142 // Waits until the Profile instance is destroyed.
143 class ProfileDestructionWaiter {
145 explicit ProfileDestructionWaiter(Profile* profile) {
146 profile->SetUserData(
147 &kProfileDestructionWaiterUserDataKey,
148 std::make_unique<ProfileDestroyedData>(run_loop_.QuitClosure()));
151 void Wait() { run_loop_.Run(); }
154 // Simple user data that calls a callback at destruction.
155 class ProfileDestroyedData : public base::SupportsUserData::Data {
157 explicit ProfileDestroyedData(base::OnceClosure callback)
158 : scoped_closure_runner_(std::move(callback)) {}
161 base::ScopedClosureRunner scoped_closure_runner_;
164 base::RunLoop run_loop_;
169 @interface TestOpenShortcutOnStartup : NSObject
170 - (void)applicationWillFinishLaunching:(NSNotification*)notification;
173 @implementation TestOpenShortcutOnStartup
175 - (void)applicationWillFinishLaunching:(NSNotification*)notification {
176 if (!g_open_shortcut_url.is_valid())
179 SendOpenUrlToAppController(g_open_shortcut_url);
186 using AppControllerBrowserTest = InProcessBrowserTest;
188 // Returns whether a window's pixels are actually on the screen, which is the
189 // case when it and all of its parents are marked visible.
190 bool IsReallyVisible(NSWindow* window) {
194 window = [window parentWindow];
199 size_t CountVisibleWindows() {
201 for (NSWindow* w in [NSApp windows])
202 count = count + (IsReallyVisible(w) ? 1 : 0);
206 // Returns how many visible NSWindows are expected for a given count of browser
208 size_t ExpectedWindowCountForBrowserCount(size_t browsers) {
212 // Test browser shutdown with a command in the message queue.
213 IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest, CommandDuringShutdown) {
214 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
215 EXPECT_EQ(ExpectedWindowCountForBrowserCount(1), CountVisibleWindows());
217 chrome::AttemptExit(); // Set chrome::IsTryingToQuit and close all windows.
219 // Opening a new window here is fine (unload handlers can also interrupt
220 // exit). But closing the window posts an autorelease on
221 // BrowserWindowController, which calls ~Browser() and, if that was the last
222 // Browser, it invokes applicationWillTerminate: (because IsTryingToQuit is
223 // set). So, verify assumptions then process that autorelease.
225 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
226 EXPECT_EQ(ExpectedWindowCountForBrowserCount(0), CountVisibleWindows());
228 base::RunLoop().RunUntilIdle();
230 EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
231 EXPECT_EQ(ExpectedWindowCountForBrowserCount(0), CountVisibleWindows());
233 NSEvent* cmd_n = cocoa_test_event_utils::KeyEventWithKeyCode(
234 'n', 'n', NSEventTypeKeyDown, NSEventModifierFlagCommand);
235 [[NSApp mainMenu] performSelector:@selector(performKeyEquivalent:)
238 // Let the run loop get flushed, during process cleanup and try not to crash.
241 // Regression test for https://crbug.com/1236073
242 // TODO(crbug.com/1373692): Extremely flaky on the mac12-arm64-rel bot.
243 IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest,
244 DISABLED_DeleteEphemeralProfile) {
245 EXPECT_EQ(1u, chrome::GetTotalBrowserCount());
246 Profile* profile = browser()->profile();
247 // Activate the first profile.
248 [NSNotificationCenter.defaultCenter
249 postNotificationName:NSWindowDidBecomeMainNotification
253 .GetNativeNSWindow()];
254 AppController* app_controller = AppController.sharedController;
255 ASSERT_EQ(profile, app_controller.lastProfileIfLoaded);
257 // Mark the profile as ephemeral.
258 profile->GetPrefs()->SetBoolean(prefs::kForceEphemeralProfiles, true);
259 ProfileManager* profile_manager = g_browser_process->profile_manager();
260 ProfileAttributesStorage& storage =
261 profile_manager->GetProfileAttributesStorage();
262 ProfileAttributesEntry* entry =
263 storage.GetProfileAttributesWithPath(profile->GetPath());
264 EXPECT_TRUE(entry->IsEphemeral());
266 // Add sentinel data to observe profile destruction. Ephemeral profiles are
267 // destroyed immediately upon browser close.
268 ProfileDestructionWaiter waiter(profile);
270 // Close browser and wait for the profile to be deleted.
271 CloseBrowserSynchronously(browser());
273 EXPECT_EQ(0u, chrome::GetTotalBrowserCount());
275 // Create a new profile and activate it.
276 Profile& profile2 = CreateAndWaitForProfile(
277 profile_manager->user_data_dir().AppendASCII("Profile 2"));
278 Browser* browser2 = CreateBrowser(&profile2);
279 // This should not crash.
280 [[NSNotificationCenter defaultCenter]
281 postNotificationName:NSWindowDidBecomeMainNotification
282 object:browser2->window()
284 .GetNativeNSWindow()];
285 ASSERT_EQ(&profile2, app_controller.lastProfileIfLoaded);
288 class AppControllerKeepAliveBrowserTest : public InProcessBrowserTest {
290 AppControllerKeepAliveBrowserTest() {
291 features_.InitAndEnableFeature(features::kDestroyProfileOnBrowserClose);
294 base::test::ScopedFeatureList features_;
297 class AppControllerPlatformAppBrowserTest
298 : public extensions::PlatformAppBrowserTest {
300 AppControllerPlatformAppBrowserTest()
301 : active_browser_list_(BrowserList::GetInstance()) {}
303 void SetUpCommandLine(base::CommandLine* command_line) override {
304 PlatformAppBrowserTest::SetUpCommandLine(command_line);
305 command_line->AppendSwitchASCII(switches::kAppId,
309 raw_ptr<const BrowserList> active_browser_list_;
312 // Test that if only a platform app window is open and no browser windows are
313 // open then a reopen event does nothing.
314 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
315 DISABLED_PlatformAppReopenWithWindows) {
316 NSUInteger old_window_count = NSApp.windows.count;
317 EXPECT_EQ(1u, active_browser_list_->size());
318 [AppController.sharedController applicationShouldHandleReopen:NSApp
319 hasVisibleWindows:YES];
320 // We do not EXPECT_TRUE the result here because the method
321 // deminiaturizes windows manually rather than return YES and have
324 EXPECT_EQ(old_window_count, NSApp.windows.count);
325 EXPECT_EQ(1u, active_browser_list_->size());
328 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
329 DISABLED_ActivationFocusesBrowserWindow) {
330 ExtensionTestMessageListener listener("Launched");
331 const extensions::Extension* app =
332 InstallAndLaunchPlatformApp("minimal");
333 ASSERT_TRUE(listener.WaitUntilSatisfied());
335 NSWindow* app_window = extensions::AppWindowRegistry::Get(profile())
336 ->GetAppWindowsForApp(app->id())
339 .GetNativeNSWindow();
340 NSWindow* browser_window =
341 browser()->window()->GetNativeWindow().GetNativeNSWindow();
343 chrome::testing::NSRunLoopRunAllPending();
344 EXPECT_LE([NSApp.orderedWindows indexOfObject:app_window],
345 [NSApp.orderedWindows indexOfObject:browser_window]);
346 [AppController.sharedController applicationShouldHandleReopen:NSApp
347 hasVisibleWindows:YES];
348 chrome::testing::NSRunLoopRunAllPending();
349 EXPECT_LE([NSApp.orderedWindows indexOfObject:browser_window],
350 [NSApp.orderedWindows indexOfObject:app_window]);
353 class AppControllerWebAppBrowserTest : public InProcessBrowserTest {
355 AppControllerWebAppBrowserTest()
356 : active_browser_list_(BrowserList::GetInstance()) {}
358 void SetUpCommandLine(base::CommandLine* command_line) override {
359 command_line->AppendSwitchASCII(switches::kApp, GetAppURL());
362 std::string GetAppURL() const {
363 return "http://example.com/";
366 raw_ptr<const BrowserList> active_browser_list_;
369 // Test that in web app mode a reopen event opens the app URL.
370 IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest,
371 WebAppReopenWithNoWindows) {
372 EXPECT_EQ(1u, active_browser_list_->size());
374 [AppController.sharedController applicationShouldHandleReopen:NSApp
375 hasVisibleWindows:NO];
377 EXPECT_FALSE(result);
378 EXPECT_EQ(2u, active_browser_list_->size());
380 Browser* browser = active_browser_list_->get(0);
382 browser->tab_strip_model()->GetActiveWebContents()->GetURL();
383 EXPECT_EQ(GetAppURL(), current_url.spec());
386 class AppControllerProfilePickerBrowserTest : public InProcessBrowserTest {
388 AppControllerProfilePickerBrowserTest()
389 : active_browser_list_(BrowserList::GetInstance()) {}
390 ~AppControllerProfilePickerBrowserTest() override = default;
392 void SetUpOnMainThread() override {
393 InProcessBrowserTest::SetUpOnMainThread();
395 // Flag the profile picker as already shown in the past, to avoid additional
396 // feature onboarding logic.
397 g_browser_process->local_state()->SetBoolean(
398 prefs::kBrowserProfilePickerShown, true);
401 const BrowserList* active_browser_list() const {
402 return active_browser_list_;
406 raw_ptr<const BrowserList> active_browser_list_;
409 // Test that for a guest last profile, commandDispatch should open UserManager
410 // if guest mode is disabled. Note that this test might be flaky under ASAN
411 // due to https://crbug.com/674475. Please disable this test under ASAN
412 // as the tests below if that happened.
413 IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
414 OpenGuestProfileOnlyIfGuestModeIsEnabled) {
415 SetGuestProfileAsLastProfile();
417 PrefService* local_state = g_browser_process->local_state();
418 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
419 AppController* app_controller = AppController.sharedController;
420 NSMenu* menu = [app_controller applicationDockMenu:NSApp];
422 NSMenuItem* item = [menu itemWithTag:IDC_NEW_WINDOW];
424 EXPECT_EQ(1u, active_browser_list()->size());
426 [app_controller commandDispatch:item];
428 base::RunLoop().RunUntilIdle();
430 EXPECT_EQ(1u, active_browser_list()->size());
431 EXPECT_TRUE(ProfilePicker::IsOpen());
432 ProfilePicker::Hide();
434 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, true);
435 [app_controller commandDispatch:item];
436 base::RunLoop().RunUntilIdle();
437 EXPECT_EQ(2u, active_browser_list()->size());
438 EXPECT_FALSE(ProfilePicker::IsOpen());
441 IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
442 AboutChromeGuestDisallowed) {
443 SetGuestProfileAsLastProfile();
445 // Disallow guest by policy and make sure "About Chrome" is not available
447 PrefService* local_state = g_browser_process->local_state();
448 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
449 NSMenuItem* about_menu_item = [[[NSApp.mainMenu itemWithTag:IDC_CHROME_MENU]
450 submenu] itemWithTag:IDC_ABOUT];
451 EXPECT_FALSE([AppController.sharedController
452 validateUserInterfaceItem:about_menu_item]);
455 // Test that for a regular last profile, a reopen event opens a browser.
456 IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
457 RegularProfileReopenWithNoWindows) {
458 EXPECT_EQ(1u, active_browser_list()->size());
460 [AppController.sharedController applicationShouldHandleReopen:NSApp
461 hasVisibleWindows:NO];
463 EXPECT_FALSE(result);
464 EXPECT_EQ(2u, active_browser_list()->size());
465 EXPECT_FALSE(ProfilePicker::IsOpen());
468 // Test that for a locked last profile, a reopen event opens the ProfilePicker.
469 IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
470 LockedProfileReopenWithNoWindows) {
471 signin_util::ScopedForceSigninSetterForTesting signin_setter(true);
472 // The User Manager uses the system profile as its underlying profile. To
473 // minimize flakiness due to the scheduling/descheduling of tasks on the
474 // different threads, pre-initialize the guest profile before it is needed.
475 CreateAndWaitForSystemProfile();
476 AppController* app_controller = AppController.sharedController;
478 // Lock the active profile.
479 Profile* profile = [app_controller lastProfileIfLoaded];
480 ProfileAttributesEntry* entry =
481 g_browser_process->profile_manager()
482 ->GetProfileAttributesStorage()
483 .GetProfileAttributesWithPath(profile->GetPath());
484 ASSERT_NE(entry, nullptr);
485 entry->LockForceSigninProfile(true);
486 EXPECT_TRUE(entry->IsSigninRequired());
488 EXPECT_EQ(1u, active_browser_list()->size());
489 BOOL result = [app_controller applicationShouldHandleReopen:NSApp
490 hasVisibleWindows:NO];
491 EXPECT_FALSE(result);
493 base::RunLoop().RunUntilIdle();
494 EXPECT_EQ(1u, active_browser_list()->size());
495 EXPECT_TRUE(ProfilePicker::IsOpen());
496 ProfilePicker::Hide();
499 // "About Chrome" does not unlock the profile (regression test for
500 // https://crbug.com/1226844).
501 IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
502 AboutPanelDoesNotUnlockProfile) {
503 signin_util::ScopedForceSigninSetterForTesting signin_setter(true);
504 // The User Manager uses the system profile as its underlying profile. To
505 // minimize flakiness due to the scheduling/descheduling of tasks on the
506 // different threads, pre-initialize the guest profile before it is needed.
507 CreateAndWaitForSystemProfile();
508 AppController* app_controller = AppController.sharedController;
509 // Lock the active profile.
510 Profile* profile = [app_controller lastProfileIfLoaded];
511 ProfileAttributesEntry* entry =
512 g_browser_process->profile_manager()
513 ->GetProfileAttributesStorage()
514 .GetProfileAttributesWithPath(profile->GetPath());
515 ASSERT_NE(entry, nullptr);
516 entry->LockForceSigninProfile(true);
517 EXPECT_TRUE(entry->IsSigninRequired());
518 EXPECT_EQ(1u, active_browser_list()->size());
519 Browser* browser = active_browser_list()->get(0);
520 EXPECT_FALSE(browser->profile()->IsGuestSession());
521 // "About Chrome" is not available in the menu.
522 NSMenu* chrome_submenu =
523 [[NSApp.mainMenu itemWithTag:IDC_CHROME_MENU] submenu];
524 NSMenuItem* about_menu_item = [chrome_submenu itemWithTag:IDC_ABOUT];
525 EXPECT_FALSE([app_controller validateUserInterfaceItem:about_menu_item]);
526 [chrome_submenu update];
527 EXPECT_FALSE([about_menu_item isEnabled]);
530 // Test that for a guest last profile, a reopen event opens the ProfilePicker.
531 IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
532 GuestProfileReopenWithNoWindows) {
533 SetGuestProfileAsLastProfile();
535 EXPECT_EQ(1u, active_browser_list()->size());
537 [AppController.sharedController applicationShouldHandleReopen:NSApp
538 hasVisibleWindows:NO];
539 EXPECT_FALSE(result);
541 base::RunLoop().RunUntilIdle();
543 EXPECT_EQ(1u, active_browser_list()->size());
544 EXPECT_TRUE(ProfilePicker::IsOpen());
545 ProfilePicker::Hide();
548 // Test that the ProfilePicker is shown when there are multiple profiles.
549 IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest,
550 MultiProfilePickerShown) {
551 CreateAndWaitForSystemProfile();
553 // Add a profile in the cache (simulate another profile on disk).
554 ProfileManager* profile_manager = g_browser_process->profile_manager();
555 ProfileAttributesStorage* profile_storage =
556 &profile_manager->GetProfileAttributesStorage();
557 const base::FilePath profile_path =
558 profile_manager->GenerateNextProfileDirectoryPath();
559 ProfileAttributesInitParams params;
560 params.profile_path = profile_path;
561 params.profile_name = u"name_1";
562 profile_storage->AddProfile(std::move(params));
564 EXPECT_EQ(1u, active_browser_list()->size());
566 [AppController.sharedController applicationShouldHandleReopen:NSApp
567 hasVisibleWindows:NO];
568 EXPECT_FALSE(result);
570 base::RunLoop().RunUntilIdle();
571 EXPECT_EQ(1u, active_browser_list()->size());
572 EXPECT_TRUE(ProfilePicker::IsOpen());
573 ProfilePicker::Hide();
576 // Checks that menu items and commands work when the profile picker is open.
577 IN_PROC_BROWSER_TEST_F(AppControllerProfilePickerBrowserTest, MenuCommands) {
578 // Show the profile picker.
579 ProfilePicker::Show(ProfilePicker::Params::FromEntryPoint(
580 ProfilePicker::EntryPoint::kProfileMenuManageProfiles));
582 AppController* app_controller = AppController.sharedController;
584 // Unhandled menu items are disabled.
585 NSMenu* file_submenu = [[NSApp.mainMenu itemWithTag:IDC_FILE_MENU] submenu];
586 NSMenuItem* close_tab_menu_item = [file_submenu itemWithTag:IDC_CLOSE_TAB];
587 EXPECT_FALSE([app_controller validateUserInterfaceItem:close_tab_menu_item]);
588 [file_submenu update];
589 EXPECT_FALSE([close_tab_menu_item isEnabled]);
591 // Enabled menu items work.
592 NSMenuItem* new_window_menu_item = [file_submenu itemWithTag:IDC_NEW_WINDOW];
593 EXPECT_TRUE([new_window_menu_item isEnabled]);
594 EXPECT_TRUE([app_controller validateUserInterfaceItem:new_window_menu_item]);
595 // Click on the item and checks that a new browser is opened.
596 ui_test_utils::BrowserChangeObserver browser_added_observer(
597 nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
599 performActionForItemAtIndex:[file_submenu
600 indexOfItemWithTag:IDC_NEW_WINDOW]];
601 EXPECT_TRUE(browser_added_observer.Wait());
604 class AppControllerFirstRunBrowserTest : public AppControllerBrowserTest {
606 void SetUpDefaultCommandLine(base::CommandLine* command_line) override {
607 InProcessBrowserTest::SetUpDefaultCommandLine(command_line);
608 command_line->RemoveSwitch(switches::kNoFirstRun);
612 base::test::ScopedFeatureList scoped_feature_list_{kForYouFre};
615 IN_PROC_BROWSER_TEST_F(AppControllerFirstRunBrowserTest,
616 OpenNewWindowWhileFreIsRunning) {
617 EXPECT_TRUE(ProfilePicker::IsFirstRunOpen());
618 EXPECT_EQ(BrowserList::GetInstance()->size(), 0u);
619 AppController* app_controller = AppController.sharedController;
620 NSMenu* menu = [app_controller applicationDockMenu:NSApp];
623 NSMenuItem* item = [menu itemWithTag:IDC_NEW_WINDOW];
625 [app_controller commandDispatch:item];
627 profiles::testing::WaitForPickerClosed();
628 EXPECT_FALSE(ProfilePicker::IsFirstRunOpen());
629 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
632 IN_PROC_BROWSER_TEST_F(AppControllerFirstRunBrowserTest,
633 ClickingChromeDockIconDoesNotOpenBrowser) {
634 EXPECT_TRUE(ProfilePicker::IsFirstRunOpen());
635 EXPECT_EQ(BrowserList::GetInstance()->size(), 0u);
636 [AppController.sharedController applicationShouldHandleReopen:NSApp
637 hasVisibleWindows:NO];
639 EXPECT_EQ(BrowserList::GetInstance()->size(), 0u);
640 ProfilePicker::Hide();
643 class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest {
645 AppControllerOpenShortcutBrowserTest()
646 : AppControllerOpenShortcutBrowserTest(/*enable_fre=*/false) {}
648 AppControllerOpenShortcutBrowserTest(bool enable_fre) {
649 std::vector<base::test::FeatureRef> enabled_features = {
650 welcome::kForceEnabled};
651 std::vector<base::test::FeatureRef> disabled_features = {};
653 enabled_features.push_back(kForYouFre);
655 disabled_features.push_back(kForYouFre);
658 scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
661 void SetUpInProcessBrowserTestFixture() override {
662 // In order to mimic opening shortcut during browser startup, we need to
663 // send the event before -applicationDidFinishLaunching is called, but
664 // after AppController is loaded.
666 // Since -applicationWillFinishLaunching does nothing now, we swizzle it to
667 // our function to send the event. We need to do this early before running
668 // the main message loop.
670 // NSApp does not exist yet. We need to get the AppController using
672 Class appControllerClass = NSClassFromString(@"AppController");
673 Class openShortcutClass = NSClassFromString(@"TestOpenShortcutOnStartup");
675 ASSERT_TRUE(appControllerClass != nil);
676 ASSERT_TRUE(openShortcutClass != nil);
678 SEL targetMethod = @selector(applicationWillFinishLaunching:);
679 Method original = class_getInstanceMethod(appControllerClass,
681 Method destination = class_getInstanceMethod(openShortcutClass,
684 ASSERT_TRUE(original);
685 ASSERT_TRUE(destination);
687 method_exchangeImplementations(original, destination);
689 ASSERT_TRUE(embedded_test_server()->Start());
690 g_open_shortcut_url = embedded_test_server()->GetURL("/simple.html");
693 void SetUpCommandLine(base::CommandLine* command_line) override {
694 // If the arg is empty, PrepareTestCommandLine() after this function will
695 // append about:blank as default url.
696 command_line->AppendArg(chrome::kChromeUINewTabURL);
700 base::test::ScopedFeatureList scoped_feature_list_;
703 IN_PROC_BROWSER_TEST_F(AppControllerOpenShortcutBrowserTest,
704 OpenShortcutOnStartup) {
705 // The two tabs expected are the Welcome page and the desired URL.
706 EXPECT_EQ(2, browser()->tab_strip_model()->count());
707 EXPECT_EQ(g_open_shortcut_url, browser()
709 ->GetActiveWebContents()
710 ->GetLastCommittedURL());
713 class AppControllerOpenShortcutWithFreBrowserTest
714 : public AppControllerOpenShortcutBrowserTest {
716 AppControllerOpenShortcutWithFreBrowserTest()
717 : AppControllerOpenShortcutBrowserTest(/*enable_fre=*/true) {}
720 IN_PROC_BROWSER_TEST_F(AppControllerOpenShortcutWithFreBrowserTest,
721 OpenShortcutOnStartup) {
722 // The Welcome page is not expected.
723 EXPECT_EQ(1, browser()->tab_strip_model()->count());
725 EXPECT_EQ(g_open_shortcut_url,
726 browser()->tab_strip_model()->GetActiveWebContents()
727 ->GetLastCommittedURL());
730 class AppControllerReplaceNTPBrowserTest : public InProcessBrowserTest {
732 AppControllerReplaceNTPBrowserTest() = default;
734 void SetUpInProcessBrowserTestFixture() override {
735 ASSERT_TRUE(embedded_test_server()->Start());
738 void SetUpCommandLine(base::CommandLine* command_line) override {
739 // If the arg is empty, PrepareTestCommandLine() after this function will
740 // append about:blank as default url.
741 command_line->AppendArg(chrome::kChromeUINewTabURL);
745 // Tests that when a GURL is opened after startup, it replaces the NTP.
746 // Flaky. See crbug.com/1234765.
747 IN_PROC_BROWSER_TEST_F(AppControllerReplaceNTPBrowserTest,
748 DISABLED_ReplaceNTPAfterStartup) {
749 // Depending on network connectivity, the NTP URL can either be
750 // chrome://newtab/ or chrome://new-tab-page-third-party. See
751 // ntp_test_utils::GetFinalNtpUrl for more details.
752 std::string expected_url =
753 ntp_test_utils::GetFinalNtpUrl(browser()->profile()).spec();
755 // Ensure that there is exactly 1 tab showing, and the tab is the NTP.
756 GURL ntp(expected_url);
757 EXPECT_EQ(1, browser()->tab_strip_model()->count());
758 browser()->tab_strip_model()->GetActiveWebContents()->GetController().LoadURL(
759 GURL(expected_url), content::Referrer(),
760 ui::PageTransition::PAGE_TRANSITION_LINK, std::string());
762 // Wait for one navigation on the active web contents.
763 content::TestNavigationObserver ntp_navigation_observer(
764 browser()->tab_strip_model()->GetActiveWebContents());
765 ntp_navigation_observer.Wait();
770 ->GetActiveWebContents()
771 ->GetLastCommittedURL());
773 GURL simple(embedded_test_server()->GetURL("/simple.html"));
774 SendOpenUrlToAppController(simple);
776 EXPECT_EQ(1, browser()->tab_strip_model()->count());
777 content::TestNavigationObserver event_navigation_observer(
778 browser()->tab_strip_model()->GetActiveWebContents());
779 event_navigation_observer.Wait();
784 ->GetActiveWebContents()
785 ->GetLastCommittedURL());
788 // Tests that, even if an incognito browser is the last active browser, a GURL
789 // is opened in a regular (non-incognito) browser.
790 // Regression test for https://crbug.com/757253, https://crbug.com/1444747
791 IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest, OpenInRegularBrowser) {
792 ASSERT_TRUE(embedded_test_server()->Start());
794 base::apple::ObjCCastStrict<AppController>([NSApp delegate]);
796 // Create an incognito browser and make it the last active browser.
797 Browser* incognito_browser = CreateIncognitoBrowser(browser()->profile());
798 EXPECT_EQ(1, browser()->tab_strip_model()->count());
799 EXPECT_EQ(1, incognito_browser->tab_strip_model()->count());
800 EXPECT_TRUE(incognito_browser->profile()->IsIncognitoProfile());
801 EXPECT_EQ(incognito_browser, chrome::GetLastActiveBrowser());
802 // Assure that `windowDidBecomeMain` is called even if this browser process
803 // lost focus because of other browser processes in other shards taking
804 // focus. It prevents flakiness.
805 // See: https://crrev.com/c/4530255/comments/2aadb9cf_9a39d4bf
806 [[NSNotificationCenter defaultCenter]
807 postNotificationName:NSWindowDidBecomeMainNotification
808 object:incognito_browser->window()
810 .GetNativeNSWindow()];
812 GURL simple(embedded_test_server()->GetURL("/simple.html"));
813 content::TestNavigationObserver event_navigation_observer(simple);
814 event_navigation_observer.StartWatchingNewWebContents();
815 SendOpenUrlToAppController(simple);
816 event_navigation_observer.Wait();
817 // It should be opened in the regular browser.
818 EXPECT_EQ(2, browser()->tab_strip_model()->count());
819 EXPECT_EQ(1, incognito_browser->tab_strip_model()->count());
820 EXPECT_EQ(simple, browser()
822 ->GetActiveWebContents()
823 ->GetLastCommittedURL());
826 // Tests that, even if only an incognito browser is currently opened, a GURL
827 // is opened in a regular (non-incognito) browser.
828 // Regression test for https://crbug.com/757253, https://crbug.com/1444747
829 IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest,
830 OpenInRegularBrowserWhenOnlyIncognitoBrowserIsOpened) {
831 ASSERT_TRUE(embedded_test_server()->Start());
833 base::apple::ObjCCastStrict<AppController>([NSApp delegate]);
835 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
836 // Close the current browser.
837 Profile* profile = browser()->profile();
838 chrome::CloseAllBrowsers();
839 ui_test_utils::WaitForBrowserToClose();
840 EXPECT_TRUE(BrowserList::GetInstance()->empty());
841 // Create an incognito browser and check that it is the last active browser.
842 Browser* incognito_browser = CreateIncognitoBrowser(profile);
843 EXPECT_TRUE(incognito_browser->profile()->IsIncognitoProfile());
844 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
845 EXPECT_EQ(incognito_browser, chrome::GetLastActiveBrowser());
846 // Assure that `windowDidBecomeMain` is called even if this browser process
847 // lost focus because of other browser processes in other shards taking
848 // focus. It prevents flakiness.
849 // See: https://crrev.com/c/4530255/comments/2aadb9cf_9a39d4bf
850 [[NSNotificationCenter defaultCenter]
851 postNotificationName:NSWindowDidBecomeMainNotification
852 object:incognito_browser->window()
854 .GetNativeNSWindow()];
856 GURL simple(embedded_test_server()->GetURL("/simple.html"));
857 content::TestNavigationObserver event_navigation_observer(simple);
858 event_navigation_observer.StartWatchingNewWebContents();
859 SendOpenUrlToAppController(simple);
860 event_navigation_observer.Wait();
861 // Check that a new regular browser is opened
862 // and the url is opened in the regular browser.
863 Browser* new_browser = chrome::GetLastActiveBrowser();
864 EXPECT_EQ(BrowserList::GetInstance()->size(), 2u);
865 EXPECT_TRUE(new_browser->profile()->IsRegularProfile());
866 EXPECT_EQ(profile, new_browser->profile());
867 EXPECT_EQ(simple, new_browser->tab_strip_model()
868 ->GetActiveWebContents()
869 ->GetLastCommittedURL());
872 // Tests that, if a guest browser is the last active browser, a GURL is opened
873 // in the guest browser.
874 IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest, OpenUrlInGuestBrowser) {
875 ASSERT_TRUE(embedded_test_server()->Start());
877 base::apple::ObjCCastStrict<AppController>([NSApp delegate]);
879 // Create a guest browser and make it the last active browser.
880 Browser* guest_browser = CreateGuestBrowser();
881 EXPECT_EQ(1, browser()->tab_strip_model()->count());
882 EXPECT_EQ(1, guest_browser->tab_strip_model()->count());
883 EXPECT_TRUE(guest_browser->profile()->IsGuestSession());
884 guest_browser->window()->Show();
885 EXPECT_EQ(guest_browser, chrome::GetLastActiveBrowser());
886 // Assure that `windowDidBecomeMain` is called even if this browser process
887 // lost focus because of other browser processes in other shards taking
888 // focus. It prevents flakiness.
889 // See: https://crrev.com/c/4530255/comments/2aadb9cf_9a39d4bf
890 [[NSNotificationCenter defaultCenter]
891 postNotificationName:NSWindowDidBecomeMainNotification
892 object:guest_browser->window()
894 .GetNativeNSWindow()];
896 GURL simple(embedded_test_server()->GetURL("/simple.html"));
897 content::TestNavigationObserver event_navigation_observer(simple);
898 event_navigation_observer.StartWatchingNewWebContents();
899 SendOpenUrlToAppController(simple);
900 event_navigation_observer.Wait();
901 // It should be opened in the guest browser.
902 EXPECT_EQ(1, browser()->tab_strip_model()->count());
903 EXPECT_EQ(2, guest_browser->tab_strip_model()->count());
904 EXPECT_EQ(simple, guest_browser->tab_strip_model()
905 ->GetActiveWebContents()
906 ->GetLastCommittedURL());
909 // Tests that when a GURL is opened while incognito forced and there is no
910 // browser opened, it is opened in a new incognito browser.
911 // Test for https://crbug.com/1444747#c8
912 IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest, OpenUrlWhenForcedIncognito) {
913 ASSERT_TRUE(embedded_test_server()->Start());
914 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
915 // Close the current non-incognito browser.
916 Profile* profile = browser()->profile();
917 chrome::CloseAllBrowsers();
918 ui_test_utils::WaitForBrowserToClose();
919 EXPECT_TRUE(BrowserList::GetInstance()->empty());
920 // Force incognito mode.
921 IncognitoModePrefs::SetAvailability(
922 profile->GetPrefs(), policy::IncognitoModeAvailability::kForced);
924 GURL simple(embedded_test_server()->GetURL("/simple.html"));
925 content::TestNavigationObserver event_navigation_observer(simple);
926 event_navigation_observer.StartWatchingNewWebContents();
927 SendOpenUrlToAppController(simple);
928 event_navigation_observer.Wait();
929 // Check that a new incognito browser is opened
930 // and the url is opened in the incognito browser.
931 Browser* new_browser = chrome::GetLastActiveBrowser();
932 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
933 EXPECT_TRUE(new_browser->profile()->IsIncognitoProfile());
934 EXPECT_TRUE(new_browser->profile()->IsPrimaryOTRProfile());
935 EXPECT_EQ(profile, new_browser->profile()->GetOriginalProfile());
936 EXPECT_EQ(simple, new_browser->tab_strip_model()
937 ->GetActiveWebContents()
938 ->GetLastCommittedURL());
941 // Tests that when a GURL is opened while incognito forced and an incognito
942 // browser is opened, it is opened in the already opened incognito browser.
943 // Test for https://crbug.com/1444747#c8
944 IN_PROC_BROWSER_TEST_F(AppControllerBrowserTest,
945 OpenUrlWhenForcedIncognitoAndIncognitoBrowserIsOpened) {
946 ASSERT_TRUE(embedded_test_server()->Start());
947 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
948 // Close the current non-incognito browser.
949 Profile* profile = browser()->profile();
950 chrome::CloseAllBrowsers();
951 ui_test_utils::WaitForBrowserToClose();
952 EXPECT_TRUE(BrowserList::GetInstance()->empty());
953 // Force incognito mode.
954 IncognitoModePrefs::SetAvailability(
955 profile->GetPrefs(), policy::IncognitoModeAvailability::kForced);
956 // Create an incognito browser.
957 Browser* incognito_browser = CreateIncognitoBrowser(profile);
958 EXPECT_TRUE(incognito_browser->profile()->IsIncognitoProfile());
959 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
960 EXPECT_EQ(1, incognito_browser->tab_strip_model()->count());
961 EXPECT_EQ(incognito_browser, chrome::GetLastActiveBrowser());
962 // Assure that `windowDidBecomeMain` is called even if this browser process
963 // lost focus because of other browser processes in other shards taking
964 // focus. It prevents flakiness.
965 // See: https://crrev.com/c/4530255/comments/2aadb9cf_9a39d4bf
966 [[NSNotificationCenter defaultCenter]
967 postNotificationName:NSWindowDidBecomeMainNotification
968 object:incognito_browser->window()
970 .GetNativeNSWindow()];
972 GURL simple(embedded_test_server()->GetURL("/simple.html"));
973 content::TestNavigationObserver event_navigation_observer(simple);
974 event_navigation_observer.StartWatchingNewWebContents();
975 SendOpenUrlToAppController(simple);
976 event_navigation_observer.Wait();
977 // Check the url is opened in the already opened incognito browser.
978 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
979 EXPECT_EQ(2, incognito_browser->tab_strip_model()->count());
980 EXPECT_EQ(simple, incognito_browser->tab_strip_model()
981 ->GetActiveWebContents()
982 ->GetLastCommittedURL());
985 class AppControllerMainMenuBrowserTest : public InProcessBrowserTest {
987 AppControllerMainMenuBrowserTest() = default;
990 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
991 HistoryMenuResetAfterProfileDeletion) {
992 ProfileManager* profile_manager = g_browser_process->profile_manager();
993 AppController* app_controller = AppController.sharedController;
995 // Use the existing profile as profile 1.
996 Profile* profile1 = browser()->profile();
999 base::FilePath profile2_path =
1000 profile_manager->GenerateNextProfileDirectoryPath();
1002 profiles::testing::CreateProfileSync(profile_manager, profile2_path);
1004 // Load profile1's History Service backend so it will be assigned to the
1005 // HistoryMenuBridge when setLastProfile is called, or else this test will
1007 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
1008 profile1, ServiceAccessType::EXPLICIT_ACCESS));
1009 // Switch the controller to profile1.
1010 [app_controller setLastProfile:profile1];
1011 base::RunLoop().RunUntilIdle();
1013 // Verify the controller's History Menu corresponds to profile1.
1014 EXPECT_TRUE([app_controller historyMenuBridge]->service());
1015 EXPECT_EQ([app_controller historyMenuBridge]->service(),
1016 HistoryServiceFactory::GetForProfile(
1017 profile1, ServiceAccessType::EXPLICIT_ACCESS));
1019 // Load profile2's History Service backend so it will be assigned to the
1020 // HistoryMenuBridge when setLastProfile is called, or else this test will
1022 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
1023 &profile2, ServiceAccessType::EXPLICIT_ACCESS));
1024 // Switch the controller to profile2.
1025 [app_controller setLastProfile:&profile2];
1026 base::RunLoop().RunUntilIdle();
1028 // Verify the controller's History Menu has changed.
1029 EXPECT_TRUE([app_controller historyMenuBridge]->service());
1030 EXPECT_EQ([app_controller historyMenuBridge]->service(),
1031 HistoryServiceFactory::GetForProfile(
1032 &profile2, ServiceAccessType::EXPLICIT_ACCESS));
1033 EXPECT_NE(HistoryServiceFactory::GetForProfile(
1034 profile1, ServiceAccessType::EXPLICIT_ACCESS),
1035 HistoryServiceFactory::GetForProfile(
1036 &profile2, ServiceAccessType::EXPLICIT_ACCESS));
1039 profile_manager->GetDeleteProfileHelper().MaybeScheduleProfileForDeletion(
1040 profile2.GetPath(), base::DoNothing(),
1041 ProfileMetrics::DELETE_PROFILE_USER_MANAGER);
1042 content::RunAllTasksUntilIdle();
1044 // Verify the controller's history is back to profile1.
1045 EXPECT_EQ([app_controller historyMenuBridge]->service(),
1046 HistoryServiceFactory::GetForProfile(
1047 profile1, ServiceAccessType::EXPLICIT_ACCESS));
1050 // Disabled because of flakiness. See crbug.com/1278031.
1051 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
1052 DISABLED_ReloadingDestroyedProfileDoesNotCrash) {
1053 ProfileManager* profile_manager = g_browser_process->profile_manager();
1054 AppController* app_controller = AppController.sharedController;
1056 Profile* profile = browser()->profile();
1057 base::FilePath profile_path = profile->GetPath();
1059 // Switch the controller to |profile|.
1060 [app_controller setLastProfile:profile];
1061 base::RunLoop().RunUntilIdle();
1062 EXPECT_EQ(profile, [app_controller lastProfileIfLoaded]);
1064 // Trigger Profile* destruction. Note that this event (destruction from
1065 // memory) is a separate event from profile deletion (from disk).
1066 chrome::CloseAllBrowsers();
1067 ProfileDestructionWaiter(profile).Wait();
1068 EXPECT_EQ(nullptr, [app_controller lastProfileIfLoaded]);
1070 // Re-open the profile. Since the Profile* is destroyed, this involves loading
1072 base::ScopedAllowBlockingForTesting allow_blocking;
1073 profile = profile_manager->GetProfile(profile_path);
1074 [app_controller setLastProfile:profile];
1075 base::RunLoop().RunUntilIdle();
1077 // We mostly want to make sure re-loading the same profile didn't cause a
1078 // crash. This means we didn't have e.g. a dangling ProfilePrefRegistrar, or
1079 // observers pointing to the old (now dead) Profile.
1080 EXPECT_EQ(profile, [app_controller lastProfileIfLoaded]);
1083 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
1084 BookmarksMenuIsRestoredAfterProfileSwitch) {
1085 ProfileManager* profile_manager = g_browser_process->profile_manager();
1086 AppController* app_controller = AppController.sharedController;
1088 [app_controller mainMenuCreated];
1090 // Constants for bookmarks that we will create later.
1091 const std::u16string title1(u"Dinosaur Comics");
1092 const GURL url1("http://qwantz.com//");
1094 const std::u16string title2(u"XKCD");
1095 const GURL url2("https://www.xkcd.com/");
1097 // Use the existing profile as profile 1.
1098 Profile* profile1 = browser()->profile();
1099 bookmarks::test::WaitForBookmarkModelToLoad(
1100 BookmarkModelFactory::GetForBrowserContext(profile1));
1102 // Create profile 2.
1103 base::ScopedAllowBlockingForTesting allow_blocking;
1104 base::FilePath path2 = profile_manager->GenerateNextProfileDirectoryPath();
1105 std::unique_ptr<Profile> profile2 =
1106 Profile::CreateProfile(path2, nullptr, Profile::CREATE_MODE_SYNCHRONOUS);
1107 Profile* profile2_ptr = profile2.get();
1108 profile_manager->RegisterTestingProfile(std::move(profile2), false);
1109 bookmarks::test::WaitForBookmarkModelToLoad(
1110 BookmarkModelFactory::GetForBrowserContext(profile2_ptr));
1112 // Switch to profile 1, create bookmark 1 and force the menu to build.
1113 [app_controller setLastProfile:profile1];
1114 [app_controller bookmarkMenuBridge]->GetBookmarkModel()
1115 -> AddURL([app_controller bookmarkMenuBridge]->GetBookmarkModel()
1116 -> bookmark_bar_node(),
1118 NSMenu* profile1_submenu =
1119 [app_controller bookmarkMenuBridge]->BookmarkMenu();
1120 [[profile1_submenu delegate] menuNeedsUpdate:profile1_submenu];
1122 // Switch to profile 2, create bookmark 2 and force the menu to build.
1123 [app_controller setLastProfile:profile2_ptr];
1124 [app_controller bookmarkMenuBridge]->GetBookmarkModel()
1125 -> AddURL([app_controller bookmarkMenuBridge]->GetBookmarkModel()
1126 -> bookmark_bar_node(),
1128 NSMenu* profile2_submenu =
1129 [app_controller bookmarkMenuBridge]->BookmarkMenu();
1130 [[profile2_submenu delegate] menuNeedsUpdate:profile2_submenu];
1131 EXPECT_NE(profile1_submenu, profile2_submenu);
1133 // Test that only bookmark 2 is shown.
1134 EXPECT_FALSE([[app_controller bookmarkMenuBridge]->BookmarkMenu()
1135 itemWithTitle:base::SysUTF16ToNSString(title1)]);
1136 EXPECT_TRUE([[app_controller bookmarkMenuBridge]->BookmarkMenu()
1137 itemWithTitle:base::SysUTF16ToNSString(title2)]);
1139 // Switch *back* to profile 1 and *don't* force the menu to build.
1140 [app_controller setLastProfile:profile1];
1142 // Test that only bookmark 1 is shown in the restored menu.
1143 EXPECT_TRUE([[app_controller bookmarkMenuBridge]->BookmarkMenu()
1144 itemWithTitle:base::SysUTF16ToNSString(title1)]);
1145 EXPECT_FALSE([[app_controller bookmarkMenuBridge]->BookmarkMenu()
1146 itemWithTitle:base::SysUTF16ToNSString(title2)]);
1148 // Ensure a cached menu was used.
1149 EXPECT_EQ(profile1_submenu,
1150 [app_controller bookmarkMenuBridge]->BookmarkMenu());
1153 // Tests opening a new window from a browser command while incognito is forced.
1154 // Regression test for https://crbug.com/1206726
1155 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
1156 ForcedIncognito_NewWindow) {
1157 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
1158 // Close the current non-incognito browser.
1159 Profile* profile = browser()->profile();
1160 chrome::CloseAllBrowsers();
1161 ui_test_utils::WaitForBrowserToClose();
1162 EXPECT_TRUE(BrowserList::GetInstance()->empty());
1163 // Force incognito mode.
1164 IncognitoModePrefs::SetAvailability(
1165 profile->GetPrefs(), policy::IncognitoModeAvailability::kForced);
1166 // Simulate click on "New window".
1167 ui_test_utils::BrowserChangeObserver browser_added_observer(
1168 nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
1169 AppController* app_controller = AppController.sharedController;
1170 NSMenu* menu = [app_controller applicationDockMenu:NSApp];
1172 NSMenuItem* item = [menu itemWithTag:IDC_NEW_WINDOW];
1174 [app_controller commandDispatch:item];
1175 // Check that a new incognito browser is opened.
1176 Browser* new_browser = browser_added_observer.Wait();
1177 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
1178 EXPECT_TRUE(new_browser->profile()->IsPrimaryOTRProfile());
1179 EXPECT_EQ(profile, new_browser->profile()->GetOriginalProfile());
1182 // Tests opening a new window from dock menu while incognito browser is opened.
1183 // Regression test for https://crbug.com/1371923
1184 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
1185 WhileIncognitoBrowserIsOpened_NewWindow) {
1186 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
1188 // Close the current browser.
1189 Profile* profile = browser()->profile();
1190 chrome::CloseAllBrowsers();
1191 ui_test_utils::WaitForBrowserToClose();
1192 EXPECT_TRUE(BrowserList::GetInstance()->empty());
1194 // Create an incognito browser.
1195 Browser* incognito_browser = CreateIncognitoBrowser(profile);
1196 EXPECT_TRUE(incognito_browser->profile()->IsIncognitoProfile());
1197 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
1198 EXPECT_EQ(incognito_browser, chrome::GetLastActiveBrowser());
1199 // Assure that `windowDidBecomeMain` is called even if this browser process
1200 // lost focus because of other browser processes in other shards taking
1201 // focus. It prevents flakiness.
1202 // See: https://crbug.com/1450491
1203 [[NSNotificationCenter defaultCenter]
1204 postNotificationName:NSWindowDidBecomeMainNotification
1205 object:incognito_browser->window()
1207 .GetNativeNSWindow()];
1209 // Simulate click on "New Window".
1210 ui_test_utils::BrowserChangeObserver browser_added_observer(
1211 nullptr, ui_test_utils::BrowserChangeObserver::ChangeType::kAdded);
1212 AppController* app_controller = AppController.sharedController;
1213 NSMenu* menu = [app_controller applicationDockMenu:NSApp];
1215 NSMenuItem* item = [menu itemWithTag:IDC_NEW_WINDOW];
1217 [app_controller commandDispatch:item];
1219 // Check that a new non-incognito browser is opened.
1220 Browser* new_browser = browser_added_observer.Wait();
1221 EXPECT_EQ(BrowserList::GetInstance()->size(), 2u);
1222 EXPECT_TRUE(new_browser->profile()->IsRegularProfile());
1223 EXPECT_EQ(profile, new_browser->profile());
1226 // Test switching from Regular to OTR profiles updates the history menu.
1227 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
1228 SwitchToIncognitoRemovesHistoryItems) {
1229 ASSERT_TRUE(embedded_test_server()->Start());
1230 AppController* app_controller = AppController.sharedController;
1232 GURL simple(embedded_test_server()->GetURL("/simple.html"));
1233 SendOpenUrlToAppController(simple);
1235 Profile* profile = browser()->profile();
1236 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
1238 // Load profile's History Service backend so it will be assigned to the
1239 // HistoryMenuBridge, or else this test will fail flaky.
1240 ui_test_utils::WaitForHistoryToLoad(HistoryServiceFactory::GetForProfile(
1241 profile, ServiceAccessType::EXPLICIT_ACCESS));
1243 // Verify that history bridge service is available for regular profiles.
1244 EXPECT_TRUE([app_controller historyMenuBridge]->service());
1246 // Open a URL in Incognito window.
1247 ui_test_utils::NavigateToURLWithDisposition(
1248 browser(), simple, WindowOpenDisposition::OFF_THE_RECORD,
1249 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
1251 // Check that there are exactly 2 browsers (regular and incognito).
1252 BrowserList* active_browser_list = BrowserList::GetInstance();
1253 EXPECT_EQ(2u, active_browser_list->size());
1255 // Verify that history bridge service is not available in Incognito.
1256 EXPECT_FALSE([app_controller historyMenuBridge]->service());
1258 // Switch back to the regular profile window.
1259 Browser* browser1 = active_browser_list->get(0);
1260 browser1->window()->Show();
1262 // Verify that history bridge service is available again.
1263 EXPECT_TRUE([app_controller historyMenuBridge]->service());
1266 class AppControllerIncognitoSwitchTest : public InProcessBrowserTest {
1268 void SetUpCommandLine(base::CommandLine* command_line) override {
1269 InProcessBrowserTest::SetUpCommandLine(command_line);
1270 command_line->AppendSwitch(switches::kIncognito);
1274 // Regression test for https://crbug.com/1248661
1275 IN_PROC_BROWSER_TEST_F(AppControllerIncognitoSwitchTest,
1276 ObserveProfileDestruction) {
1277 // Chrome is launched in incognito.
1278 Profile* otr_profile = browser()->profile();
1279 EXPECT_EQ(otr_profile,
1280 otr_profile->GetPrimaryOTRProfile(/*create_if_needed=*/false));
1281 EXPECT_EQ(BrowserList::GetInstance()->size(), 1u);
1282 AppController* app_controller = AppController.sharedController;
1283 [[NSNotificationCenter defaultCenter]
1284 postNotificationName:NSWindowDidBecomeMainNotification
1288 .GetNativeNSWindow()];
1289 // The last profile is the incognito profile.
1290 EXPECT_EQ([app_controller lastProfileIfLoaded], otr_profile);
1291 // Destroy the incognito profile.
1292 ProfileDestructionWaiter waiter(otr_profile);
1293 CloseBrowserSynchronously(browser());
1295 // Check that |-lastProfileIfLoaded| is not pointing to released memory.
1296 EXPECT_NE([app_controller lastProfileIfLoaded], otr_profile);
1301 //--------------------------AppControllerHandoffBrowserTest---------------------
1303 static GURL g_handoff_url;
1304 static std::u16string g_handoff_title;
1306 @interface AppController (BrowserTest)
1307 - (void)new_updateHandoffManagerWithURL:(const GURL&)handoffURL
1308 title:(const std::u16string&)handoffTitle;
1311 @implementation AppController (BrowserTest)
1312 - (void)new_updateHandoffManagerWithURL:(const GURL&)handoffURL
1313 title:(const std::u16string&)handoffTitle {
1314 g_handoff_url = handoffURL;
1315 g_handoff_title = handoffTitle;
1321 class AppControllerHandoffBrowserTest : public InProcessBrowserTest {
1323 // Swizzle Handoff related implementations.
1324 void SetUpInProcessBrowserTestFixture() override {
1325 // This swizzle intercepts the URL that would be sent to the Handoff
1326 // Manager, and instead puts it into a variable accessible to this test.
1327 swizzler_ = std::make_unique<base::apple::ScopedObjCClassSwizzler>(
1328 [AppController class], @selector(updateHandoffManagerWithURL:title:),
1329 @selector(new_updateHandoffManagerWithURL:title:));
1332 void TearDownInProcessBrowserTestFixture() override { swizzler_.reset(); }
1333 // Closes the tab, and waits for the close to finish.
1334 void CloseTab(Browser* browser, int index) {
1335 content::WebContentsDestroyedWatcher destroyed_watcher(
1336 browser->tab_strip_model()->GetWebContentsAt(index));
1337 browser->tab_strip_model()->CloseWebContentsAt(
1338 index, TabCloseTypes::CLOSE_CREATE_HISTORICAL_TAB);
1339 destroyed_watcher.Wait();
1343 std::unique_ptr<base::apple::ScopedObjCClassSwizzler> swizzler_;
1346 // Tests that as a user switches between tabs, navigates within a tab, and
1347 // switches between browser windows, the correct URL is being passed to the
1349 IN_PROC_BROWSER_TEST_F(AppControllerHandoffBrowserTest, TestHandoffURLs) {
1350 ASSERT_TRUE(embedded_test_server()->Start());
1351 EXPECT_EQ(g_handoff_url, GURL(url::kAboutBlankURL));
1352 EXPECT_EQ(g_handoff_title, u"about:blank");
1354 // Test that navigating to a URL updates the handoff manager.
1355 GURL test_url1 = embedded_test_server()->GetURL("/title1.html");
1356 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), test_url1));
1357 EXPECT_EQ(g_handoff_url, test_url1);
1358 EXPECT_TRUE(base::EndsWith(g_handoff_title, u"title1.html"));
1360 // Test that opening a new tab updates the handoff URL.
1361 GURL test_url2 = embedded_test_server()->GetURL("/title2.html");
1362 NavigateParams params(browser(), test_url2, ui::PAGE_TRANSITION_LINK);
1363 params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB;
1364 ui_test_utils::NavigateToURL(¶ms);
1365 EXPECT_EQ(g_handoff_url, test_url2);
1367 // Test that switching tabs updates the handoff URL.
1368 browser()->tab_strip_model()->ActivateTabAt(
1369 0, TabStripUserGestureDetails(
1370 TabStripUserGestureDetails::GestureType::kOther));
1371 EXPECT_EQ(g_handoff_url, test_url1);
1372 EXPECT_TRUE(base::EndsWith(g_handoff_title, u"title1.html"));
1374 // Test that closing the current tab updates the handoff URL.
1375 CloseTab(browser(), 0);
1376 EXPECT_EQ(g_handoff_url, test_url2);
1377 EXPECT_EQ(g_handoff_title, u"Title Of Awesomeness");
1379 // Test that opening a new browser window updates the handoff URL.
1380 GURL test_url3 = embedded_test_server()->GetURL("/title3.html");
1381 ui_test_utils::NavigateToURLWithDisposition(
1382 browser(), GURL(test_url3), WindowOpenDisposition::NEW_WINDOW,
1383 ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP);
1384 EXPECT_EQ(g_handoff_url, test_url3);
1385 EXPECT_EQ(g_handoff_title, u"Title Of More Awesomeness");
1387 // Check that there are exactly 2 browsers.
1388 BrowserList* active_browser_list = BrowserList::GetInstance();
1389 EXPECT_EQ(2u, active_browser_list->size());
1391 // Close the second browser window (which only has 1 tab left).
1392 Browser* browser2 = active_browser_list->get(1);
1393 CloseBrowserSynchronously(browser2);
1394 EXPECT_EQ(g_handoff_url, test_url2);
1395 EXPECT_EQ(g_handoff_title, u"Title Of Awesomeness");
1397 // The URLs of incognito windows should not be passed to Handoff.
1398 GURL test_url4 = embedded_test_server()->GetURL("/simple.html");
1399 ui_test_utils::NavigateToURLWithDisposition(
1400 browser(), GURL(test_url4), WindowOpenDisposition::OFF_THE_RECORD,
1401 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
1402 EXPECT_EQ(g_handoff_url, GURL());
1403 EXPECT_EQ(g_handoff_title, u"");
1405 // Open a new tab in the incognito window.
1406 EXPECT_EQ(2u, active_browser_list->size());
1407 Browser* browser3 = active_browser_list->get(1);
1408 ui_test_utils::NavigateToURLWithDisposition(
1409 browser3, test_url4, WindowOpenDisposition::NEW_FOREGROUND_TAB,
1410 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
1411 EXPECT_EQ(g_handoff_url, GURL());
1412 EXPECT_EQ(g_handoff_title, u"");
1414 // Navigate the current tab in the incognito window.
1415 ASSERT_TRUE(ui_test_utils::NavigateToURL(browser3, test_url1));
1416 EXPECT_EQ(g_handoff_url, GURL());
1417 EXPECT_EQ(g_handoff_title, u"");
1419 // Activate the original browser window.
1420 Browser* browser1 = active_browser_list->get(0);
1421 browser1->window()->Show();
1422 EXPECT_EQ(g_handoff_url, test_url2);
1423 EXPECT_EQ(g_handoff_title, u"Title Of Awesomeness");
1426 class AppControllerHandoffPrerenderBrowserTest
1427 : public AppControllerHandoffBrowserTest {
1429 void SetUpOnMainThread() override {
1430 prerender_helper_.RegisterServerRequestMonitor(embedded_test_server());
1431 host_resolver()->AddRule("*", "127.0.0.1");
1432 embedded_test_server()->ServeFilesFromDirectory(
1433 base::PathService::CheckedGet(chrome::DIR_TEST_DATA));
1434 ASSERT_TRUE(embedded_test_server()->Start());
1437 content::WebContents* GetActiveWebContents() {
1438 return browser()->tab_strip_model()->GetActiveWebContents();
1441 content::test::PrerenderTestHelper& prerender_helper() {
1442 return prerender_helper_;
1446 AppControllerHandoffPrerenderBrowserTest()
1447 : prerender_helper_(base::BindRepeating(
1448 &AppControllerHandoffPrerenderBrowserTest::GetActiveWebContents,
1449 // Unretained is safe here, as this class owns PrerenderTestHelper
1450 // object, which holds the callback being constructed here, so the
1451 // callback will be destructed before this class.
1452 base::Unretained(this))) {}
1455 content::test::PrerenderTestHelper prerender_helper_;
1458 // Tests that as a user switches from main page to prerendered page, the correct
1459 // URL is being passed to the Handoff.
1460 IN_PROC_BROWSER_TEST_F(AppControllerHandoffPrerenderBrowserTest,
1462 // Navigate to an initial page.
1463 GURL url = embedded_test_server()->GetURL("/empty.html");
1464 ASSERT_TRUE(content::NavigateToURL(GetActiveWebContents(), url));
1466 // Start a prerender.
1467 GURL prerender_url = embedded_test_server()->GetURL("/simple.html");
1468 prerender_helper().AddPrerender(prerender_url);
1469 EXPECT_EQ(g_handoff_url, url);
1472 content::TestActivationManager navigation_manager(GetActiveWebContents(),
1475 content::ExecJs(GetActiveWebContents()->GetPrimaryMainFrame(),
1476 content::JsReplace("location = $1", prerender_url)));
1477 navigation_manager.WaitForNavigationFinished();
1478 EXPECT_TRUE(navigation_manager.was_activated());
1479 EXPECT_TRUE(navigation_manager.was_successful());
1480 EXPECT_EQ(g_handoff_url, prerender_url);