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 #include "base/logging.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "content/browser/frame_host/interstitial_page_impl.h"
8 #include "content/browser/frame_host/navigation_entry_impl.h"
9 #include "content/browser/renderer_host/render_view_host_impl.h"
10 #include "content/browser/renderer_host/test_render_view_host.h"
11 #include "content/browser/site_instance_impl.h"
12 #include "content/browser/webui/web_ui_controller_factory_registry.h"
13 #include "content/common/view_messages.h"
14 #include "content/public/browser/global_request_id.h"
15 #include "content/public/browser/interstitial_page_delegate.h"
16 #include "content/public/browser/navigation_details.h"
17 #include "content/public/browser/notification_details.h"
18 #include "content/public/browser/notification_source.h"
19 #include "content/public/browser/render_widget_host_view.h"
20 #include "content/public/browser/web_contents_observer.h"
21 #include "content/public/browser/web_ui_controller.h"
22 #include "content/public/common/bindings_policy.h"
23 #include "content/public/common/content_constants.h"
24 #include "content/public/common/url_constants.h"
25 #include "content/public/test/mock_render_process_host.h"
26 #include "content/public/test/test_browser_thread.h"
27 #include "content/public/test/test_utils.h"
28 #include "content/test/test_content_browser_client.h"
29 #include "content/test/test_content_client.h"
30 #include "content/test/test_web_contents.h"
31 #include "testing/gtest/include/gtest/gtest.h"
36 const char kTestWebUIUrl[] = "chrome://blah";
38 class WebContentsImplTestWebUIControllerFactory
39 : public WebUIControllerFactory {
41 virtual WebUIController* CreateWebUIControllerForURL(
42 WebUI* web_ui, const GURL& url) const OVERRIDE {
45 return new WebUIController(web_ui);
48 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
49 const GURL& url) const OVERRIDE {
50 return WebUI::kNoWebUI;
53 virtual bool UseWebUIForURL(BrowserContext* browser_context,
54 const GURL& url) const OVERRIDE {
58 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
59 const GURL& url) const OVERRIDE {
64 bool UseWebUI(const GURL& url) const {
65 return url == GURL(kTestWebUIUrl);
69 class TestInterstitialPage;
71 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
73 explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
74 : interstitial_page_(interstitial_page) {}
75 virtual void CommandReceived(const std::string& command) OVERRIDE;
76 virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
77 virtual void OnDontProceed() OVERRIDE;
78 virtual void OnProceed() OVERRIDE;
80 TestInterstitialPage* interstitial_page_;
83 class TestInterstitialPage : public InterstitialPageImpl {
85 enum InterstitialState {
86 INVALID = 0, // Hasn't yet been initialized.
87 UNDECIDED, // Initialized, but no decision taken yet.
88 OKED, // Proceed was called.
89 CANCELED // DontProceed was called.
94 virtual void TestInterstitialPageDeleted(
95 TestInterstitialPage* interstitial) = 0;
98 virtual ~Delegate() {}
101 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
102 // |deleted| (like all interstitial related tests do at this point), make sure
103 // to create an instance of the TestInterstitialPageStateGuard class on the
104 // stack in your test. This will ensure that the TestInterstitialPage states
105 // are cleared when the test finishes.
106 // Not doing so will cause stack trashing if your test does not hide the
107 // interstitial, as in such a case it will be destroyed in the test TearDown
108 // method and will dereference the |deleted| local variable which by then is
110 TestInterstitialPage(WebContentsImpl* contents,
113 InterstitialState* state,
115 : InterstitialPageImpl(
117 static_cast<RenderWidgetHostDelegate*>(contents),
118 new_navigation, url, new TestInterstitialPageDelegate(this)),
121 command_received_count_(0),
127 virtual ~TestInterstitialPage() {
131 delegate_->TestInterstitialPageDeleted(this);
134 void OnDontProceed() {
143 int command_received_count() const {
144 return command_received_count_;
147 void TestDomOperationResponse(const std::string& json_string) {
152 void TestDidNavigate(int page_id, const GURL& url) {
153 ViewHostMsg_FrameNavigate_Params params;
154 InitNavigateParams(¶ms, page_id, url, PAGE_TRANSITION_TYPED);
155 DidNavigate(GetRenderViewHostForTesting(), params);
158 void TestRenderViewTerminated(base::TerminationStatus status,
160 RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
163 bool is_showing() const {
164 return static_cast<TestRenderWidgetHostView*>(
165 GetRenderViewHostForTesting()->GetView())->is_showing();
174 void CommandReceived() {
175 command_received_count_++;
178 void set_delegate(Delegate* delegate) {
179 delegate_ = delegate;
183 virtual RenderViewHost* CreateRenderViewHost() OVERRIDE {
184 return new TestRenderViewHost(
185 SiteInstance::Create(web_contents()->GetBrowserContext()),
186 this, this, MSG_ROUTING_NONE, MSG_ROUTING_NONE, false);
189 virtual WebContentsView* CreateWebContentsView() OVERRIDE {
194 InterstitialState* state_;
196 int command_received_count_;
200 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
201 interstitial_page_->CommandReceived();
204 void TestInterstitialPageDelegate::OnDontProceed() {
205 interstitial_page_->OnDontProceed();
208 void TestInterstitialPageDelegate::OnProceed() {
209 interstitial_page_->OnProceed();
212 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
214 explicit TestInterstitialPageStateGuard(
215 TestInterstitialPage* interstitial_page)
216 : interstitial_page_(interstitial_page) {
217 DCHECK(interstitial_page_);
218 interstitial_page_->set_delegate(this);
220 virtual ~TestInterstitialPageStateGuard() {
221 if (interstitial_page_)
222 interstitial_page_->ClearStates();
225 virtual void TestInterstitialPageDeleted(
226 TestInterstitialPage* interstitial) OVERRIDE {
227 DCHECK(interstitial_page_ == interstitial);
228 interstitial_page_ = NULL;
232 TestInterstitialPage* interstitial_page_;
235 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
237 WebContentsImplTestBrowserClient()
238 : assign_site_for_url_(false) {}
240 virtual ~WebContentsImplTestBrowserClient() {}
242 virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
243 return assign_site_for_url_;
246 void set_assign_site_for_url(bool assign) {
247 assign_site_for_url_ = assign;
251 bool assign_site_for_url_;
254 class WebContentsImplTest : public RenderViewHostImplTestHarness {
256 virtual void SetUp() {
257 RenderViewHostImplTestHarness::SetUp();
258 WebUIControllerFactory::RegisterFactory(&factory_);
261 virtual void TearDown() {
262 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
263 RenderViewHostImplTestHarness::TearDown();
267 WebContentsImplTestWebUIControllerFactory factory_;
270 class TestWebContentsObserver : public WebContentsObserver {
272 explicit TestWebContentsObserver(WebContents* contents)
273 : WebContentsObserver(contents) {
275 virtual ~TestWebContentsObserver() {}
277 virtual void DidFinishLoad(int64 frame_id,
278 const GURL& validated_url,
280 RenderViewHost* render_view_host) OVERRIDE {
281 last_url_ = validated_url;
283 virtual void DidFailLoad(int64 frame_id,
284 const GURL& validated_url,
287 const string16& error_description,
288 RenderViewHost* render_view_host) OVERRIDE {
289 last_url_ = validated_url;
292 const GURL& last_url() const { return last_url_; }
297 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
302 // Test to make sure that title updates get stripped of whitespace.
303 TEST_F(WebContentsImplTest, UpdateTitle) {
304 NavigationControllerImpl& cont =
305 static_cast<NavigationControllerImpl&>(controller());
306 ViewHostMsg_FrameNavigate_Params params;
307 InitNavigateParams(¶ms, 0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED);
309 LoadCommittedDetails details;
310 cont.RendererDidNavigate(params, &details);
312 contents()->UpdateTitle(rvh(), 0, ASCIIToUTF16(" Lots O' Whitespace\n"),
313 base::i18n::LEFT_TO_RIGHT);
314 EXPECT_EQ(ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
317 // Test view source mode for a webui page.
318 TEST_F(WebContentsImplTest, NTPViewSource) {
319 NavigationControllerImpl& cont =
320 static_cast<NavigationControllerImpl&>(controller());
321 const char kUrl[] = "view-source:chrome://blah";
322 const GURL kGURL(kUrl);
324 process()->sink().ClearMessages();
327 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
328 rvh()->GetDelegate()->RenderViewCreated(rvh());
329 // Did we get the expected message?
330 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
331 ViewMsg_EnableViewSourceMode::ID));
333 ViewHostMsg_FrameNavigate_Params params;
334 InitNavigateParams(¶ms, 0, kGURL, PAGE_TRANSITION_TYPED);
335 LoadCommittedDetails details;
336 cont.RendererDidNavigate(params, &details);
337 // Also check title and url.
338 EXPECT_EQ(ASCIIToUTF16(kUrl), contents()->GetTitle());
341 // Test to ensure UpdateMaxPageID is working properly.
342 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
343 SiteInstance* instance1 = contents()->GetSiteInstance();
344 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
347 EXPECT_EQ(-1, contents()->GetMaxPageID());
348 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
349 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
351 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
352 contents()->UpdateMaxPageID(3);
353 contents()->UpdateMaxPageID(1);
354 EXPECT_EQ(3, contents()->GetMaxPageID());
355 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
356 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
358 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
359 EXPECT_EQ(3, contents()->GetMaxPageID());
360 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
361 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
364 // Test simple same-SiteInstance navigation.
365 TEST_F(WebContentsImplTest, SimpleNavigation) {
366 TestRenderViewHost* orig_rvh = test_rvh();
367 SiteInstance* instance1 = contents()->GetSiteInstance();
368 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
371 const GURL url("http://www.google.com");
372 controller().LoadURL(
373 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
374 EXPECT_FALSE(contents()->cross_navigation_pending());
375 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
376 // Controller's pending entry will have a NULL site instance until we assign
377 // it in DidNavigate.
379 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
380 site_instance() == NULL);
382 // DidNavigate from the page
383 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
384 EXPECT_FALSE(contents()->cross_navigation_pending());
385 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
386 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
387 // Controller's entry should now have the SiteInstance, or else we won't be
388 // able to find it later.
391 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
395 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
396 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
397 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
398 const GURL url(std::string("http://example.org/").append(
399 kMaxURLChars + 1, 'a'));
401 controller().LoadURL(
402 url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
403 EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
406 // Test that navigating across a site boundary creates a new RenderViewHost
407 // with a new SiteInstance. Going back should do the same.
408 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
409 contents()->transition_cross_site = true;
410 TestRenderViewHost* orig_rvh = test_rvh();
411 int orig_rvh_delete_count = 0;
412 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
413 SiteInstance* instance1 = contents()->GetSiteInstance();
415 // Navigate to URL. First URL should use first RenderViewHost.
416 const GURL url("http://www.google.com");
417 controller().LoadURL(
418 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
419 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
421 // Keep the number of active views in orig_rvh's SiteInstance
422 // non-zero so that orig_rvh doesn't get deleted when it gets
424 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
425 increment_active_view_count();
427 EXPECT_FALSE(contents()->cross_navigation_pending());
428 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
429 EXPECT_EQ(url, contents()->GetLastCommittedURL());
430 EXPECT_EQ(url, contents()->GetVisibleURL());
432 // Navigate to new site
433 const GURL url2("http://www.yahoo.com");
434 controller().LoadURL(
435 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
436 EXPECT_TRUE(contents()->cross_navigation_pending());
437 EXPECT_EQ(url, contents()->GetLastCommittedURL());
438 EXPECT_EQ(url2, contents()->GetVisibleURL());
439 TestRenderViewHost* pending_rvh =
440 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
441 int pending_rvh_delete_count = 0;
442 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
444 // Navigations should be suspended in pending_rvh until ShouldCloseACK.
445 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
446 orig_rvh->SendShouldCloseACK(true);
447 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
449 // DidNavigate from the pending page
450 contents()->TestDidNavigate(
451 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
452 SiteInstance* instance2 = contents()->GetSiteInstance();
454 // Keep the number of active views in pending_rvh's SiteInstance
455 // non-zero so that orig_rvh doesn't get deleted when it gets
457 static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
458 increment_active_view_count();
460 EXPECT_FALSE(contents()->cross_navigation_pending());
461 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
462 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
463 EXPECT_EQ(url2, contents()->GetVisibleURL());
464 EXPECT_NE(instance1, instance2);
465 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
466 // We keep the original RVH around, swapped out.
467 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
469 EXPECT_EQ(orig_rvh_delete_count, 0);
471 // Going back should switch SiteInstances again. The first SiteInstance is
472 // stored in the NavigationEntry, so it should be the same as at the start.
473 // We should use the same RVH as before, swapping it back in.
474 controller().GoBack();
475 TestRenderViewHost* goback_rvh =
476 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
477 EXPECT_EQ(orig_rvh, goback_rvh);
478 EXPECT_TRUE(contents()->cross_navigation_pending());
480 // Navigations should be suspended in goback_rvh until ShouldCloseACK.
481 EXPECT_TRUE(goback_rvh->are_navigations_suspended());
482 pending_rvh->SendShouldCloseACK(true);
483 EXPECT_FALSE(goback_rvh->are_navigations_suspended());
485 // DidNavigate from the back action
486 contents()->TestDidNavigate(
487 goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
488 EXPECT_FALSE(contents()->cross_navigation_pending());
489 EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
490 EXPECT_EQ(instance1, contents()->GetSiteInstance());
491 // The pending RVH should now be swapped out, not deleted.
492 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
493 IsOnSwappedOutList(pending_rvh));
494 EXPECT_EQ(pending_rvh_delete_count, 0);
496 // Close contents and ensure RVHs are deleted.
498 EXPECT_EQ(orig_rvh_delete_count, 1);
499 EXPECT_EQ(pending_rvh_delete_count, 1);
502 // Test that navigating across a site boundary after a crash creates a new
503 // RVH without requiring a cross-site transition (i.e., PENDING state).
504 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
505 contents()->transition_cross_site = true;
506 TestRenderViewHost* orig_rvh = test_rvh();
507 int orig_rvh_delete_count = 0;
508 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
509 SiteInstance* instance1 = contents()->GetSiteInstance();
511 // Navigate to URL. First URL should use first RenderViewHost.
512 const GURL url("http://www.google.com");
513 controller().LoadURL(
514 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
515 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
517 EXPECT_FALSE(contents()->cross_navigation_pending());
518 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
520 // Crash the renderer.
521 orig_rvh->set_render_view_created(false);
523 // Navigate to new site. We should not go into PENDING.
524 const GURL url2("http://www.yahoo.com");
525 controller().LoadURL(
526 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
527 RenderViewHost* new_rvh = rvh();
528 EXPECT_FALSE(contents()->cross_navigation_pending());
529 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
530 EXPECT_NE(orig_rvh, new_rvh);
531 EXPECT_EQ(orig_rvh_delete_count, 1);
533 // DidNavigate from the new page
534 contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
535 SiteInstance* instance2 = contents()->GetSiteInstance();
537 EXPECT_FALSE(contents()->cross_navigation_pending());
538 EXPECT_EQ(new_rvh, rvh());
539 EXPECT_NE(instance1, instance2);
540 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
542 // Close contents and ensure RVHs are deleted.
544 EXPECT_EQ(orig_rvh_delete_count, 1);
547 // Test that opening a new contents in the same SiteInstance and then navigating
548 // both contentses to a new site will place both contentses in a single
550 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
551 contents()->transition_cross_site = true;
552 TestRenderViewHost* orig_rvh = test_rvh();
553 SiteInstance* instance1 = contents()->GetSiteInstance();
555 // Navigate to URL. First URL should use first RenderViewHost.
556 const GURL url("http://www.google.com");
557 controller().LoadURL(
558 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
559 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
561 // Open a new contents with the same SiteInstance, navigated to the same site.
562 scoped_ptr<TestWebContents> contents2(
563 TestWebContents::Create(browser_context(), instance1));
564 contents2->transition_cross_site = true;
565 contents2->GetController().LoadURL(url, Referrer(),
566 PAGE_TRANSITION_TYPED,
568 // Need this page id to be 2 since the site instance is the same (which is the
569 // scope of page IDs) and we want to consider this a new page.
570 contents2->TestDidNavigate(
571 contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
573 // Navigate first contents to a new site.
574 const GURL url2a("http://www.yahoo.com");
575 controller().LoadURL(
576 url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
577 orig_rvh->SendShouldCloseACK(true);
578 TestRenderViewHost* pending_rvh_a =
579 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
580 contents()->TestDidNavigate(
581 pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
582 SiteInstance* instance2a = contents()->GetSiteInstance();
583 EXPECT_NE(instance1, instance2a);
585 // Navigate second contents to the same site as the first tab.
586 const GURL url2b("http://mail.yahoo.com");
587 contents2->GetController().LoadURL(url2b, Referrer(),
588 PAGE_TRANSITION_TYPED,
590 TestRenderViewHost* rvh2 =
591 static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
592 rvh2->SendShouldCloseACK(true);
593 TestRenderViewHost* pending_rvh_b =
594 static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
595 EXPECT_TRUE(pending_rvh_b != NULL);
596 EXPECT_TRUE(contents2->cross_navigation_pending());
598 // NOTE(creis): We used to be in danger of showing a crash page here if the
599 // second contents hadn't navigated somewhere first (bug 1145430). That case
600 // is now covered by the CrossSiteBoundariesAfterCrash test.
601 contents2->TestDidNavigate(
602 pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
603 SiteInstance* instance2b = contents2->GetSiteInstance();
604 EXPECT_NE(instance1, instance2b);
606 // Both contentses should now be in the same SiteInstance.
607 EXPECT_EQ(instance2a, instance2b);
610 TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
611 WebContentsImplTestBrowserClient browser_client;
612 SetBrowserClientForTesting(&browser_client);
614 contents()->transition_cross_site = true;
615 TestRenderViewHost* orig_rvh = test_rvh();
616 int orig_rvh_delete_count = 0;
617 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
618 SiteInstanceImpl* orig_instance =
619 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
621 browser_client.set_assign_site_for_url(false);
622 // Navigate to an URL that will not assign a new SiteInstance.
623 const GURL native_url("non-site-url://stuffandthings");
624 controller().LoadURL(
625 native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
626 contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
628 EXPECT_FALSE(contents()->cross_navigation_pending());
629 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
630 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
631 EXPECT_EQ(native_url, contents()->GetVisibleURL());
632 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
633 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
634 EXPECT_FALSE(orig_instance->HasSite());
636 browser_client.set_assign_site_for_url(true);
637 // Navigate to new site (should keep same site instance).
638 const GURL url("http://www.google.com");
639 controller().LoadURL(
640 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
641 EXPECT_FALSE(contents()->cross_navigation_pending());
642 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
643 EXPECT_EQ(url, contents()->GetVisibleURL());
644 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
645 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
647 // Keep the number of active views in orig_rvh's SiteInstance
648 // non-zero so that orig_rvh doesn't get deleted when it gets
650 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
651 increment_active_view_count();
653 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
655 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
656 EXPECT_EQ(url, contents()->GetLastCommittedURL());
658 // Navigate to another new site (should create a new site instance).
659 const GURL url2("http://www.yahoo.com");
660 controller().LoadURL(
661 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
662 EXPECT_TRUE(contents()->cross_navigation_pending());
663 EXPECT_EQ(url, contents()->GetLastCommittedURL());
664 EXPECT_EQ(url2, contents()->GetVisibleURL());
665 TestRenderViewHost* pending_rvh =
666 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
667 int pending_rvh_delete_count = 0;
668 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
670 // Navigations should be suspended in pending_rvh until ShouldCloseACK.
671 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
672 orig_rvh->SendShouldCloseACK(true);
673 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
675 // DidNavigate from the pending page.
676 contents()->TestDidNavigate(
677 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
678 SiteInstance* new_instance = contents()->GetSiteInstance();
680 EXPECT_FALSE(contents()->cross_navigation_pending());
681 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
682 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
683 EXPECT_EQ(url2, contents()->GetVisibleURL());
684 EXPECT_NE(new_instance, orig_instance);
685 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
686 // We keep the original RVH around, swapped out.
687 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
689 EXPECT_EQ(orig_rvh_delete_count, 0);
691 // Close contents and ensure RVHs are deleted.
693 EXPECT_EQ(orig_rvh_delete_count, 1);
694 EXPECT_EQ(pending_rvh_delete_count, 1);
697 // Test that we can find an opener RVH even if it's pending.
698 // http://crbug.com/176252.
699 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
700 contents()->transition_cross_site = true;
701 TestRenderViewHost* orig_rvh = test_rvh();
703 // Navigate to a URL.
704 const GURL url("http://www.google.com");
705 controller().LoadURL(
706 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
707 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
709 // Start to navigate first tab to a new site, so that it has a pending RVH.
710 const GURL url2("http://www.yahoo.com");
711 controller().LoadURL(
712 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
713 orig_rvh->SendShouldCloseACK(true);
714 TestRenderViewHost* pending_rvh =
715 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
717 // While it is still pending, simulate opening a new tab with the first tab
718 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
719 // on the opener to ensure that an RVH exists.
720 int opener_routing_id = contents()->CreateOpenerRenderViews(
721 pending_rvh->GetSiteInstance());
723 // We should find the pending RVH and not create a new one.
724 EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
727 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
728 // to determine whether a navigation is cross-site.
729 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
730 contents()->transition_cross_site = true;
731 RenderViewHost* orig_rvh = rvh();
732 SiteInstance* instance1 = contents()->GetSiteInstance();
735 const GURL url("http://www.google.com");
736 controller().LoadURL(
737 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
738 contents()->TestDidNavigate(
739 orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
741 // Open a related contents to a second site.
742 scoped_ptr<TestWebContents> contents2(
743 TestWebContents::Create(browser_context(), instance1));
744 contents2->transition_cross_site = true;
745 const GURL url2("http://www.yahoo.com");
746 contents2->GetController().LoadURL(url2, Referrer(),
747 PAGE_TRANSITION_TYPED,
749 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
751 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
752 contents2->GetRenderViewHost());
753 EXPECT_FALSE(contents2->cross_navigation_pending());
754 contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
755 SiteInstance* instance2 = contents2->GetSiteInstance();
756 EXPECT_NE(instance1, instance2);
757 EXPECT_FALSE(contents2->cross_navigation_pending());
759 // Simulate a link click in first contents to second site. Doesn't switch
760 // SiteInstances, because we don't intercept WebKit navigations.
761 contents()->TestDidNavigate(
762 orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
763 SiteInstance* instance3 = contents()->GetSiteInstance();
764 EXPECT_EQ(instance1, instance3);
765 EXPECT_FALSE(contents()->cross_navigation_pending());
767 // Navigate to the new site. Doesn't switch SiteInstancees, because we
768 // compare against the current URL, not the SiteInstance's site.
769 const GURL url3("http://mail.yahoo.com");
770 controller().LoadURL(
771 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
772 EXPECT_FALSE(contents()->cross_navigation_pending());
773 contents()->TestDidNavigate(
774 orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
775 SiteInstance* instance4 = contents()->GetSiteInstance();
776 EXPECT_EQ(instance1, instance4);
779 // Test that the onbeforeunload and onunload handlers run when navigating
780 // across site boundaries.
781 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
782 contents()->transition_cross_site = true;
783 TestRenderViewHost* orig_rvh = test_rvh();
784 SiteInstance* instance1 = contents()->GetSiteInstance();
786 // Navigate to URL. First URL should use first RenderViewHost.
787 const GURL url("http://www.google.com");
788 controller().LoadURL(
789 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
790 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
791 EXPECT_FALSE(contents()->cross_navigation_pending());
792 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
794 // Navigate to new site, but simulate an onbeforeunload denial.
795 const GURL url2("http://www.yahoo.com");
796 controller().LoadURL(
797 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
798 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
799 base::TimeTicks now = base::TimeTicks::Now();
800 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, false, now, now));
801 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
802 EXPECT_FALSE(contents()->cross_navigation_pending());
803 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
805 // Navigate again, but simulate an onbeforeunload approval.
806 controller().LoadURL(
807 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
808 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
809 now = base::TimeTicks::Now();
810 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
811 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
812 EXPECT_TRUE(contents()->cross_navigation_pending());
813 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
814 contents()->GetPendingRenderViewHost());
816 // We won't hear DidNavigate until the onunload handler has finished running.
818 // DidNavigate from the pending page.
819 contents()->TestDidNavigate(
820 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
821 SiteInstance* instance2 = contents()->GetSiteInstance();
822 EXPECT_FALSE(contents()->cross_navigation_pending());
823 EXPECT_EQ(pending_rvh, rvh());
824 EXPECT_NE(instance1, instance2);
825 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
828 // Test that during a slow cross-site navigation, the original renderer can
829 // navigate to a different URL and have it displayed, canceling the slow
831 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
832 contents()->transition_cross_site = true;
833 TestRenderViewHost* orig_rvh = test_rvh();
834 SiteInstance* instance1 = contents()->GetSiteInstance();
836 // Navigate to URL. First URL should use first RenderViewHost.
837 const GURL url("http://www.google.com");
838 controller().LoadURL(
839 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
840 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
841 EXPECT_FALSE(contents()->cross_navigation_pending());
842 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
844 // Navigate to new site, simulating an onbeforeunload approval.
845 const GURL url2("http://www.yahoo.com");
846 controller().LoadURL(
847 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
848 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
849 base::TimeTicks now = base::TimeTicks::Now();
850 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
851 EXPECT_TRUE(contents()->cross_navigation_pending());
853 // Suppose the original renderer navigates before the new one is ready.
854 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
856 // Verify that the pending navigation is cancelled.
857 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
858 SiteInstance* instance2 = contents()->GetSiteInstance();
859 EXPECT_FALSE(contents()->cross_navigation_pending());
860 EXPECT_EQ(orig_rvh, rvh());
861 EXPECT_EQ(instance1, instance2);
862 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
865 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
866 contents()->transition_cross_site = true;
868 // Start with a web ui page, which gets a new RVH with WebUI bindings.
869 const GURL url1("chrome://blah");
870 controller().LoadURL(
871 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
872 TestRenderViewHost* ntp_rvh = test_rvh();
873 contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
874 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
875 SiteInstance* instance1 = contents()->GetSiteInstance();
877 EXPECT_FALSE(contents()->cross_navigation_pending());
878 EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
879 EXPECT_EQ(url1, entry1->GetURL());
881 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
882 EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
884 // Navigate to new site.
885 const GURL url2("http://www.google.com");
886 controller().LoadURL(
887 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
888 EXPECT_TRUE(contents()->cross_navigation_pending());
889 TestRenderViewHost* google_rvh =
890 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
892 // Simulate beforeunload approval.
893 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
894 base::TimeTicks now = base::TimeTicks::Now();
895 ntp_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
897 // DidNavigate from the pending page.
898 contents()->TestDidNavigate(
899 google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
900 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
901 SiteInstance* instance2 = contents()->GetSiteInstance();
903 EXPECT_FALSE(contents()->cross_navigation_pending());
904 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
905 EXPECT_NE(instance1, instance2);
906 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
907 EXPECT_EQ(url2, entry2->GetURL());
909 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
910 EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
912 // Navigate to third page on same site.
913 const GURL url3("http://news.google.com");
914 controller().LoadURL(
915 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
916 EXPECT_FALSE(contents()->cross_navigation_pending());
917 contents()->TestDidNavigate(
918 google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
919 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
920 SiteInstance* instance3 = contents()->GetSiteInstance();
922 EXPECT_FALSE(contents()->cross_navigation_pending());
923 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
924 EXPECT_EQ(instance2, instance3);
925 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
926 EXPECT_EQ(url3, entry3->GetURL());
928 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
930 // Go back within the site.
931 controller().GoBack();
932 EXPECT_FALSE(contents()->cross_navigation_pending());
933 EXPECT_EQ(entry2, controller().GetPendingEntry());
935 // Before that commits, go back again.
936 controller().GoBack();
937 EXPECT_TRUE(contents()->cross_navigation_pending());
938 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
939 EXPECT_EQ(entry1, controller().GetPendingEntry());
941 // Simulate beforeunload approval.
942 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
943 now = base::TimeTicks::Now();
944 google_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
946 // DidNavigate from the first back. This aborts the second back's pending RVH.
947 contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
949 // We should commit this page and forget about the second back.
950 EXPECT_FALSE(contents()->cross_navigation_pending());
951 EXPECT_FALSE(controller().GetPendingEntry());
952 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
953 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
955 // We should not have corrupted the NTP entry.
957 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
959 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
961 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
962 EXPECT_EQ(url1, entry1->GetURL());
965 // Test that during a slow cross-site navigation, a sub-frame navigation in the
966 // original renderer will not cancel the slow navigation (bug 42029).
967 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
968 contents()->transition_cross_site = true;
969 TestRenderViewHost* orig_rvh = test_rvh();
971 // Navigate to URL. First URL should use first RenderViewHost.
972 const GURL url("http://www.google.com");
973 controller().LoadURL(
974 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
975 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
976 EXPECT_FALSE(contents()->cross_navigation_pending());
977 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
979 // Start navigating to new site.
980 const GURL url2("http://www.yahoo.com");
981 controller().LoadURL(
982 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
984 // Simulate a sub-frame navigation arriving and ensure the RVH is still
985 // waiting for a before unload response.
986 orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
987 PAGE_TRANSITION_AUTO_SUBFRAME);
988 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
990 // Now simulate the onbeforeunload approval and verify the navigation is
992 base::TimeTicks now = base::TimeTicks::Now();
993 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
994 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
995 EXPECT_TRUE(contents()->cross_navigation_pending());
998 // Test that a cross-site navigation is not preempted if the previous
999 // renderer sends a FrameNavigate message just before being told to stop.
1000 // We should only preempt the cross-site navigation if the previous renderer
1001 // has started a new navigation. See http://crbug.com/79176.
1002 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1003 contents()->transition_cross_site = true;
1005 // Navigate to NTP URL.
1006 const GURL url("chrome://blah");
1007 controller().LoadURL(
1008 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1009 TestRenderViewHost* orig_rvh = test_rvh();
1010 EXPECT_FALSE(contents()->cross_navigation_pending());
1012 // Navigate to new site, with the beforeunload request in flight.
1013 const GURL url2("http://www.yahoo.com");
1014 controller().LoadURL(
1015 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1016 TestRenderViewHost* pending_rvh =
1017 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1018 EXPECT_TRUE(contents()->cross_navigation_pending());
1019 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1021 // Suppose the first navigation tries to commit now, with a
1022 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1023 // but it should act as if the beforeunload ack arrived.
1024 orig_rvh->SendNavigate(1, GURL("chrome://blah"));
1025 EXPECT_TRUE(contents()->cross_navigation_pending());
1026 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1027 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1029 // The pending navigation should be able to commit successfully.
1030 contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1031 EXPECT_FALSE(contents()->cross_navigation_pending());
1032 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
1035 // Test that the original renderer cannot preempt a cross-site navigation once
1036 // the unload request has been made. At this point, the cross-site navigation
1037 // is almost ready to be displayed, and the original renderer is only given a
1038 // short chance to run an unload handler. Prevents regression of bug 23942.
1039 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
1040 contents()->transition_cross_site = true;
1041 TestRenderViewHost* orig_rvh = test_rvh();
1042 SiteInstance* instance1 = contents()->GetSiteInstance();
1044 // Navigate to URL. First URL should use first RenderViewHost.
1045 const GURL url("http://www.google.com");
1046 controller().LoadURL(
1047 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1048 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1049 EXPECT_FALSE(contents()->cross_navigation_pending());
1050 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1052 // Navigate to new site, simulating an onbeforeunload approval.
1053 const GURL url2("http://www.yahoo.com");
1054 controller().LoadURL(
1055 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1056 base::TimeTicks now = base::TimeTicks::Now();
1057 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1058 EXPECT_TRUE(contents()->cross_navigation_pending());
1059 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
1060 contents()->GetPendingRenderViewHost());
1062 // Simulate the pending renderer's response, which leads to an unload request
1063 // being sent to orig_rvh.
1064 std::vector<GURL> url_chain;
1065 url_chain.push_back(GURL());
1066 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1067 pending_rvh, GlobalRequestID(0, 0), false, url_chain, Referrer(),
1068 PAGE_TRANSITION_TYPED, 1);
1070 // Suppose the original renderer navigates now, while the unload request is in
1071 // flight. We should ignore it, wait for the unload ack, and let the pending
1072 // request continue. Otherwise, the contents may close spontaneously or stop
1073 // responding to navigation requests. (See bug 23942.)
1074 ViewHostMsg_FrameNavigate_Params params1a;
1075 InitNavigateParams(¶ms1a, 2, GURL("http://www.google.com/foo"),
1076 PAGE_TRANSITION_TYPED);
1077 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1079 // Verify that the pending navigation is still in progress.
1080 EXPECT_TRUE(contents()->cross_navigation_pending());
1081 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
1083 // DidNavigate from the pending page should commit it.
1084 contents()->TestDidNavigate(
1085 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1086 SiteInstance* instance2 = contents()->GetSiteInstance();
1087 EXPECT_FALSE(contents()->cross_navigation_pending());
1088 EXPECT_EQ(pending_rvh, rvh());
1089 EXPECT_NE(instance1, instance2);
1090 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1093 // Test that a cross-site navigation that doesn't commit after the unload
1094 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1095 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1096 contents()->transition_cross_site = true;
1097 TestRenderViewHost* orig_rvh = test_rvh();
1098 SiteInstance* instance1 = contents()->GetSiteInstance();
1100 // Navigate to URL. First URL should use first RenderViewHost.
1101 const GURL url("http://www.google.com");
1102 controller().LoadURL(
1103 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1104 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1105 EXPECT_FALSE(contents()->cross_navigation_pending());
1106 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1108 // Navigate to new site, simulating an onbeforeunload approval.
1109 const GURL url2("http://www.yahoo.com");
1110 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1111 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1112 base::TimeTicks now = base::TimeTicks::Now();
1113 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1114 EXPECT_TRUE(contents()->cross_navigation_pending());
1116 // Simulate swap out message when the response arrives.
1117 orig_rvh->set_is_swapped_out(true);
1119 // Suppose the navigation doesn't get a chance to commit, and the user
1120 // navigates in the current RVH's SiteInstance.
1121 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1123 // Verify that the pending navigation is cancelled and the renderer is no
1124 // longer swapped out.
1125 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1126 SiteInstance* instance2 = contents()->GetSiteInstance();
1127 EXPECT_FALSE(contents()->cross_navigation_pending());
1128 EXPECT_EQ(orig_rvh, rvh());
1129 EXPECT_FALSE(orig_rvh->is_swapped_out());
1130 EXPECT_EQ(instance1, instance2);
1131 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1134 // Test that NavigationEntries have the correct page state after going
1135 // forward and back. Prevents regression for bug 1116137.
1136 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1137 TestRenderViewHost* orig_rvh = test_rvh();
1139 // Navigate to URL. There should be no committed entry yet.
1140 const GURL url("http://www.google.com");
1141 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1142 NavigationEntry* entry = controller().GetLastCommittedEntry();
1143 EXPECT_TRUE(entry == NULL);
1145 // Committed entry should have page state after DidNavigate.
1146 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1147 entry = controller().GetLastCommittedEntry();
1148 EXPECT_TRUE(entry->GetPageState().IsValid());
1150 // Navigate to same site.
1151 const GURL url2("http://images.google.com");
1152 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1153 entry = controller().GetLastCommittedEntry();
1154 EXPECT_TRUE(entry->GetPageState().IsValid());
1156 // Committed entry should have page state after DidNavigate.
1157 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1158 entry = controller().GetLastCommittedEntry();
1159 EXPECT_TRUE(entry->GetPageState().IsValid());
1161 // Now go back. Committed entry should still have page state.
1162 controller().GoBack();
1163 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1164 entry = controller().GetLastCommittedEntry();
1165 EXPECT_TRUE(entry->GetPageState().IsValid());
1168 // Test that NavigationEntries have the correct page state and SiteInstance
1169 // state after opening a new window to about:blank. Prevents regression for
1170 // bugs b/1116137 and http://crbug.com/111975.
1171 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1172 TestRenderViewHost* orig_rvh = test_rvh();
1174 // When opening a new window, it is navigated to about:blank internally.
1175 // Currently, this results in two DidNavigate events.
1176 const GURL url(kAboutBlankURL);
1177 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1178 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1180 // Should have a page state here.
1181 NavigationEntry* entry = controller().GetLastCommittedEntry();
1182 EXPECT_TRUE(entry->GetPageState().IsValid());
1184 // The SiteInstance should be available for other navigations to use.
1185 NavigationEntryImpl* entry_impl =
1186 NavigationEntryImpl::FromNavigationEntry(entry);
1187 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1188 int32 site_instance_id = entry_impl->site_instance()->GetId();
1190 // Navigating to a normal page should not cause a process swap.
1191 const GURL new_url("http://www.google.com");
1192 controller().LoadURL(new_url, Referrer(),
1193 PAGE_TRANSITION_TYPED, std::string());
1194 EXPECT_FALSE(contents()->cross_navigation_pending());
1195 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1196 contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1197 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1198 controller().GetLastCommittedEntry());
1199 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1200 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1203 ////////////////////////////////////////////////////////////////////////////////
1204 // Interstitial Tests
1205 ////////////////////////////////////////////////////////////////////////////////
1207 // Test navigating to a page (with the navigation initiated from the browser,
1208 // as when a URL is typed in the location bar) that shows an interstitial and
1209 // creates a new navigation entry, then hiding it without proceeding.
1210 TEST_F(WebContentsImplTest,
1211 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1212 // Navigate to a page.
1213 GURL url1("http://www.google.com");
1214 test_rvh()->SendNavigate(1, url1);
1215 EXPECT_EQ(1, controller().GetEntryCount());
1217 // Initiate a browser navigation that will trigger the interstitial
1218 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1219 PAGE_TRANSITION_TYPED, std::string());
1221 // Show an interstitial.
1222 TestInterstitialPage::InterstitialState state =
1223 TestInterstitialPage::INVALID;
1224 bool deleted = false;
1225 GURL url2("http://interstitial");
1226 TestInterstitialPage* interstitial =
1227 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1228 TestInterstitialPageStateGuard state_guard(interstitial);
1229 interstitial->Show();
1230 // The interstitial should not show until its navigation has committed.
1231 EXPECT_FALSE(interstitial->is_showing());
1232 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1233 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1234 // Let's commit the interstitial navigation.
1235 interstitial->TestDidNavigate(1, url2);
1236 EXPECT_TRUE(interstitial->is_showing());
1237 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1238 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1239 NavigationEntry* entry = controller().GetVisibleEntry();
1240 ASSERT_TRUE(entry != NULL);
1241 EXPECT_TRUE(entry->GetURL() == url2);
1243 // Now don't proceed.
1244 interstitial->DontProceed();
1245 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1246 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1247 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1248 entry = controller().GetVisibleEntry();
1249 ASSERT_TRUE(entry != NULL);
1250 EXPECT_TRUE(entry->GetURL() == url1);
1251 EXPECT_EQ(1, controller().GetEntryCount());
1253 RunAllPendingInMessageLoop();
1254 EXPECT_TRUE(deleted);
1257 // Test navigating to a page (with the navigation initiated from the renderer,
1258 // as when clicking on a link in the page) that shows an interstitial and
1259 // creates a new navigation entry, then hiding it without proceeding.
1260 TEST_F(WebContentsImplTest,
1261 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1262 // Navigate to a page.
1263 GURL url1("http://www.google.com");
1264 test_rvh()->SendNavigate(1, url1);
1265 EXPECT_EQ(1, controller().GetEntryCount());
1267 // Show an interstitial (no pending entry, the interstitial would have been
1268 // triggered by clicking on a link).
1269 TestInterstitialPage::InterstitialState state =
1270 TestInterstitialPage::INVALID;
1271 bool deleted = false;
1272 GURL url2("http://interstitial");
1273 TestInterstitialPage* interstitial =
1274 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1275 TestInterstitialPageStateGuard state_guard(interstitial);
1276 interstitial->Show();
1277 // The interstitial should not show until its navigation has committed.
1278 EXPECT_FALSE(interstitial->is_showing());
1279 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1280 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1281 // Let's commit the interstitial navigation.
1282 interstitial->TestDidNavigate(1, url2);
1283 EXPECT_TRUE(interstitial->is_showing());
1284 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1285 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1286 NavigationEntry* entry = controller().GetVisibleEntry();
1287 ASSERT_TRUE(entry != NULL);
1288 EXPECT_TRUE(entry->GetURL() == url2);
1290 // Now don't proceed.
1291 interstitial->DontProceed();
1292 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1293 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1294 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1295 entry = controller().GetVisibleEntry();
1296 ASSERT_TRUE(entry != NULL);
1297 EXPECT_TRUE(entry->GetURL() == url1);
1298 EXPECT_EQ(1, controller().GetEntryCount());
1300 RunAllPendingInMessageLoop();
1301 EXPECT_TRUE(deleted);
1304 // Test navigating to a page that shows an interstitial without creating a new
1305 // navigation entry (this happens when the interstitial is triggered by a
1306 // sub-resource in the page), then hiding it without proceeding.
1307 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1308 // Navigate to a page.
1309 GURL url1("http://www.google.com");
1310 test_rvh()->SendNavigate(1, url1);
1311 EXPECT_EQ(1, controller().GetEntryCount());
1313 // Show an interstitial.
1314 TestInterstitialPage::InterstitialState state =
1315 TestInterstitialPage::INVALID;
1316 bool deleted = false;
1317 GURL url2("http://interstitial");
1318 TestInterstitialPage* interstitial =
1319 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1320 TestInterstitialPageStateGuard state_guard(interstitial);
1321 interstitial->Show();
1322 // The interstitial should not show until its navigation has committed.
1323 EXPECT_FALSE(interstitial->is_showing());
1324 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1325 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1326 // Let's commit the interstitial navigation.
1327 interstitial->TestDidNavigate(1, url2);
1328 EXPECT_TRUE(interstitial->is_showing());
1329 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1330 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1331 NavigationEntry* entry = controller().GetVisibleEntry();
1332 ASSERT_TRUE(entry != NULL);
1333 // The URL specified to the interstitial should have been ignored.
1334 EXPECT_TRUE(entry->GetURL() == url1);
1336 // Now don't proceed.
1337 interstitial->DontProceed();
1338 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1339 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1340 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1341 entry = controller().GetVisibleEntry();
1342 ASSERT_TRUE(entry != NULL);
1343 EXPECT_TRUE(entry->GetURL() == url1);
1344 EXPECT_EQ(1, controller().GetEntryCount());
1346 RunAllPendingInMessageLoop();
1347 EXPECT_TRUE(deleted);
1350 // Test navigating to a page (with the navigation initiated from the browser,
1351 // as when a URL is typed in the location bar) that shows an interstitial and
1352 // creates a new navigation entry, then proceeding.
1353 TEST_F(WebContentsImplTest,
1354 ShowInterstitialFromBrowserNewNavigationProceed) {
1355 // Navigate to a page.
1356 GURL url1("http://www.google.com");
1357 test_rvh()->SendNavigate(1, url1);
1358 EXPECT_EQ(1, controller().GetEntryCount());
1360 // Initiate a browser navigation that will trigger the interstitial
1361 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1362 PAGE_TRANSITION_TYPED, std::string());
1364 // Show an interstitial.
1365 TestInterstitialPage::InterstitialState state =
1366 TestInterstitialPage::INVALID;
1367 bool deleted = false;
1368 GURL url2("http://interstitial");
1369 TestInterstitialPage* interstitial =
1370 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1371 TestInterstitialPageStateGuard state_guard(interstitial);
1372 interstitial->Show();
1373 // The interstitial should not show until its navigation has committed.
1374 EXPECT_FALSE(interstitial->is_showing());
1375 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1376 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1377 // Let's commit the interstitial navigation.
1378 interstitial->TestDidNavigate(1, url2);
1379 EXPECT_TRUE(interstitial->is_showing());
1380 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1381 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1382 NavigationEntry* entry = controller().GetVisibleEntry();
1383 ASSERT_TRUE(entry != NULL);
1384 EXPECT_TRUE(entry->GetURL() == url2);
1387 interstitial->Proceed();
1388 // The interstitial should show until the new navigation commits.
1389 RunAllPendingInMessageLoop();
1390 ASSERT_FALSE(deleted);
1391 EXPECT_EQ(TestInterstitialPage::OKED, state);
1392 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1393 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1395 // Simulate the navigation to the page, that's when the interstitial gets
1397 GURL url3("http://www.thepage.com");
1398 test_rvh()->SendNavigate(2, url3);
1400 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1401 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1402 entry = controller().GetVisibleEntry();
1403 ASSERT_TRUE(entry != NULL);
1404 EXPECT_TRUE(entry->GetURL() == url3);
1406 EXPECT_EQ(2, controller().GetEntryCount());
1408 RunAllPendingInMessageLoop();
1409 EXPECT_TRUE(deleted);
1412 // Test navigating to a page (with the navigation initiated from the renderer,
1413 // as when clicking on a link in the page) that shows an interstitial and
1414 // creates a new navigation entry, then proceeding.
1415 TEST_F(WebContentsImplTest,
1416 ShowInterstitialFromRendererNewNavigationProceed) {
1417 // Navigate to a page.
1418 GURL url1("http://www.google.com");
1419 test_rvh()->SendNavigate(1, url1);
1420 EXPECT_EQ(1, controller().GetEntryCount());
1422 // Show an interstitial.
1423 TestInterstitialPage::InterstitialState state =
1424 TestInterstitialPage::INVALID;
1425 bool deleted = false;
1426 GURL url2("http://interstitial");
1427 TestInterstitialPage* interstitial =
1428 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1429 TestInterstitialPageStateGuard state_guard(interstitial);
1430 interstitial->Show();
1431 // The interstitial should not show until its navigation has committed.
1432 EXPECT_FALSE(interstitial->is_showing());
1433 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1434 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1435 // Let's commit the interstitial navigation.
1436 interstitial->TestDidNavigate(1, url2);
1437 EXPECT_TRUE(interstitial->is_showing());
1438 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1439 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1440 NavigationEntry* entry = controller().GetVisibleEntry();
1441 ASSERT_TRUE(entry != NULL);
1442 EXPECT_TRUE(entry->GetURL() == url2);
1445 interstitial->Proceed();
1446 // The interstitial should show until the new navigation commits.
1447 RunAllPendingInMessageLoop();
1448 ASSERT_FALSE(deleted);
1449 EXPECT_EQ(TestInterstitialPage::OKED, state);
1450 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1451 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1453 // Simulate the navigation to the page, that's when the interstitial gets
1455 GURL url3("http://www.thepage.com");
1456 test_rvh()->SendNavigate(2, url3);
1458 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1459 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1460 entry = controller().GetVisibleEntry();
1461 ASSERT_TRUE(entry != NULL);
1462 EXPECT_TRUE(entry->GetURL() == url3);
1464 EXPECT_EQ(2, controller().GetEntryCount());
1466 RunAllPendingInMessageLoop();
1467 EXPECT_TRUE(deleted);
1470 // Test navigating to a page that shows an interstitial without creating a new
1471 // navigation entry (this happens when the interstitial is triggered by a
1472 // sub-resource in the page), then proceeding.
1473 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1474 // Navigate to a page so we have a navigation entry in the controller.
1475 GURL url1("http://www.google.com");
1476 test_rvh()->SendNavigate(1, url1);
1477 EXPECT_EQ(1, controller().GetEntryCount());
1479 // Show an interstitial.
1480 TestInterstitialPage::InterstitialState state =
1481 TestInterstitialPage::INVALID;
1482 bool deleted = false;
1483 GURL url2("http://interstitial");
1484 TestInterstitialPage* interstitial =
1485 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1486 TestInterstitialPageStateGuard state_guard(interstitial);
1487 interstitial->Show();
1488 // The interstitial should not show until its navigation has committed.
1489 EXPECT_FALSE(interstitial->is_showing());
1490 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1491 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1492 // Let's commit the interstitial navigation.
1493 interstitial->TestDidNavigate(1, url2);
1494 EXPECT_TRUE(interstitial->is_showing());
1495 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1496 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1497 NavigationEntry* entry = controller().GetVisibleEntry();
1498 ASSERT_TRUE(entry != NULL);
1499 // The URL specified to the interstitial should have been ignored.
1500 EXPECT_TRUE(entry->GetURL() == url1);
1503 interstitial->Proceed();
1504 // Since this is not a new navigation, the previous page is dismissed right
1505 // away and shows the original page.
1506 EXPECT_EQ(TestInterstitialPage::OKED, state);
1507 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1508 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1509 entry = controller().GetVisibleEntry();
1510 ASSERT_TRUE(entry != NULL);
1511 EXPECT_TRUE(entry->GetURL() == url1);
1513 EXPECT_EQ(1, controller().GetEntryCount());
1515 RunAllPendingInMessageLoop();
1516 EXPECT_TRUE(deleted);
1519 // Test navigating to a page that shows an interstitial, then navigating away.
1520 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1521 // Show interstitial.
1522 TestInterstitialPage::InterstitialState state =
1523 TestInterstitialPage::INVALID;
1524 bool deleted = false;
1525 GURL url("http://interstitial");
1526 TestInterstitialPage* interstitial =
1527 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1528 TestInterstitialPageStateGuard state_guard(interstitial);
1529 interstitial->Show();
1530 interstitial->TestDidNavigate(1, url);
1532 // While interstitial showing, navigate to a new URL.
1533 const GURL url2("http://www.yahoo.com");
1534 test_rvh()->SendNavigate(1, url2);
1536 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1538 RunAllPendingInMessageLoop();
1539 EXPECT_TRUE(deleted);
1542 // Test navigating to a page that shows an interstitial, then going back.
1543 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1544 // Navigate to a page so we have a navigation entry in the controller.
1545 GURL url1("http://www.google.com");
1546 test_rvh()->SendNavigate(1, url1);
1547 EXPECT_EQ(1, controller().GetEntryCount());
1549 // Show interstitial.
1550 TestInterstitialPage::InterstitialState state =
1551 TestInterstitialPage::INVALID;
1552 bool deleted = false;
1553 GURL interstitial_url("http://interstitial");
1554 TestInterstitialPage* interstitial =
1555 new TestInterstitialPage(contents(), true, interstitial_url,
1557 TestInterstitialPageStateGuard state_guard(interstitial);
1558 interstitial->Show();
1559 interstitial->TestDidNavigate(2, interstitial_url);
1561 // While the interstitial is showing, go back.
1562 controller().GoBack();
1563 test_rvh()->SendNavigate(1, url1);
1565 // Make sure we are back to the original page and that the interstitial is
1567 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1568 NavigationEntry* entry = controller().GetVisibleEntry();
1570 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1572 RunAllPendingInMessageLoop();
1573 EXPECT_TRUE(deleted);
1576 // Test navigating to a page that shows an interstitial, has a renderer crash,
1577 // and then goes back.
1578 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1579 // Navigate to a page so we have a navigation entry in the controller.
1580 GURL url1("http://www.google.com");
1581 test_rvh()->SendNavigate(1, url1);
1582 EXPECT_EQ(1, controller().GetEntryCount());
1584 // Show interstitial.
1585 TestInterstitialPage::InterstitialState state =
1586 TestInterstitialPage::INVALID;
1587 bool deleted = false;
1588 GURL interstitial_url("http://interstitial");
1589 TestInterstitialPage* interstitial =
1590 new TestInterstitialPage(contents(), true, interstitial_url,
1592 TestInterstitialPageStateGuard state_guard(interstitial);
1593 interstitial->Show();
1594 interstitial->TestDidNavigate(2, interstitial_url);
1596 // Crash the renderer
1597 test_rvh()->OnMessageReceived(
1598 ViewHostMsg_RenderProcessGone(
1599 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1601 // While the interstitial is showing, go back.
1602 controller().GoBack();
1603 test_rvh()->SendNavigate(1, url1);
1605 // Make sure we are back to the original page and that the interstitial is
1607 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1608 NavigationEntry* entry = controller().GetVisibleEntry();
1610 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1612 RunAllPendingInMessageLoop();
1613 EXPECT_TRUE(deleted);
1616 // Test navigating to a page that shows an interstitial, has the renderer crash,
1617 // and then navigates to the interstitial.
1618 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1619 // Navigate to a page so we have a navigation entry in the controller.
1620 GURL url1("http://www.google.com");
1621 test_rvh()->SendNavigate(1, url1);
1622 EXPECT_EQ(1, controller().GetEntryCount());
1624 // Show interstitial.
1625 TestInterstitialPage::InterstitialState state =
1626 TestInterstitialPage::INVALID;
1627 bool deleted = false;
1628 GURL interstitial_url("http://interstitial");
1629 TestInterstitialPage* interstitial =
1630 new TestInterstitialPage(contents(), true, interstitial_url,
1632 TestInterstitialPageStateGuard state_guard(interstitial);
1633 interstitial->Show();
1635 // Crash the renderer
1636 test_rvh()->OnMessageReceived(
1637 ViewHostMsg_RenderProcessGone(
1638 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1640 interstitial->TestDidNavigate(2, interstitial_url);
1643 // Test navigating to a page that shows an interstitial, then close the
1645 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1646 // Show interstitial.
1647 TestInterstitialPage::InterstitialState state =
1648 TestInterstitialPage::INVALID;
1649 bool deleted = false;
1650 GURL url("http://interstitial");
1651 TestInterstitialPage* interstitial =
1652 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1653 TestInterstitialPageStateGuard state_guard(interstitial);
1654 interstitial->Show();
1655 interstitial->TestDidNavigate(1, url);
1657 // Now close the contents.
1659 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1661 RunAllPendingInMessageLoop();
1662 EXPECT_TRUE(deleted);
1665 // Test navigating to a page that shows an interstitial, then close the
1667 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1668 // Show interstitial.
1669 TestInterstitialPage::InterstitialState state =
1670 TestInterstitialPage::INVALID;
1671 bool deleted = false;
1672 GURL url("http://interstitial");
1673 TestInterstitialPage* interstitial =
1674 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1675 TestInterstitialPageStateGuard state_guard(interstitial);
1676 interstitial->Show();
1677 interstitial->TestDidNavigate(1, url);
1678 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1679 interstitial->GetRenderViewHostForTesting());
1681 // Now close the contents.
1683 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1685 // Before the interstitial has a chance to process its shutdown task,
1686 // simulate quitting the browser. This goes through all processes and
1687 // tells them to destruct.
1688 rvh->OnMessageReceived(
1689 ViewHostMsg_RenderProcessGone(0, 0, 0));
1691 RunAllPendingInMessageLoop();
1692 EXPECT_TRUE(deleted);
1695 // Test that after Proceed is called and an interstitial is still shown, no more
1696 // commands get executed.
1697 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1698 // Navigate to a page so we have a navigation entry in the controller.
1699 GURL url1("http://www.google.com");
1700 test_rvh()->SendNavigate(1, url1);
1701 EXPECT_EQ(1, controller().GetEntryCount());
1703 // Show an interstitial.
1704 TestInterstitialPage::InterstitialState state =
1705 TestInterstitialPage::INVALID;
1706 bool deleted = false;
1707 GURL url2("http://interstitial");
1708 TestInterstitialPage* interstitial =
1709 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1710 TestInterstitialPageStateGuard state_guard(interstitial);
1711 interstitial->Show();
1712 interstitial->TestDidNavigate(1, url2);
1715 EXPECT_EQ(0, interstitial->command_received_count());
1716 interstitial->TestDomOperationResponse("toto");
1717 EXPECT_EQ(1, interstitial->command_received_count());
1720 interstitial->Proceed();
1721 RunAllPendingInMessageLoop();
1722 ASSERT_FALSE(deleted);
1724 // While the navigation to the new page is pending, send other commands, they
1725 // should be ignored.
1726 interstitial->TestDomOperationResponse("hello");
1727 interstitial->TestDomOperationResponse("hi");
1728 EXPECT_EQ(1, interstitial->command_received_count());
1731 // Test showing an interstitial while another interstitial is already showing.
1732 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1733 // Navigate to a page so we have a navigation entry in the controller.
1734 GURL start_url("http://www.google.com");
1735 test_rvh()->SendNavigate(1, start_url);
1736 EXPECT_EQ(1, controller().GetEntryCount());
1738 // Show an interstitial.
1739 TestInterstitialPage::InterstitialState state1 =
1740 TestInterstitialPage::INVALID;
1741 bool deleted1 = false;
1742 GURL url1("http://interstitial1");
1743 TestInterstitialPage* interstitial1 =
1744 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1745 TestInterstitialPageStateGuard state_guard1(interstitial1);
1746 interstitial1->Show();
1747 interstitial1->TestDidNavigate(1, url1);
1749 // Now show another interstitial.
1750 TestInterstitialPage::InterstitialState state2 =
1751 TestInterstitialPage::INVALID;
1752 bool deleted2 = false;
1753 GURL url2("http://interstitial2");
1754 TestInterstitialPage* interstitial2 =
1755 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1756 TestInterstitialPageStateGuard state_guard2(interstitial2);
1757 interstitial2->Show();
1758 interstitial2->TestDidNavigate(1, url2);
1760 // Showing interstitial2 should have caused interstitial1 to go away.
1761 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1762 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1764 RunAllPendingInMessageLoop();
1765 EXPECT_TRUE(deleted1);
1766 ASSERT_FALSE(deleted2);
1768 // Let's make sure interstitial2 is working as intended.
1769 interstitial2->Proceed();
1770 GURL landing_url("http://www.thepage.com");
1771 test_rvh()->SendNavigate(2, landing_url);
1773 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1774 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1775 NavigationEntry* entry = controller().GetVisibleEntry();
1776 ASSERT_TRUE(entry != NULL);
1777 EXPECT_TRUE(entry->GetURL() == landing_url);
1778 EXPECT_EQ(2, controller().GetEntryCount());
1779 RunAllPendingInMessageLoop();
1780 EXPECT_TRUE(deleted2);
1783 // Test showing an interstitial, proceeding and then navigating to another
1785 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
1786 // Navigate to a page so we have a navigation entry in the controller.
1787 GURL start_url("http://www.google.com");
1788 test_rvh()->SendNavigate(1, start_url);
1789 EXPECT_EQ(1, controller().GetEntryCount());
1791 // Show an interstitial.
1792 TestInterstitialPage::InterstitialState state1 =
1793 TestInterstitialPage::INVALID;
1794 bool deleted1 = false;
1795 GURL url1("http://interstitial1");
1796 TestInterstitialPage* interstitial1 =
1797 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1798 TestInterstitialPageStateGuard state_guard1(interstitial1);
1799 interstitial1->Show();
1800 interstitial1->TestDidNavigate(1, url1);
1802 // Take action. The interstitial won't be hidden until the navigation is
1804 interstitial1->Proceed();
1805 EXPECT_EQ(TestInterstitialPage::OKED, state1);
1807 // Now show another interstitial (simulating the navigation causing another
1809 TestInterstitialPage::InterstitialState state2 =
1810 TestInterstitialPage::INVALID;
1811 bool deleted2 = false;
1812 GURL url2("http://interstitial2");
1813 TestInterstitialPage* interstitial2 =
1814 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1815 TestInterstitialPageStateGuard state_guard2(interstitial2);
1816 interstitial2->Show();
1817 interstitial2->TestDidNavigate(1, url2);
1819 // Showing interstitial2 should have caused interstitial1 to go away.
1820 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1821 RunAllPendingInMessageLoop();
1822 EXPECT_TRUE(deleted1);
1823 ASSERT_FALSE(deleted2);
1825 // Let's make sure interstitial2 is working as intended.
1826 interstitial2->Proceed();
1827 GURL landing_url("http://www.thepage.com");
1828 test_rvh()->SendNavigate(2, landing_url);
1830 RunAllPendingInMessageLoop();
1831 EXPECT_TRUE(deleted2);
1832 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1833 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1834 NavigationEntry* entry = controller().GetVisibleEntry();
1835 ASSERT_TRUE(entry != NULL);
1836 EXPECT_TRUE(entry->GetURL() == landing_url);
1837 EXPECT_EQ(2, controller().GetEntryCount());
1840 // Test that navigating away from an interstitial while it's loading cause it
1842 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
1843 // Show an interstitial.
1844 TestInterstitialPage::InterstitialState state =
1845 TestInterstitialPage::INVALID;
1846 bool deleted = false;
1847 GURL interstitial_url("http://interstitial");
1848 TestInterstitialPage* interstitial =
1849 new TestInterstitialPage(contents(), true, interstitial_url,
1851 TestInterstitialPageStateGuard state_guard(interstitial);
1852 interstitial->Show();
1854 // Let's simulate a navigation initiated from the browser before the
1855 // interstitial finishes loading.
1856 const GURL url("http://www.google.com");
1857 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1858 EXPECT_FALSE(interstitial->is_showing());
1859 RunAllPendingInMessageLoop();
1860 ASSERT_FALSE(deleted);
1862 // Now let's make the interstitial navigation commit.
1863 interstitial->TestDidNavigate(1, interstitial_url);
1865 // After it loaded the interstitial should be gone.
1866 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1868 RunAllPendingInMessageLoop();
1869 EXPECT_TRUE(deleted);
1872 // Test that a new request to show an interstitial while an interstitial is
1873 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
1874 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
1875 GURL interstitial_url("http://interstitial");
1877 // Show a first interstitial.
1878 TestInterstitialPage::InterstitialState state1 =
1879 TestInterstitialPage::INVALID;
1880 bool deleted1 = false;
1881 TestInterstitialPage* interstitial1 =
1882 new TestInterstitialPage(contents(), true, interstitial_url,
1883 &state1, &deleted1);
1884 TestInterstitialPageStateGuard state_guard1(interstitial1);
1885 interstitial1->Show();
1887 // Show another interstitial on that same contents before the first one had
1889 TestInterstitialPage::InterstitialState state2 =
1890 TestInterstitialPage::INVALID;
1891 bool deleted2 = false;
1892 TestInterstitialPage* interstitial2 =
1893 new TestInterstitialPage(contents(), true, interstitial_url,
1894 &state2, &deleted2);
1895 TestInterstitialPageStateGuard state_guard2(interstitial2);
1896 interstitial2->Show();
1898 // The first interstitial should have been closed and deleted.
1899 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1900 // The 2nd one should still be OK.
1901 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1903 RunAllPendingInMessageLoop();
1904 EXPECT_TRUE(deleted1);
1905 ASSERT_FALSE(deleted2);
1907 // Make the interstitial navigation commit it should be showing.
1908 interstitial2->TestDidNavigate(1, interstitial_url);
1909 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
1912 // Test showing an interstitial and have its renderer crash.
1913 TEST_F(WebContentsImplTest, InterstitialCrasher) {
1914 // Show an interstitial.
1915 TestInterstitialPage::InterstitialState state =
1916 TestInterstitialPage::INVALID;
1917 bool deleted = false;
1918 GURL url("http://interstitial");
1919 TestInterstitialPage* interstitial =
1920 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1921 TestInterstitialPageStateGuard state_guard(interstitial);
1922 interstitial->Show();
1923 // Simulate a renderer crash before the interstitial is shown.
1924 interstitial->TestRenderViewTerminated(
1925 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1926 // The interstitial should have been dismissed.
1927 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1928 RunAllPendingInMessageLoop();
1929 EXPECT_TRUE(deleted);
1931 // Now try again but this time crash the intersitial after it was shown.
1933 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1934 interstitial->Show();
1935 interstitial->TestDidNavigate(1, url);
1936 // Simulate a renderer crash.
1937 interstitial->TestRenderViewTerminated(
1938 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1939 // The interstitial should have been dismissed.
1940 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1941 RunAllPendingInMessageLoop();
1942 EXPECT_TRUE(deleted);
1945 // Tests that showing an interstitial as a result of a browser initiated
1946 // navigation while an interstitial is showing does not remove the pending
1947 // entry (see http://crbug.com/9791).
1948 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
1949 const char kUrl[] = "http://www.badguys.com/";
1950 const GURL kGURL(kUrl);
1952 // Start a navigation to a page
1953 contents()->GetController().LoadURL(
1954 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1956 // Simulate that navigation triggering an interstitial.
1957 TestInterstitialPage::InterstitialState state =
1958 TestInterstitialPage::INVALID;
1959 bool deleted = false;
1960 TestInterstitialPage* interstitial =
1961 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
1962 TestInterstitialPageStateGuard state_guard(interstitial);
1963 interstitial->Show();
1964 interstitial->TestDidNavigate(1, kGURL);
1966 // Initiate a new navigation from the browser that also triggers an
1968 contents()->GetController().LoadURL(
1969 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1970 TestInterstitialPage::InterstitialState state2 =
1971 TestInterstitialPage::INVALID;
1972 bool deleted2 = false;
1973 TestInterstitialPage* interstitial2 =
1974 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
1975 TestInterstitialPageStateGuard state_guard2(interstitial2);
1976 interstitial2->Show();
1977 interstitial2->TestDidNavigate(1, kGURL);
1979 // Make sure we still have an entry.
1980 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
1982 EXPECT_EQ(kUrl, entry->GetURL().spec());
1984 // And that the first interstitial is gone, but not the second.
1985 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1986 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1987 RunAllPendingInMessageLoop();
1988 EXPECT_TRUE(deleted);
1989 EXPECT_FALSE(deleted2);
1992 // Tests that Javascript messages are not shown while an interstitial is
1994 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
1995 const char kUrl[] = "http://www.badguys.com/";
1996 const GURL kGURL(kUrl);
1998 // Start a navigation to a page
1999 contents()->GetController().LoadURL(
2000 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2001 // DidNavigate from the page
2002 contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
2004 // Simulate showing an interstitial while the page is showing.
2005 TestInterstitialPage::InterstitialState state =
2006 TestInterstitialPage::INVALID;
2007 bool deleted = false;
2008 TestInterstitialPage* interstitial =
2009 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2010 TestInterstitialPageStateGuard state_guard(interstitial);
2011 interstitial->Show();
2012 interstitial->TestDidNavigate(1, kGURL);
2014 // While the interstitial is showing, let's simulate the hidden page
2015 // attempting to show a JS message.
2016 IPC::Message* dummy_message = new IPC::Message;
2017 bool did_suppress_message = false;
2018 contents()->RunJavaScriptMessage(contents()->GetRenderViewHost(),
2019 ASCIIToUTF16("This is an informative message"), ASCIIToUTF16("OK"),
2020 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message,
2021 &did_suppress_message);
2022 EXPECT_TRUE(did_suppress_message);
2025 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2026 // interstitial it isn't copied over to the destination.
2027 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2028 // Navigate to a page.
2029 GURL url1("http://www.google.com");
2030 test_rvh()->SendNavigate(1, url1);
2031 EXPECT_EQ(1, controller().GetEntryCount());
2033 // Initiate a browser navigation that will trigger the interstitial
2034 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2035 PAGE_TRANSITION_TYPED, std::string());
2037 // Show an interstitial.
2038 TestInterstitialPage::InterstitialState state =
2039 TestInterstitialPage::INVALID;
2040 bool deleted = false;
2041 GURL url2("http://interstitial");
2042 TestInterstitialPage* interstitial =
2043 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2044 TestInterstitialPageStateGuard state_guard(interstitial);
2045 interstitial->Show();
2046 interstitial->TestDidNavigate(1, url2);
2047 EXPECT_TRUE(interstitial->is_showing());
2048 EXPECT_EQ(2, controller().GetEntryCount());
2050 // Create another NavigationController.
2051 GURL url3("http://foo2");
2052 scoped_ptr<TestWebContents> other_contents(
2053 static_cast<TestWebContents*>(CreateTestWebContents()));
2054 NavigationControllerImpl& other_controller = other_contents->GetController();
2055 other_contents->NavigateAndCommit(url3);
2056 other_contents->ExpectSetHistoryLengthAndPrune(
2057 NavigationEntryImpl::FromNavigationEntry(
2058 other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2059 other_controller.GetEntryAtIndex(0)->GetPageID());
2060 other_controller.CopyStateFromAndPrune(&controller());
2062 // The merged controller should only have two entries: url1 and url2.
2063 ASSERT_EQ(2, other_controller.GetEntryCount());
2064 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2065 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2066 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2068 // And the merged controller shouldn't be showing an interstitial.
2069 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2072 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2073 // showing an interstitial.
2074 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2075 // Navigate to a page.
2076 GURL url1("http://www.google.com");
2077 contents()->NavigateAndCommit(url1);
2079 // Create another NavigationController.
2080 scoped_ptr<TestWebContents> other_contents(
2081 static_cast<TestWebContents*>(CreateTestWebContents()));
2082 NavigationControllerImpl& other_controller = other_contents->GetController();
2084 // Navigate it to url2.
2085 GURL url2("http://foo2");
2086 other_contents->NavigateAndCommit(url2);
2088 // Show an interstitial.
2089 TestInterstitialPage::InterstitialState state =
2090 TestInterstitialPage::INVALID;
2091 bool deleted = false;
2092 GURL url3("http://interstitial");
2093 TestInterstitialPage* interstitial =
2094 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2096 TestInterstitialPageStateGuard state_guard(interstitial);
2097 interstitial->Show();
2098 interstitial->TestDidNavigate(1, url3);
2099 EXPECT_TRUE(interstitial->is_showing());
2100 EXPECT_EQ(2, other_controller.GetEntryCount());
2102 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2103 // interstitial is showing in the target.
2104 EXPECT_FALSE(other_controller.CanPruneAllButVisible());
2107 // Regression test for http://crbug.com/168611 - the URLs passed by the
2108 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2109 TEST_F(WebContentsImplTest, FilterURLs) {
2110 TestWebContentsObserver observer(contents());
2112 // A navigation to about:whatever should always look like a navigation to
2114 GURL url_normalized(kAboutBlankURL);
2115 GURL url_from_ipc("about:whatever");
2117 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2118 // will use the given URL to create the NavigationEntry as well, and that
2119 // entry should contain the filtered URL.
2120 contents()->NavigateAndCommit(url_normalized);
2122 // Check that an IPC with about:whatever is correctly normalized.
2123 contents()->TestDidFinishLoad(1, url_from_ipc, true);
2125 EXPECT_EQ(url_normalized, observer.last_url());
2127 // Create and navigate another WebContents.
2128 scoped_ptr<TestWebContents> other_contents(
2129 static_cast<TestWebContents*>(CreateTestWebContents()));
2130 TestWebContentsObserver other_observer(other_contents.get());
2131 other_contents->NavigateAndCommit(url_normalized);
2133 // Check that an IPC with about:whatever is correctly normalized.
2134 other_contents->TestDidFailLoadWithError(
2135 1, url_from_ipc, true, 1, string16());
2136 EXPECT_EQ(url_normalized, other_observer.last_url());
2139 // Test that if a pending contents is deleted before it is shown, we don't
2141 TEST_F(WebContentsImplTest, PendingContents) {
2142 scoped_ptr<TestWebContents> other_contents(
2143 static_cast<TestWebContents*>(CreateTestWebContents()));
2144 contents()->AddPendingContents(other_contents.get());
2145 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2146 other_contents.reset();
2147 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2150 } // namespace content