1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #import <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>
12 #include "base/command_line.h"
13 #include "base/mac/foundation_util.h"
14 #include "base/mac/scoped_nsobject.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/run_loop.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "chrome/app/chrome_command_ids.h"
20 #import "chrome/browser/app_controller_mac.h"
21 #include "chrome/browser/apps/app_browsertest_util.h"
22 #include "chrome/browser/bookmarks/bookmark_model_factory.h"
23 #include "chrome/browser/browser_process.h"
24 #include "chrome/browser/history/history_service_factory.h"
25 #include "chrome/browser/profiles/profile_manager.h"
26 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/browser_list.h"
28 #include "chrome/browser/ui/browser_window.h"
29 #include "chrome/browser/ui/cocoa/bookmarks/bookmark_menu_bridge.h"
30 #include "chrome/browser/ui/cocoa/history_menu_bridge.h"
31 #include "chrome/browser/ui/cocoa/run_loop_testing.h"
32 #include "chrome/browser/ui/host_desktop.h"
33 #include "chrome/browser/ui/tabs/tab_strip_model.h"
34 #include "chrome/browser/ui/user_manager.h"
35 #include "chrome/common/chrome_constants.h"
36 #include "chrome/common/chrome_switches.h"
37 #include "chrome/common/pref_names.h"
38 #include "chrome/common/url_constants.h"
39 #include "chrome/test/base/in_process_browser_test.h"
40 #include "chrome/test/base/ui_test_utils.h"
41 #include "components/bookmarks/browser/bookmark_model.h"
42 #include "components/bookmarks/test/bookmark_test_helpers.h"
43 #include "components/signin/core/common/profile_management_switches.h"
44 #include "content/public/browser/web_contents.h"
45 #include "content/public/test/browser_test_utils.h"
46 #include "content/public/test/test_navigation_observer.h"
47 #include "extensions/browser/app_window/app_window_registry.h"
48 #include "extensions/common/extension.h"
49 #include "extensions/test/extension_test_message_listener.h"
50 #include "net/test/embedded_test_server/embedded_test_server.h"
54 GURL g_open_shortcut_url = GURL::EmptyGURL();
56 // Returns an Apple Event that instructs the application to open |url|.
57 NSAppleEventDescriptor* AppleEventToOpenUrl(const GURL& url) {
58 NSAppleEventDescriptor* shortcut_event = [[[NSAppleEventDescriptor alloc]
59 initWithEventClass:kASAppleScriptSuite
60 eventID:kASSubroutineEvent
62 returnID:kAutoGenerateReturnID
63 transactionID:kAnyTransactionID] autorelease];
64 NSString* url_string = [NSString stringWithUTF8String:url.spec().c_str()];
65 [shortcut_event setParamDescriptor:[NSAppleEventDescriptor
66 descriptorWithString:url_string]
67 forKeyword:keyDirectObject];
68 return shortcut_event;
71 // Instructs the NSApp's delegate to open |url|.
72 void SendAppleEventToOpenUrlToAppController(const GURL& url) {
73 AppController* controller =
74 base::mac::ObjCCast<AppController>([NSApp delegate]);
76 class_getInstanceMethod([controller class], @selector(getUrl:withReply:));
80 NSAppleEventDescriptor* shortcut_event = AppleEventToOpenUrl(url);
82 method_invoke(controller, get_url, shortcut_event, NULL);
85 void RunClosureWhenProfileInitialized(const base::Closure& closure,
87 Profile::CreateStatus status) {
88 if (status == Profile::CREATE_STATUS_INITIALIZED)
94 @interface TestOpenShortcutOnStartup : NSObject
95 - (void)applicationWillFinishLaunching:(NSNotification*)notification;
98 @implementation TestOpenShortcutOnStartup
100 - (void)applicationWillFinishLaunching:(NSNotification*)notification {
101 if (!g_open_shortcut_url.is_valid())
104 SendAppleEventToOpenUrlToAppController(g_open_shortcut_url);
111 class AppControllerPlatformAppBrowserTest
112 : public extensions::PlatformAppBrowserTest {
114 AppControllerPlatformAppBrowserTest()
115 : active_browser_list_(BrowserList::GetInstance(
116 chrome::GetActiveDesktop())) {
119 void SetUpCommandLine(base::CommandLine* command_line) override {
120 PlatformAppBrowserTest::SetUpCommandLine(command_line);
121 command_line->AppendSwitchASCII(switches::kAppId,
125 const BrowserList* active_browser_list_;
128 // Test that if only a platform app window is open and no browser windows are
129 // open then a reopen event does nothing.
130 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
131 PlatformAppReopenWithWindows) {
132 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
133 NSUInteger old_window_count = [[NSApp windows] count];
134 EXPECT_EQ(1u, active_browser_list_->size());
135 [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:YES];
136 // We do not EXPECT_TRUE the result here because the method
137 // deminiaturizes windows manually rather than return YES and have
140 EXPECT_EQ(old_window_count, [[NSApp windows] count]);
141 EXPECT_EQ(1u, active_browser_list_->size());
144 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
145 ActivationFocusesBrowserWindow) {
146 base::scoped_nsobject<AppController> app_controller(
147 [[AppController alloc] init]);
149 ExtensionTestMessageListener listener("Launched", false);
150 const extensions::Extension* app =
151 InstallAndLaunchPlatformApp("minimal");
152 ASSERT_TRUE(listener.WaitUntilSatisfied());
154 NSWindow* app_window = extensions::AppWindowRegistry::Get(profile())
155 ->GetAppWindowsForApp(app->id())
158 NSWindow* browser_window = browser()->window()->GetNativeWindow();
160 chrome::testing::NSRunLoopRunAllPending();
161 EXPECT_LE([[NSApp orderedWindows] indexOfObject:app_window],
162 [[NSApp orderedWindows] indexOfObject:browser_window]);
163 [app_controller applicationShouldHandleReopen:NSApp
164 hasVisibleWindows:YES];
165 chrome::testing::NSRunLoopRunAllPending();
166 EXPECT_LE([[NSApp orderedWindows] indexOfObject:browser_window],
167 [[NSApp orderedWindows] indexOfObject:app_window]);
170 class AppControllerWebAppBrowserTest : public InProcessBrowserTest {
172 AppControllerWebAppBrowserTest()
173 : active_browser_list_(BrowserList::GetInstance(
174 chrome::GetActiveDesktop())) {
177 void SetUpCommandLine(base::CommandLine* command_line) override {
178 command_line->AppendSwitchASCII(switches::kApp, GetAppURL());
181 std::string GetAppURL() const {
182 return "http://example.com/";
185 const BrowserList* active_browser_list_;
188 // Test that in web app mode a reopen event opens the app URL.
189 IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest,
190 WebAppReopenWithNoWindows) {
191 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
192 EXPECT_EQ(1u, active_browser_list_->size());
193 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
195 EXPECT_FALSE(result);
196 EXPECT_EQ(2u, active_browser_list_->size());
198 Browser* browser = active_browser_list_->get(0);
200 browser->tab_strip_model()->GetActiveWebContents()->GetURL();
201 EXPECT_EQ(GetAppURL(), current_url.spec());
204 // Called when the ProfileManager has created a profile.
205 void CreateProfileCallback(const base::Closure& quit_closure,
207 Profile::CreateStatus status) {
208 EXPECT_TRUE(profile);
209 EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status);
210 EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status);
211 // This will be called multiple times. Wait until the profile is initialized
212 // fully to quit the loop.
213 if (status == Profile::CREATE_STATUS_INITIALIZED)
217 void CreateAndWaitForSystemProfile() {
218 ProfileManager::CreateCallback create_callback =
219 base::Bind(&CreateProfileCallback,
220 base::MessageLoop::current()->QuitClosure());
221 g_browser_process->profile_manager()->CreateProfileAsync(
222 ProfileManager::GetSystemProfilePath(),
227 base::RunLoop().Run();
230 class AppControllerNewProfileManagementBrowserTest
231 : public InProcessBrowserTest {
233 AppControllerNewProfileManagementBrowserTest()
234 : active_browser_list_(BrowserList::GetInstance(
235 chrome::GetActiveDesktop())) {
238 void SetUpCommandLine(base::CommandLine* command_line) override {
239 switches::EnableNewProfileManagementForTesting(command_line);
242 const BrowserList* active_browser_list_;
245 // Test that for a regular last profile, a reopen event opens a browser.
246 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
247 RegularProfileReopenWithNoWindows) {
248 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
249 EXPECT_EQ(1u, active_browser_list_->size());
250 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
252 EXPECT_FALSE(result);
253 EXPECT_EQ(2u, active_browser_list_->size());
254 EXPECT_FALSE(UserManager::IsShowing());
257 // Test that for a locked last profile, a reopen event opens the User Manager.
258 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
259 LockedProfileReopenWithNoWindows) {
260 // The User Manager uses the system profile as its underlying profile. To
261 // minimize flakiness due to the scheduling/descheduling of tasks on the
262 // different threads, pre-initialize the guest profile before it is needed.
263 CreateAndWaitForSystemProfile();
264 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
266 // Lock the active profile.
267 Profile* profile = [ac lastProfile];
268 ProfileInfoCache& cache =
269 g_browser_process->profile_manager()->GetProfileInfoCache();
270 size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
271 cache.SetProfileSigninRequiredAtIndex(profile_index, true);
272 EXPECT_TRUE(cache.ProfileIsSigninRequiredAtIndex(profile_index));
274 EXPECT_EQ(1u, active_browser_list_->size());
275 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
276 EXPECT_FALSE(result);
278 base::RunLoop().RunUntilIdle();
279 EXPECT_EQ(1u, active_browser_list_->size());
280 EXPECT_TRUE(UserManager::IsShowing());
284 // Test that for a guest last profile, a reopen event opens the User Manager.
285 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
286 GuestProfileReopenWithNoWindows) {
287 // Create the system profile. Set the guest as the last used profile so the
288 // app controller can use it on init.
289 CreateAndWaitForSystemProfile();
290 PrefService* local_state = g_browser_process->local_state();
291 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
293 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
295 Profile* profile = [ac lastProfile];
296 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath());
297 EXPECT_TRUE(profile->IsGuestSession());
299 EXPECT_EQ(1u, active_browser_list_->size());
300 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
301 EXPECT_FALSE(result);
303 base::RunLoop().RunUntilIdle();
305 EXPECT_EQ(1u, active_browser_list_->size());
306 EXPECT_TRUE(UserManager::IsShowing());
310 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
311 AboutChromeForcesUserManager) {
312 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
314 // Create the guest profile, and set it as the last used profile so the
315 // app controller can use it on init.
316 CreateAndWaitForSystemProfile();
317 PrefService* local_state = g_browser_process->local_state();
318 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
320 // Prohibiting guest mode forces the user manager flow for About Chrome.
321 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
323 Profile* guest_profile = [ac lastProfile];
324 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), guest_profile->GetPath());
325 EXPECT_TRUE(guest_profile->IsGuestSession());
327 // Tell the browser to open About Chrome.
328 EXPECT_EQ(1u, active_browser_list_->size());
329 [ac orderFrontStandardAboutPanel:NSApp];
331 base::RunLoop().RunUntilIdle();
333 // No new browser is opened; the User Manager opens instead.
334 EXPECT_EQ(1u, active_browser_list_->size());
335 EXPECT_TRUE(UserManager::IsShowing());
340 class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest {
342 AppControllerOpenShortcutBrowserTest() {
345 void SetUpInProcessBrowserTestFixture() override {
346 // In order to mimic opening shortcut during browser startup, we need to
347 // send the event before -applicationDidFinishLaunching is called, but
348 // after AppController is loaded.
350 // Since -applicationWillFinishLaunching does nothing now, we swizzle it to
351 // our function to send the event. We need to do this early before running
352 // the main message loop.
354 // NSApp does not exist yet. We need to get the AppController using
356 Class appControllerClass = NSClassFromString(@"AppController");
357 Class openShortcutClass = NSClassFromString(@"TestOpenShortcutOnStartup");
359 ASSERT_TRUE(appControllerClass != nil);
360 ASSERT_TRUE(openShortcutClass != nil);
362 SEL targetMethod = @selector(applicationWillFinishLaunching:);
363 Method original = class_getInstanceMethod(appControllerClass,
365 Method destination = class_getInstanceMethod(openShortcutClass,
368 ASSERT_TRUE(original != NULL);
369 ASSERT_TRUE(destination != NULL);
371 method_exchangeImplementations(original, destination);
373 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
374 g_open_shortcut_url = embedded_test_server()->GetURL("/simple.html");
377 void SetUpCommandLine(base::CommandLine* command_line) override {
378 // If the arg is empty, PrepareTestCommandLine() after this function will
379 // append about:blank as default url.
380 command_line->AppendArg(chrome::kChromeUINewTabURL);
384 IN_PROC_BROWSER_TEST_F(AppControllerOpenShortcutBrowserTest,
385 OpenShortcutOnStartup) {
386 EXPECT_EQ(1, browser()->tab_strip_model()->count());
387 EXPECT_EQ(g_open_shortcut_url,
388 browser()->tab_strip_model()->GetActiveWebContents()
389 ->GetLastCommittedURL());
392 class AppControllerReplaceNTPBrowserTest : public InProcessBrowserTest {
394 AppControllerReplaceNTPBrowserTest() {}
396 void SetUpInProcessBrowserTestFixture() override {
397 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
400 void SetUpCommandLine(base::CommandLine* command_line) override {
401 // If the arg is empty, PrepareTestCommandLine() after this function will
402 // append about:blank as default url.
403 command_line->AppendArg(chrome::kChromeUINewTabURL);
407 // Tests that when a GURL is opened after startup, it replaces the NTP.
408 IN_PROC_BROWSER_TEST_F(AppControllerReplaceNTPBrowserTest,
409 ReplaceNTPAfterStartup) {
410 // Ensure that there is exactly 1 tab showing, and the tab is the NTP.
411 GURL ntp(chrome::kChromeUINewTabURL);
412 EXPECT_EQ(1, browser()->tab_strip_model()->count());
416 ->GetActiveWebContents()
417 ->GetLastCommittedURL());
419 GURL simple(embedded_test_server()->GetURL("/simple.html"));
420 SendAppleEventToOpenUrlToAppController(simple);
422 // Wait for one navigation on the active web contents.
423 EXPECT_EQ(1, browser()->tab_strip_model()->count());
424 content::TestNavigationObserver obs(
425 browser()->tab_strip_model()->GetActiveWebContents(), 1);
431 ->GetActiveWebContents()
432 ->GetLastCommittedURL());
435 class AppControllerMainMenuBrowserTest : public InProcessBrowserTest {
437 AppControllerMainMenuBrowserTest() {
441 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
442 HistoryMenuResetAfterProfileDeletion) {
443 ProfileManager* profile_manager = g_browser_process->profile_manager();
444 AppController* ac = [NSApp delegate];
446 // Use the existing profile as profile 1.
447 Profile* profile1 = browser()->profile();
450 base::FilePath profile2_path =
451 profile_manager->GenerateNextProfileDirectoryPath();
452 base::RunLoop run_loop;
453 profile_manager->CreateProfileAsync(
455 base::Bind(&RunClosureWhenProfileInitialized,
456 run_loop.QuitClosure()),
461 Profile* profile2 = profile_manager->GetProfileByPath(profile2_path);
462 ASSERT_TRUE(profile2);
464 // Switch the controller to profile1.
465 [ac windowChangedToProfile:profile1];
466 base::RunLoop().RunUntilIdle();
468 // Verify the controller's History Menu corresponds to profile1.
469 EXPECT_TRUE([ac historyMenuBridge]->service());
470 EXPECT_EQ([ac historyMenuBridge]->service(),
471 HistoryServiceFactory::GetForProfile(profile1,
472 ServiceAccessType::EXPLICIT_ACCESS));
474 // Load profile2's History Service backend so it will be assigned to the
475 // HistoryMenuBridge when windowChangedToProfile is called, or else this test
477 ui_test_utils::WaitForHistoryToLoad(
478 HistoryServiceFactory::GetForProfile(profile2,
479 ServiceAccessType::EXPLICIT_ACCESS));
480 // Switch the controller to profile2.
481 [ac windowChangedToProfile:profile2];
482 base::RunLoop().RunUntilIdle();
484 // Verify the controller's History Menu has changed.
485 EXPECT_TRUE([ac historyMenuBridge]->service());
486 EXPECT_EQ([ac historyMenuBridge]->service(),
487 HistoryServiceFactory::GetForProfile(profile2,
488 ServiceAccessType::EXPLICIT_ACCESS));
490 HistoryServiceFactory::GetForProfile(profile1,
491 ServiceAccessType::EXPLICIT_ACCESS),
492 HistoryServiceFactory::GetForProfile(profile2,
493 ServiceAccessType::EXPLICIT_ACCESS));
496 profile_manager->ScheduleProfileForDeletion(
497 profile2->GetPath(), ProfileManager::CreateCallback());
498 base::RunLoop().RunUntilIdle();
500 // Verify the controller's history is back to profile1.
501 EXPECT_EQ([ac historyMenuBridge]->service(),
502 HistoryServiceFactory::GetForProfile(profile1,
503 ServiceAccessType::EXPLICIT_ACCESS));
506 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
507 BookmarksMenuIsRestoredAfterProfileSwitch) {
508 ProfileManager* profile_manager = g_browser_process->profile_manager();
509 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
512 // Constants for bookmarks that we will create later.
513 const base::string16 title1(base::ASCIIToUTF16("Dinosaur Comics"));
514 const GURL url1("http://qwantz.com//");
516 const base::string16 title2(base::ASCIIToUTF16("XKCD"));
517 const GURL url2("https://www.xkcd.com/");
519 // Use the existing profile as profile 1.
520 Profile* profile1 = browser()->profile();
521 bookmarks::test::WaitForBookmarkModelToLoad(
522 BookmarkModelFactory::GetForProfile(profile1));
525 base::FilePath path2 = profile_manager->GenerateNextProfileDirectoryPath();
527 Profile::CreateProfile(path2, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
528 profile_manager->RegisterTestingProfile(profile2, false, true);
529 bookmarks::test::WaitForBookmarkModelToLoad(
530 BookmarkModelFactory::GetForProfile(profile2));
532 // Switch to profile 1, create bookmark 1 and force the menu to build.
533 [ac windowChangedToProfile:profile1];
534 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
535 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
537 [ac bookmarkMenuBridge]->BuildMenu();
539 // Switch to profile 2, create bookmark 2 and force the menu to build.
540 [ac windowChangedToProfile:profile2];
541 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
542 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
544 [ac bookmarkMenuBridge]->BuildMenu();
546 // Test that only bookmark 2 is shown.
547 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
548 SysUTF16ToNSString(title1)]);
549 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
550 SysUTF16ToNSString(title2)]);
552 // Switch *back* to profile 1 and *don't* force the menu to build.
553 [ac windowChangedToProfile:profile1];
555 // Test that only bookmark 1 is shown in the restored menu.
556 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
557 SysUTF16ToNSString(title1)]);
558 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
559 SysUTF16ToNSString(title2)]);
564 //--------------------------AppControllerHandoffBrowserTest---------------------
566 static GURL g_handoff_url;
568 @interface AppController (BrowserTest)
569 - (BOOL)new_shouldUseHandoff;
570 - (void)new_passURLToHandoffManager:(const GURL&)handoffURL;
573 @implementation AppController (BrowserTest)
574 - (BOOL)new_shouldUseHandoff {
578 - (void)new_passURLToHandoffManager:(const GURL&)handoffURL {
579 g_handoff_url = handoffURL;
585 class AppControllerHandoffBrowserTest : public InProcessBrowserTest {
587 AppControllerHandoffBrowserTest() {}
589 // Exchanges the implementations of the two selectors on the class
591 void ExchangeSelectors(SEL originalMethod, SEL newMethod) {
592 Class appControllerClass = NSClassFromString(@"AppController");
594 ASSERT_TRUE(appControllerClass != nil);
597 class_getInstanceMethod(appControllerClass, originalMethod);
598 Method destination = class_getInstanceMethod(appControllerClass, newMethod);
600 ASSERT_TRUE(original != NULL);
601 ASSERT_TRUE(destination != NULL);
603 method_exchangeImplementations(original, destination);
606 // Swizzle Handoff related implementations.
607 void SetUpInProcessBrowserTestFixture() override {
608 // Handoff is only available on OSX 10.10+. This swizzle makes the logic
609 // run on all OSX versions.
610 SEL originalMethod = @selector(shouldUseHandoff);
611 SEL newMethod = @selector(new_shouldUseHandoff);
612 ExchangeSelectors(originalMethod, newMethod);
614 // This swizzle intercepts the URL that would be sent to the Handoff
615 // Manager, and instead puts it into a variable accessible to this test.
616 originalMethod = @selector(passURLToHandoffManager:);
617 newMethod = @selector(new_passURLToHandoffManager:);
618 ExchangeSelectors(originalMethod, newMethod);
621 // Closes the tab, and waits for the close to finish.
622 void CloseTab(Browser* browser, int index) {
623 content::WebContentsDestroyedWatcher destroyed_watcher(
624 browser->tab_strip_model()->GetWebContentsAt(index));
625 browser->tab_strip_model()->CloseWebContentsAt(
626 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
627 destroyed_watcher.Wait();
631 // Tests that as a user switches between tabs, navigates within a tab, and
632 // switches between browser windows, the correct URL is being passed to the
634 IN_PROC_BROWSER_TEST_F(AppControllerHandoffBrowserTest, TestHandoffURLs) {
635 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
636 EXPECT_EQ(g_handoff_url, GURL(url::kAboutBlankURL));
638 // Test that navigating to a URL updates the handoff URL.
639 GURL test_url1 = embedded_test_server()->GetURL("/title1.html");
640 ui_test_utils::NavigateToURL(browser(), test_url1);
641 EXPECT_EQ(g_handoff_url, test_url1);
643 // Test that opening a new tab updates the handoff URL.
644 GURL test_url2 = embedded_test_server()->GetURL("/title2.html");
645 chrome::NavigateParams params(browser(), test_url2, ui::PAGE_TRANSITION_LINK);
646 params.disposition = NEW_FOREGROUND_TAB;
647 ui_test_utils::NavigateToURL(¶ms);
648 EXPECT_EQ(g_handoff_url, test_url2);
650 // Test that switching tabs updates the handoff URL.
651 browser()->tab_strip_model()->ActivateTabAt(0, true);
652 EXPECT_EQ(g_handoff_url, test_url1);
654 // Test that closing the current tab updates the handoff URL.
655 CloseTab(browser(), 0);
656 EXPECT_EQ(g_handoff_url, test_url2);
658 // Test that opening a new browser window updates the handoff URL.
659 GURL test_url3 = embedded_test_server()->GetURL("/title3.html");
660 ui_test_utils::NavigateToURLWithDisposition(
661 browser(), GURL(test_url3), NEW_WINDOW,
662 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
663 EXPECT_EQ(g_handoff_url, test_url3);
665 // Check that there are exactly 2 browsers.
666 BrowserList* active_browser_list =
667 BrowserList::GetInstance(chrome::GetActiveDesktop());
668 EXPECT_EQ(2u, active_browser_list->size());
670 // Close the second browser window (which only has 1 tab left).
671 Browser* browser2 = active_browser_list->get(1);
672 CloseBrowserSynchronously(browser2);
673 EXPECT_EQ(g_handoff_url, test_url2);
675 // The URLs of incognito windows should not be passed to Handoff.
676 GURL test_url4 = embedded_test_server()->GetURL("/simple.html");
677 ui_test_utils::NavigateToURLWithDisposition(
678 browser(), GURL(test_url4), OFF_THE_RECORD,
679 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
680 EXPECT_EQ(g_handoff_url, GURL());
682 // Open a new tab in the incognito window.
683 EXPECT_EQ(2u, active_browser_list->size());
684 Browser* browser3 = active_browser_list->get(1);
685 ui_test_utils::NavigateToURLWithDisposition(
686 browser3, test_url4, NEW_FOREGROUND_TAB,
687 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
688 EXPECT_EQ(g_handoff_url, GURL());
690 // Navigate the current tab in the incognito window.
691 ui_test_utils::NavigateToURL(browser3, test_url1);
692 EXPECT_EQ(g_handoff_url, GURL());
694 // Activate the original browser window.
695 Browser* browser1 = active_browser_list->get(0);
696 browser1->window()->Show();
697 EXPECT_EQ(g_handoff_url, test_url2);