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/host_desktop.h"
32 #include "chrome/browser/ui/tabs/tab_strip_model.h"
33 #include "chrome/browser/ui/user_manager.h"
34 #include "chrome/common/chrome_constants.h"
35 #include "chrome/common/chrome_switches.h"
36 #include "chrome/common/pref_names.h"
37 #include "chrome/common/url_constants.h"
38 #include "chrome/test/base/in_process_browser_test.h"
39 #include "chrome/test/base/ui_test_utils.h"
40 #include "components/bookmarks/browser/bookmark_model.h"
41 #include "components/bookmarks/test/bookmark_test_helpers.h"
42 #include "components/signin/core/common/profile_management_switches.h"
43 #include "content/public/browser/web_contents.h"
44 #include "content/public/test/browser_test_utils.h"
45 #include "content/public/test/test_navigation_observer.h"
46 #include "extensions/browser/app_window/app_window_registry.h"
47 #include "extensions/common/extension.h"
48 #include "extensions/test/extension_test_message_listener.h"
49 #include "net/test/embedded_test_server/embedded_test_server.h"
53 GURL g_open_shortcut_url = GURL::EmptyGURL();
55 // Returns an Apple Event that instructs the application to open |url|.
56 NSAppleEventDescriptor* AppleEventToOpenUrl(const GURL& url) {
57 NSAppleEventDescriptor* shortcut_event = [[[NSAppleEventDescriptor alloc]
58 initWithEventClass:kASAppleScriptSuite
59 eventID:kASSubroutineEvent
61 returnID:kAutoGenerateReturnID
62 transactionID:kAnyTransactionID] autorelease];
63 NSString* url_string = [NSString stringWithUTF8String:url.spec().c_str()];
64 [shortcut_event setParamDescriptor:[NSAppleEventDescriptor
65 descriptorWithString:url_string]
66 forKeyword:keyDirectObject];
67 return shortcut_event;
70 // Instructs the NSApp's delegate to open |url|.
71 void SendAppleEventToOpenUrlToAppController(const GURL& url) {
72 AppController* controller =
73 base::mac::ObjCCast<AppController>([NSApp delegate]);
75 class_getInstanceMethod([controller class], @selector(getUrl:withReply:));
79 NSAppleEventDescriptor* shortcut_event = AppleEventToOpenUrl(url);
81 method_invoke(controller, get_url, shortcut_event, NULL);
84 void RunClosureWhenProfileInitialized(const base::Closure& closure,
86 Profile::CreateStatus status) {
87 if (status == Profile::CREATE_STATUS_INITIALIZED)
93 @interface TestOpenShortcutOnStartup : NSObject
94 - (void)applicationWillFinishLaunching:(NSNotification*)notification;
97 @implementation TestOpenShortcutOnStartup
99 - (void)applicationWillFinishLaunching:(NSNotification*)notification {
100 if (!g_open_shortcut_url.is_valid())
103 SendAppleEventToOpenUrlToAppController(g_open_shortcut_url);
110 class AppControllerPlatformAppBrowserTest
111 : public extensions::PlatformAppBrowserTest {
113 AppControllerPlatformAppBrowserTest()
114 : active_browser_list_(BrowserList::GetInstance(
115 chrome::GetActiveDesktop())) {
118 void SetUpCommandLine(base::CommandLine* command_line) override {
119 PlatformAppBrowserTest::SetUpCommandLine(command_line);
120 command_line->AppendSwitchASCII(switches::kAppId,
124 const BrowserList* active_browser_list_;
127 // Test that if only a platform app window is open and no browser windows are
128 // open then a reopen event does nothing.
129 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
130 PlatformAppReopenWithWindows) {
131 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
132 NSUInteger old_window_count = [[NSApp windows] count];
133 EXPECT_EQ(1u, active_browser_list_->size());
134 [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:YES];
135 // We do not EXPECT_TRUE the result here because the method
136 // deminiaturizes windows manually rather than return YES and have
139 EXPECT_EQ(old_window_count, [[NSApp windows] count]);
140 EXPECT_EQ(1u, active_browser_list_->size());
143 IN_PROC_BROWSER_TEST_F(AppControllerPlatformAppBrowserTest,
144 ActivationFocusesBrowserWindow) {
145 base::scoped_nsobject<AppController> app_controller(
146 [[AppController alloc] init]);
148 ExtensionTestMessageListener listener("Launched", false);
149 const extensions::Extension* app =
150 InstallAndLaunchPlatformApp("minimal");
151 ASSERT_TRUE(listener.WaitUntilSatisfied());
153 NSWindow* app_window = extensions::AppWindowRegistry::Get(profile())
154 ->GetAppWindowsForApp(app->id())
157 NSWindow* browser_window = browser()->window()->GetNativeWindow();
159 EXPECT_LE([[NSApp orderedWindows] indexOfObject:app_window],
160 [[NSApp orderedWindows] indexOfObject:browser_window]);
161 [app_controller applicationShouldHandleReopen:NSApp
162 hasVisibleWindows:YES];
163 EXPECT_LE([[NSApp orderedWindows] indexOfObject:browser_window],
164 [[NSApp orderedWindows] indexOfObject:app_window]);
167 class AppControllerWebAppBrowserTest : public InProcessBrowserTest {
169 AppControllerWebAppBrowserTest()
170 : active_browser_list_(BrowserList::GetInstance(
171 chrome::GetActiveDesktop())) {
174 void SetUpCommandLine(base::CommandLine* command_line) override {
175 command_line->AppendSwitchASCII(switches::kApp, GetAppURL());
178 std::string GetAppURL() const {
179 return "http://example.com/";
182 const BrowserList* active_browser_list_;
185 // Test that in web app mode a reopen event opens the app URL.
186 IN_PROC_BROWSER_TEST_F(AppControllerWebAppBrowserTest,
187 WebAppReopenWithNoWindows) {
188 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
189 EXPECT_EQ(1u, active_browser_list_->size());
190 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
192 EXPECT_FALSE(result);
193 EXPECT_EQ(2u, active_browser_list_->size());
195 Browser* browser = active_browser_list_->get(0);
197 browser->tab_strip_model()->GetActiveWebContents()->GetURL();
198 EXPECT_EQ(GetAppURL(), current_url.spec());
201 // Called when the ProfileManager has created a profile.
202 void CreateProfileCallback(const base::Closure& quit_closure,
204 Profile::CreateStatus status) {
205 EXPECT_TRUE(profile);
206 EXPECT_NE(Profile::CREATE_STATUS_LOCAL_FAIL, status);
207 EXPECT_NE(Profile::CREATE_STATUS_REMOTE_FAIL, status);
208 // This will be called multiple times. Wait until the profile is initialized
209 // fully to quit the loop.
210 if (status == Profile::CREATE_STATUS_INITIALIZED)
214 void CreateAndWaitForSystemProfile() {
215 ProfileManager::CreateCallback create_callback =
216 base::Bind(&CreateProfileCallback,
217 base::MessageLoop::current()->QuitClosure());
218 g_browser_process->profile_manager()->CreateProfileAsync(
219 ProfileManager::GetSystemProfilePath(),
224 base::RunLoop().Run();
227 class AppControllerNewProfileManagementBrowserTest
228 : public InProcessBrowserTest {
230 AppControllerNewProfileManagementBrowserTest()
231 : active_browser_list_(BrowserList::GetInstance(
232 chrome::GetActiveDesktop())) {
235 void SetUpCommandLine(base::CommandLine* command_line) override {
236 switches::EnableNewProfileManagementForTesting(command_line);
239 const BrowserList* active_browser_list_;
242 // Test that for a regular last profile, a reopen event opens a browser.
243 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
244 RegularProfileReopenWithNoWindows) {
245 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
246 EXPECT_EQ(1u, active_browser_list_->size());
247 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
249 EXPECT_FALSE(result);
250 EXPECT_EQ(2u, active_browser_list_->size());
251 EXPECT_FALSE(UserManager::IsShowing());
254 // Test that for a locked last profile, a reopen event opens the User Manager.
255 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
256 LockedProfileReopenWithNoWindows) {
257 // The User Manager uses the system profile as its underlying profile. To
258 // minimize flakiness due to the scheduling/descheduling of tasks on the
259 // different threads, pre-initialize the guest profile before it is needed.
260 CreateAndWaitForSystemProfile();
261 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
263 // Lock the active profile.
264 Profile* profile = [ac lastProfile];
265 ProfileInfoCache& cache =
266 g_browser_process->profile_manager()->GetProfileInfoCache();
267 size_t profile_index = cache.GetIndexOfProfileWithPath(profile->GetPath());
268 cache.SetProfileSigninRequiredAtIndex(profile_index, true);
269 EXPECT_TRUE(cache.ProfileIsSigninRequiredAtIndex(profile_index));
271 EXPECT_EQ(1u, active_browser_list_->size());
272 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
273 EXPECT_FALSE(result);
275 base::RunLoop().RunUntilIdle();
276 EXPECT_EQ(1u, active_browser_list_->size());
277 EXPECT_TRUE(UserManager::IsShowing());
281 // Test that for a guest last profile, a reopen event opens the User Manager.
282 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
283 GuestProfileReopenWithNoWindows) {
284 // Create the system profile. Set the guest as the last used profile so the
285 // app controller can use it on init.
286 CreateAndWaitForSystemProfile();
287 PrefService* local_state = g_browser_process->local_state();
288 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
290 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
292 Profile* profile = [ac lastProfile];
293 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), profile->GetPath());
294 EXPECT_TRUE(profile->IsGuestSession());
296 EXPECT_EQ(1u, active_browser_list_->size());
297 BOOL result = [ac applicationShouldHandleReopen:NSApp hasVisibleWindows:NO];
298 EXPECT_FALSE(result);
300 base::RunLoop().RunUntilIdle();
302 EXPECT_EQ(1u, active_browser_list_->size());
303 EXPECT_TRUE(UserManager::IsShowing());
307 IN_PROC_BROWSER_TEST_F(AppControllerNewProfileManagementBrowserTest,
308 AboutChromeForcesUserManager) {
309 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
311 // Create the guest profile, and set it as the last used profile so the
312 // app controller can use it on init.
313 CreateAndWaitForSystemProfile();
314 PrefService* local_state = g_browser_process->local_state();
315 local_state->SetString(prefs::kProfileLastUsed, chrome::kGuestProfileDir);
317 // Prohibiting guest mode forces the user manager flow for About Chrome.
318 local_state->SetBoolean(prefs::kBrowserGuestModeEnabled, false);
320 Profile* guest_profile = [ac lastProfile];
321 EXPECT_EQ(ProfileManager::GetGuestProfilePath(), guest_profile->GetPath());
322 EXPECT_TRUE(guest_profile->IsGuestSession());
324 // Tell the browser to open About Chrome.
325 EXPECT_EQ(1u, active_browser_list_->size());
326 [ac orderFrontStandardAboutPanel:NSApp];
328 base::RunLoop().RunUntilIdle();
330 // No new browser is opened; the User Manager opens instead.
331 EXPECT_EQ(1u, active_browser_list_->size());
332 EXPECT_TRUE(UserManager::IsShowing());
337 class AppControllerOpenShortcutBrowserTest : public InProcessBrowserTest {
339 AppControllerOpenShortcutBrowserTest() {
342 void SetUpInProcessBrowserTestFixture() override {
343 // In order to mimic opening shortcut during browser startup, we need to
344 // send the event before -applicationDidFinishLaunching is called, but
345 // after AppController is loaded.
347 // Since -applicationWillFinishLaunching does nothing now, we swizzle it to
348 // our function to send the event. We need to do this early before running
349 // the main message loop.
351 // NSApp does not exist yet. We need to get the AppController using
353 Class appControllerClass = NSClassFromString(@"AppController");
354 Class openShortcutClass = NSClassFromString(@"TestOpenShortcutOnStartup");
356 ASSERT_TRUE(appControllerClass != nil);
357 ASSERT_TRUE(openShortcutClass != nil);
359 SEL targetMethod = @selector(applicationWillFinishLaunching:);
360 Method original = class_getInstanceMethod(appControllerClass,
362 Method destination = class_getInstanceMethod(openShortcutClass,
365 ASSERT_TRUE(original != NULL);
366 ASSERT_TRUE(destination != NULL);
368 method_exchangeImplementations(original, destination);
370 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
371 g_open_shortcut_url = embedded_test_server()->GetURL("/simple.html");
374 void SetUpCommandLine(base::CommandLine* command_line) override {
375 // If the arg is empty, PrepareTestCommandLine() after this function will
376 // append about:blank as default url.
377 command_line->AppendArg(chrome::kChromeUINewTabURL);
381 IN_PROC_BROWSER_TEST_F(AppControllerOpenShortcutBrowserTest,
382 OpenShortcutOnStartup) {
383 EXPECT_EQ(1, browser()->tab_strip_model()->count());
384 EXPECT_EQ(g_open_shortcut_url,
385 browser()->tab_strip_model()->GetActiveWebContents()
386 ->GetLastCommittedURL());
389 class AppControllerReplaceNTPBrowserTest : public InProcessBrowserTest {
391 AppControllerReplaceNTPBrowserTest() {}
393 void SetUpInProcessBrowserTestFixture() override {
394 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
397 void SetUpCommandLine(base::CommandLine* command_line) override {
398 // If the arg is empty, PrepareTestCommandLine() after this function will
399 // append about:blank as default url.
400 command_line->AppendArg(chrome::kChromeUINewTabURL);
404 // Tests that when a GURL is opened after startup, it replaces the NTP.
405 IN_PROC_BROWSER_TEST_F(AppControllerReplaceNTPBrowserTest,
406 ReplaceNTPAfterStartup) {
407 // Ensure that there is exactly 1 tab showing, and the tab is the NTP.
408 GURL ntp(chrome::kChromeUINewTabURL);
409 EXPECT_EQ(1, browser()->tab_strip_model()->count());
413 ->GetActiveWebContents()
414 ->GetLastCommittedURL());
416 GURL simple(embedded_test_server()->GetURL("/simple.html"));
417 SendAppleEventToOpenUrlToAppController(simple);
419 // Wait for one navigation on the active web contents.
420 EXPECT_EQ(1, browser()->tab_strip_model()->count());
421 content::TestNavigationObserver obs(
422 browser()->tab_strip_model()->GetActiveWebContents(), 1);
428 ->GetActiveWebContents()
429 ->GetLastCommittedURL());
432 class AppControllerMainMenuBrowserTest : public InProcessBrowserTest {
434 AppControllerMainMenuBrowserTest() {
438 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
439 HistoryMenuResetAfterProfileDeletion) {
440 ProfileManager* profile_manager = g_browser_process->profile_manager();
441 AppController* ac = [NSApp delegate];
443 // Use the existing profile as profile 1.
444 Profile* profile1 = browser()->profile();
447 base::FilePath profile2_path =
448 profile_manager->GenerateNextProfileDirectoryPath();
449 base::RunLoop run_loop;
450 profile_manager->CreateProfileAsync(
452 base::Bind(&RunClosureWhenProfileInitialized,
453 run_loop.QuitClosure()),
458 Profile* profile2 = profile_manager->GetProfileByPath(profile2_path);
459 ASSERT_TRUE(profile2);
461 // Switch the controller to profile1.
462 [ac windowChangedToProfile:profile1];
463 base::RunLoop().RunUntilIdle();
465 // Verify the controller's History Menu corresponds to profile1.
466 EXPECT_TRUE([ac historyMenuBridge]->service());
467 EXPECT_EQ([ac historyMenuBridge]->service(),
468 HistoryServiceFactory::GetForProfile(profile1,
469 ServiceAccessType::EXPLICIT_ACCESS));
471 // Load profile2's History Service backend so it will be assigned to the
472 // HistoryMenuBridge when windowChangedToProfile is called, or else this test
474 ui_test_utils::WaitForHistoryToLoad(
475 HistoryServiceFactory::GetForProfile(profile2,
476 ServiceAccessType::EXPLICIT_ACCESS));
477 // Switch the controller to profile2.
478 [ac windowChangedToProfile:profile2];
479 base::RunLoop().RunUntilIdle();
481 // Verify the controller's History Menu has changed.
482 EXPECT_TRUE([ac historyMenuBridge]->service());
483 EXPECT_EQ([ac historyMenuBridge]->service(),
484 HistoryServiceFactory::GetForProfile(profile2,
485 ServiceAccessType::EXPLICIT_ACCESS));
487 HistoryServiceFactory::GetForProfile(profile1,
488 ServiceAccessType::EXPLICIT_ACCESS),
489 HistoryServiceFactory::GetForProfile(profile2,
490 ServiceAccessType::EXPLICIT_ACCESS));
493 profile_manager->ScheduleProfileForDeletion(
494 profile2->GetPath(), ProfileManager::CreateCallback());
495 base::RunLoop().RunUntilIdle();
497 // Verify the controller's history is back to profile1.
498 EXPECT_EQ([ac historyMenuBridge]->service(),
499 HistoryServiceFactory::GetForProfile(profile1,
500 ServiceAccessType::EXPLICIT_ACCESS));
503 IN_PROC_BROWSER_TEST_F(AppControllerMainMenuBrowserTest,
504 BookmarksMenuIsRestoredAfterProfileSwitch) {
505 ProfileManager* profile_manager = g_browser_process->profile_manager();
506 base::scoped_nsobject<AppController> ac([[AppController alloc] init]);
509 // Constants for bookmarks that we will create later.
510 const base::string16 title1(base::ASCIIToUTF16("Dinosaur Comics"));
511 const GURL url1("http://qwantz.com//");
513 const base::string16 title2(base::ASCIIToUTF16("XKCD"));
514 const GURL url2("https://www.xkcd.com/");
516 // Use the existing profile as profile 1.
517 Profile* profile1 = browser()->profile();
518 bookmarks::test::WaitForBookmarkModelToLoad(
519 BookmarkModelFactory::GetForProfile(profile1));
522 base::FilePath path2 = profile_manager->GenerateNextProfileDirectoryPath();
524 Profile::CreateProfile(path2, NULL, Profile::CREATE_MODE_SYNCHRONOUS);
525 profile_manager->RegisterTestingProfile(profile2, false, true);
526 bookmarks::test::WaitForBookmarkModelToLoad(
527 BookmarkModelFactory::GetForProfile(profile2));
529 // Switch to profile 1, create bookmark 1 and force the menu to build.
530 [ac windowChangedToProfile:profile1];
531 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
532 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
534 [ac bookmarkMenuBridge]->BuildMenu();
536 // Switch to profile 2, create bookmark 2 and force the menu to build.
537 [ac windowChangedToProfile:profile2];
538 [ac bookmarkMenuBridge]->GetBookmarkModel()->AddURL(
539 [ac bookmarkMenuBridge]->GetBookmarkModel()->bookmark_bar_node(),
541 [ac bookmarkMenuBridge]->BuildMenu();
543 // Test that only bookmark 2 is shown.
544 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
545 SysUTF16ToNSString(title1)]);
546 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
547 SysUTF16ToNSString(title2)]);
549 // Switch *back* to profile 1 and *don't* force the menu to build.
550 [ac windowChangedToProfile:profile1];
552 // Test that only bookmark 1 is shown in the restored menu.
553 EXPECT_TRUE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
554 SysUTF16ToNSString(title1)]);
555 EXPECT_FALSE([[ac bookmarkMenuBridge]->BookmarkMenu() itemWithTitle:
556 SysUTF16ToNSString(title2)]);
561 //--------------------------AppControllerHandoffBrowserTest---------------------
563 static GURL g_handoff_url;
565 @interface AppController (BrowserTest)
566 - (BOOL)new_shouldUseHandoff;
567 - (void)new_passURLToHandoffManager:(const GURL&)handoffURL;
570 @implementation AppController (BrowserTest)
571 - (BOOL)new_shouldUseHandoff {
575 - (void)new_passURLToHandoffManager:(const GURL&)handoffURL {
576 g_handoff_url = handoffURL;
582 class AppControllerHandoffBrowserTest : public InProcessBrowserTest {
584 AppControllerHandoffBrowserTest() {}
586 // Exchanges the implementations of the two selectors on the class
588 void ExchangeSelectors(SEL originalMethod, SEL newMethod) {
589 Class appControllerClass = NSClassFromString(@"AppController");
591 ASSERT_TRUE(appControllerClass != nil);
594 class_getInstanceMethod(appControllerClass, originalMethod);
595 Method destination = class_getInstanceMethod(appControllerClass, newMethod);
597 ASSERT_TRUE(original != NULL);
598 ASSERT_TRUE(destination != NULL);
600 method_exchangeImplementations(original, destination);
603 // Swizzle Handoff related implementations.
604 void SetUpInProcessBrowserTestFixture() override {
605 // Handoff is only available on OSX 10.10+. This swizzle makes the logic
606 // run on all OSX versions.
607 SEL originalMethod = @selector(shouldUseHandoff);
608 SEL newMethod = @selector(new_shouldUseHandoff);
609 ExchangeSelectors(originalMethod, newMethod);
611 // This swizzle intercepts the URL that would be sent to the Handoff
612 // Manager, and instead puts it into a variable accessible to this test.
613 originalMethod = @selector(passURLToHandoffManager:);
614 newMethod = @selector(new_passURLToHandoffManager:);
615 ExchangeSelectors(originalMethod, newMethod);
618 // Closes the tab, and waits for the close to finish.
619 void CloseTab(Browser* browser, int index) {
620 content::WebContentsDestroyedWatcher destroyed_watcher(
621 browser->tab_strip_model()->GetWebContentsAt(index));
622 browser->tab_strip_model()->CloseWebContentsAt(
623 index, TabStripModel::CLOSE_CREATE_HISTORICAL_TAB);
624 destroyed_watcher.Wait();
628 // Tests that as a user switches between tabs, navigates within a tab, and
629 // switches between browser windows, the correct URL is being passed to the
631 IN_PROC_BROWSER_TEST_F(AppControllerHandoffBrowserTest, TestHandoffURLs) {
632 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
633 EXPECT_EQ(g_handoff_url, GURL(url::kAboutBlankURL));
635 // Test that navigating to a URL updates the handoff URL.
636 GURL test_url1 = embedded_test_server()->GetURL("/title1.html");
637 ui_test_utils::NavigateToURL(browser(), test_url1);
638 EXPECT_EQ(g_handoff_url, test_url1);
640 // Test that opening a new tab updates the handoff URL.
641 GURL test_url2 = embedded_test_server()->GetURL("/title2.html");
642 chrome::NavigateParams params(browser(), test_url2, ui::PAGE_TRANSITION_LINK);
643 params.disposition = NEW_FOREGROUND_TAB;
644 ui_test_utils::NavigateToURL(¶ms);
645 EXPECT_EQ(g_handoff_url, test_url2);
647 // Test that switching tabs updates the handoff URL.
648 browser()->tab_strip_model()->ActivateTabAt(0, true);
649 EXPECT_EQ(g_handoff_url, test_url1);
651 // Test that closing the current tab updates the handoff URL.
652 CloseTab(browser(), 0);
653 EXPECT_EQ(g_handoff_url, test_url2);
655 // Test that opening a new browser window updates the handoff URL.
656 GURL test_url3 = embedded_test_server()->GetURL("/title3.html");
657 ui_test_utils::NavigateToURLWithDisposition(
658 browser(), GURL(test_url3), NEW_WINDOW,
659 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
660 EXPECT_EQ(g_handoff_url, test_url3);
662 // Check that there are exactly 2 browsers.
663 BrowserList* active_browser_list =
664 BrowserList::GetInstance(chrome::GetActiveDesktop());
665 EXPECT_EQ(2u, active_browser_list->size());
667 // Close the second browser window (which only has 1 tab left).
668 Browser* browser2 = active_browser_list->get(1);
669 CloseBrowserSynchronously(browser2);
670 EXPECT_EQ(g_handoff_url, test_url2);
672 // The URLs of incognito windows should not be passed to Handoff.
673 GURL test_url4 = embedded_test_server()->GetURL("/simple.html");
674 ui_test_utils::NavigateToURLWithDisposition(
675 browser(), GURL(test_url4), OFF_THE_RECORD,
676 ui_test_utils::BROWSER_TEST_WAIT_FOR_BROWSER);
677 EXPECT_EQ(g_handoff_url, GURL());
679 // Open a new tab in the incognito window.
680 EXPECT_EQ(2u, active_browser_list->size());
681 Browser* browser3 = active_browser_list->get(1);
682 ui_test_utils::NavigateToURLWithDisposition(
683 browser3, test_url4, NEW_FOREGROUND_TAB,
684 ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB);
685 EXPECT_EQ(g_handoff_url, GURL());
687 // Navigate the current tab in the incognito window.
688 ui_test_utils::NavigateToURL(browser3, test_url1);
689 EXPECT_EQ(g_handoff_url, GURL());
691 // Activate the original browser window.
692 Browser* browser1 = active_browser_list->get(0);
693 browser1->window()->Show();
694 EXPECT_EQ(g_handoff_url, test_url2);