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/site_instance_impl.h"
11 #include "content/browser/webui/web_ui_controller_factory_registry.h"
12 #include "content/common/view_messages.h"
13 #include "content/public/browser/global_request_id.h"
14 #include "content/public/browser/interstitial_page_delegate.h"
15 #include "content/public/browser/navigation_details.h"
16 #include "content/public/browser/notification_details.h"
17 #include "content/public/browser/notification_source.h"
18 #include "content/public/browser/render_widget_host_view.h"
19 #include "content/public/browser/web_contents_observer.h"
20 #include "content/public/browser/web_ui_controller.h"
21 #include "content/public/common/bindings_policy.h"
22 #include "content/public/common/content_constants.h"
23 #include "content/public/common/url_constants.h"
24 #include "content/public/common/url_utils.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_render_view_host.h"
31 #include "content/test/test_web_contents.h"
32 #include "testing/gtest/include/gtest/gtest.h"
37 const char kTestWebUIUrl[] = "chrome://blah";
39 class WebContentsImplTestWebUIControllerFactory
40 : public WebUIControllerFactory {
42 virtual WebUIController* CreateWebUIControllerForURL(
43 WebUI* web_ui, const GURL& url) const OVERRIDE {
46 return new WebUIController(web_ui);
49 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
50 const GURL& url) const OVERRIDE {
51 return WebUI::kNoWebUI;
54 virtual bool UseWebUIForURL(BrowserContext* browser_context,
55 const GURL& url) const OVERRIDE {
59 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
60 const GURL& url) const OVERRIDE {
65 bool UseWebUI(const GURL& url) const {
66 return url == GURL(kTestWebUIUrl);
70 class TestInterstitialPage;
72 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
74 explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
75 : interstitial_page_(interstitial_page) {}
76 virtual void CommandReceived(const std::string& command) OVERRIDE;
77 virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
78 virtual void OnDontProceed() OVERRIDE;
79 virtual void OnProceed() OVERRIDE;
81 TestInterstitialPage* interstitial_page_;
84 class TestInterstitialPage : public InterstitialPageImpl {
86 enum InterstitialState {
87 INVALID = 0, // Hasn't yet been initialized.
88 UNDECIDED, // Initialized, but no decision taken yet.
89 OKED, // Proceed was called.
90 CANCELED // DontProceed was called.
95 virtual void TestInterstitialPageDeleted(
96 TestInterstitialPage* interstitial) = 0;
99 virtual ~Delegate() {}
102 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
103 // |deleted| (like all interstitial related tests do at this point), make sure
104 // to create an instance of the TestInterstitialPageStateGuard class on the
105 // stack in your test. This will ensure that the TestInterstitialPage states
106 // are cleared when the test finishes.
107 // Not doing so will cause stack trashing if your test does not hide the
108 // interstitial, as in such a case it will be destroyed in the test TearDown
109 // method and will dereference the |deleted| local variable which by then is
111 TestInterstitialPage(WebContentsImpl* contents,
114 InterstitialState* state,
116 : InterstitialPageImpl(
118 static_cast<RenderWidgetHostDelegate*>(contents),
119 new_navigation, url, new TestInterstitialPageDelegate(this)),
122 command_received_count_(0),
128 virtual ~TestInterstitialPage() {
132 delegate_->TestInterstitialPageDeleted(this);
135 void OnDontProceed() {
144 int command_received_count() const {
145 return command_received_count_;
148 void TestDomOperationResponse(const std::string& json_string) {
153 void TestDidNavigate(int page_id, const GURL& url) {
154 ViewHostMsg_FrameNavigate_Params params;
155 InitNavigateParams(¶ms, page_id, url, PAGE_TRANSITION_TYPED);
156 DidNavigate(GetRenderViewHostForTesting(), params);
159 void TestRenderViewTerminated(base::TerminationStatus status,
161 RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
164 bool is_showing() const {
165 return static_cast<TestRenderWidgetHostView*>(
166 GetRenderViewHostForTesting()->GetView())->is_showing();
175 void CommandReceived() {
176 command_received_count_++;
179 void set_delegate(Delegate* delegate) {
180 delegate_ = delegate;
184 virtual WebContentsView* CreateWebContentsView() OVERRIDE {
189 InterstitialState* state_;
191 int command_received_count_;
195 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
196 interstitial_page_->CommandReceived();
199 void TestInterstitialPageDelegate::OnDontProceed() {
200 interstitial_page_->OnDontProceed();
203 void TestInterstitialPageDelegate::OnProceed() {
204 interstitial_page_->OnProceed();
207 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
209 explicit TestInterstitialPageStateGuard(
210 TestInterstitialPage* interstitial_page)
211 : interstitial_page_(interstitial_page) {
212 DCHECK(interstitial_page_);
213 interstitial_page_->set_delegate(this);
215 virtual ~TestInterstitialPageStateGuard() {
216 if (interstitial_page_)
217 interstitial_page_->ClearStates();
220 virtual void TestInterstitialPageDeleted(
221 TestInterstitialPage* interstitial) OVERRIDE {
222 DCHECK(interstitial_page_ == interstitial);
223 interstitial_page_ = NULL;
227 TestInterstitialPage* interstitial_page_;
230 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
232 WebContentsImplTestBrowserClient()
233 : assign_site_for_url_(false) {}
235 virtual ~WebContentsImplTestBrowserClient() {}
237 virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
238 return assign_site_for_url_;
241 void set_assign_site_for_url(bool assign) {
242 assign_site_for_url_ = assign;
246 bool assign_site_for_url_;
249 class WebContentsImplTest : public RenderViewHostImplTestHarness {
251 virtual void SetUp() {
252 RenderViewHostImplTestHarness::SetUp();
253 WebUIControllerFactory::RegisterFactory(&factory_);
256 virtual void TearDown() {
257 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
258 RenderViewHostImplTestHarness::TearDown();
262 WebContentsImplTestWebUIControllerFactory factory_;
265 class TestWebContentsObserver : public WebContentsObserver {
267 explicit TestWebContentsObserver(WebContents* contents)
268 : WebContentsObserver(contents) {
270 virtual ~TestWebContentsObserver() {}
272 virtual void DidFinishLoad(int64 frame_id,
273 const GURL& validated_url,
275 RenderViewHost* render_view_host) OVERRIDE {
276 last_url_ = validated_url;
278 virtual void DidFailLoad(int64 frame_id,
279 const GURL& validated_url,
282 const base::string16& error_description,
283 RenderViewHost* render_view_host) OVERRIDE {
284 last_url_ = validated_url;
287 const GURL& last_url() const { return last_url_; }
292 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
297 // Test to make sure that title updates get stripped of whitespace.
298 TEST_F(WebContentsImplTest, UpdateTitle) {
299 NavigationControllerImpl& cont =
300 static_cast<NavigationControllerImpl&>(controller());
301 ViewHostMsg_FrameNavigate_Params params;
302 InitNavigateParams(¶ms, 0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED);
304 LoadCommittedDetails details;
305 cont.RendererDidNavigate(test_rvh(), params, &details);
307 contents()->UpdateTitle(rvh(), 0,
308 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
309 base::i18n::LEFT_TO_RIGHT);
310 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
313 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
314 const GURL kGURL("chrome://blah");
315 controller().LoadURL(
316 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
317 EXPECT_EQ(base::string16(), contents()->GetTitle());
320 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
321 const GURL kGURL("chrome://blah");
322 const base::string16 title = base::ASCIIToUTF16("My Title");
323 controller().LoadURL(
324 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
326 NavigationEntry* entry = controller().GetVisibleEntry();
327 ASSERT_EQ(kGURL, entry->GetURL());
328 entry->SetTitle(title);
330 EXPECT_EQ(title, contents()->GetTitle());
333 // Test view source mode for a webui page.
334 TEST_F(WebContentsImplTest, NTPViewSource) {
335 NavigationControllerImpl& cont =
336 static_cast<NavigationControllerImpl&>(controller());
337 const char kUrl[] = "view-source:chrome://blah";
338 const GURL kGURL(kUrl);
340 process()->sink().ClearMessages();
343 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
344 rvh()->GetDelegate()->RenderViewCreated(rvh());
345 // Did we get the expected message?
346 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
347 ViewMsg_EnableViewSourceMode::ID));
349 ViewHostMsg_FrameNavigate_Params params;
350 InitNavigateParams(¶ms, 0, kGURL, PAGE_TRANSITION_TYPED);
351 LoadCommittedDetails details;
352 cont.RendererDidNavigate(test_rvh(), params, &details);
353 // Also check title and url.
354 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
357 // Test to ensure UpdateMaxPageID is working properly.
358 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
359 SiteInstance* instance1 = contents()->GetSiteInstance();
360 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
363 EXPECT_EQ(-1, contents()->GetMaxPageID());
364 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
365 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
367 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
368 contents()->UpdateMaxPageID(3);
369 contents()->UpdateMaxPageID(1);
370 EXPECT_EQ(3, contents()->GetMaxPageID());
371 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
372 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
374 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
375 EXPECT_EQ(3, contents()->GetMaxPageID());
376 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
377 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
380 // Test simple same-SiteInstance navigation.
381 TEST_F(WebContentsImplTest, SimpleNavigation) {
382 TestRenderViewHost* orig_rvh = test_rvh();
383 SiteInstance* instance1 = contents()->GetSiteInstance();
384 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
387 const GURL url("http://www.google.com");
388 controller().LoadURL(
389 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
390 EXPECT_FALSE(contents()->cross_navigation_pending());
391 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
392 // Controller's pending entry will have a NULL site instance until we assign
393 // it in DidNavigate.
395 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
396 site_instance() == NULL);
398 // DidNavigate from the page
399 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
400 EXPECT_FALSE(contents()->cross_navigation_pending());
401 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
402 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
403 // Controller's entry should now have the SiteInstance, or else we won't be
404 // able to find it later.
407 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
411 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
412 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
413 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
414 const GURL url(std::string("http://example.org/").append(
415 GetMaxURLChars() + 1, 'a'));
417 controller().LoadURL(
418 url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
419 EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
422 // Test that navigating across a site boundary creates a new RenderViewHost
423 // with a new SiteInstance. Going back should do the same.
424 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
425 contents()->transition_cross_site = true;
426 TestRenderViewHost* orig_rvh = test_rvh();
427 RenderFrameHostImpl* orig_rfh =
428 contents()->GetFrameTree()->root()->current_frame_host();
429 int orig_rvh_delete_count = 0;
430 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
431 SiteInstance* instance1 = contents()->GetSiteInstance();
433 // Navigate to URL. First URL should use first RenderViewHost.
434 const GURL url("http://www.google.com");
435 controller().LoadURL(
436 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
437 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
439 // Keep the number of active views in orig_rvh's SiteInstance
440 // non-zero so that orig_rvh doesn't get deleted when it gets
442 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
443 increment_active_view_count();
445 EXPECT_FALSE(contents()->cross_navigation_pending());
446 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
447 EXPECT_EQ(url, contents()->GetLastCommittedURL());
448 EXPECT_EQ(url, contents()->GetVisibleURL());
450 // Navigate to new site
451 const GURL url2("http://www.yahoo.com");
452 controller().LoadURL(
453 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
454 EXPECT_TRUE(contents()->cross_navigation_pending());
455 EXPECT_EQ(url, contents()->GetLastCommittedURL());
456 EXPECT_EQ(url2, contents()->GetVisibleURL());
457 TestRenderViewHost* pending_rvh =
458 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
459 int pending_rvh_delete_count = 0;
460 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
461 RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()->
462 render_manager()->pending_frame_host();
464 // Navigations should be suspended in pending_rvh until ShouldCloseACK.
465 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
466 orig_rvh->SendShouldCloseACK(true);
467 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
469 // DidNavigate from the pending page
470 contents()->TestDidNavigate(
471 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
472 SiteInstance* instance2 = contents()->GetSiteInstance();
474 // Keep the number of active views in pending_rvh's SiteInstance
475 // non-zero so that orig_rvh doesn't get deleted when it gets
477 static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
478 increment_active_view_count();
480 EXPECT_FALSE(contents()->cross_navigation_pending());
481 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
482 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
483 EXPECT_EQ(url2, contents()->GetVisibleURL());
484 EXPECT_NE(instance1, instance2);
485 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
486 // We keep the original RFH around, swapped out.
487 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
489 EXPECT_EQ(orig_rvh_delete_count, 0);
491 // Going back should switch SiteInstances again. The first SiteInstance is
492 // stored in the NavigationEntry, so it should be the same as at the start.
493 // We should use the same RVH as before, swapping it back in.
494 controller().GoBack();
495 TestRenderViewHost* goback_rvh =
496 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
497 EXPECT_EQ(orig_rvh, goback_rvh);
498 EXPECT_TRUE(contents()->cross_navigation_pending());
500 // Navigations should be suspended in goback_rvh until ShouldCloseACK.
501 EXPECT_TRUE(goback_rvh->are_navigations_suspended());
502 pending_rvh->SendShouldCloseACK(true);
503 EXPECT_FALSE(goback_rvh->are_navigations_suspended());
505 // DidNavigate from the back action
506 contents()->TestDidNavigate(
507 goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
508 EXPECT_FALSE(contents()->cross_navigation_pending());
509 EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
510 EXPECT_EQ(instance1, contents()->GetSiteInstance());
511 // The pending RFH should now be swapped out, not deleted.
512 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
513 IsOnSwappedOutList(pending_rfh));
514 EXPECT_EQ(pending_rvh_delete_count, 0);
516 // Close contents and ensure RVHs are deleted.
518 EXPECT_EQ(orig_rvh_delete_count, 1);
519 EXPECT_EQ(pending_rvh_delete_count, 1);
522 // Test that navigating across a site boundary after a crash creates a new
523 // RVH without requiring a cross-site transition (i.e., PENDING state).
524 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
525 contents()->transition_cross_site = true;
526 TestRenderViewHost* orig_rvh = test_rvh();
527 int orig_rvh_delete_count = 0;
528 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
529 SiteInstance* instance1 = contents()->GetSiteInstance();
531 // Navigate to URL. First URL should use first RenderViewHost.
532 const GURL url("http://www.google.com");
533 controller().LoadURL(
534 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
535 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
537 EXPECT_FALSE(contents()->cross_navigation_pending());
538 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
540 // Crash the renderer.
541 orig_rvh->set_render_view_created(false);
543 // Navigate to new site. We should not go into PENDING.
544 const GURL url2("http://www.yahoo.com");
545 controller().LoadURL(
546 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
547 RenderViewHost* new_rvh = rvh();
548 EXPECT_FALSE(contents()->cross_navigation_pending());
549 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
550 EXPECT_NE(orig_rvh, new_rvh);
551 EXPECT_EQ(orig_rvh_delete_count, 1);
553 // DidNavigate from the new page
554 contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
555 SiteInstance* instance2 = contents()->GetSiteInstance();
557 EXPECT_FALSE(contents()->cross_navigation_pending());
558 EXPECT_EQ(new_rvh, rvh());
559 EXPECT_NE(instance1, instance2);
560 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
562 // Close contents and ensure RVHs are deleted.
564 EXPECT_EQ(orig_rvh_delete_count, 1);
567 // Test that opening a new contents in the same SiteInstance and then navigating
568 // both contentses to a new site will place both contentses in a single
570 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
571 contents()->transition_cross_site = true;
572 TestRenderViewHost* orig_rvh = test_rvh();
573 SiteInstance* instance1 = contents()->GetSiteInstance();
575 // Navigate to URL. First URL should use first RenderViewHost.
576 const GURL url("http://www.google.com");
577 controller().LoadURL(
578 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
579 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
581 // Open a new contents with the same SiteInstance, navigated to the same site.
582 scoped_ptr<TestWebContents> contents2(
583 TestWebContents::Create(browser_context(), instance1));
584 contents2->transition_cross_site = true;
585 contents2->GetController().LoadURL(url, Referrer(),
586 PAGE_TRANSITION_TYPED,
588 // Need this page id to be 2 since the site instance is the same (which is the
589 // scope of page IDs) and we want to consider this a new page.
590 contents2->TestDidNavigate(
591 contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
593 // Navigate first contents to a new site.
594 const GURL url2a("http://www.yahoo.com");
595 controller().LoadURL(
596 url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
597 orig_rvh->SendShouldCloseACK(true);
598 TestRenderViewHost* pending_rvh_a =
599 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
600 contents()->TestDidNavigate(
601 pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
602 SiteInstance* instance2a = contents()->GetSiteInstance();
603 EXPECT_NE(instance1, instance2a);
605 // Navigate second contents to the same site as the first tab.
606 const GURL url2b("http://mail.yahoo.com");
607 contents2->GetController().LoadURL(url2b, Referrer(),
608 PAGE_TRANSITION_TYPED,
610 TestRenderViewHost* rvh2 =
611 static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
612 rvh2->SendShouldCloseACK(true);
613 TestRenderViewHost* pending_rvh_b =
614 static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
615 EXPECT_TRUE(pending_rvh_b != NULL);
616 EXPECT_TRUE(contents2->cross_navigation_pending());
618 // NOTE(creis): We used to be in danger of showing a crash page here if the
619 // second contents hadn't navigated somewhere first (bug 1145430). That case
620 // is now covered by the CrossSiteBoundariesAfterCrash test.
621 contents2->TestDidNavigate(
622 pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
623 SiteInstance* instance2b = contents2->GetSiteInstance();
624 EXPECT_NE(instance1, instance2b);
626 // Both contentses should now be in the same SiteInstance.
627 EXPECT_EQ(instance2a, instance2b);
630 TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
631 WebContentsImplTestBrowserClient browser_client;
632 SetBrowserClientForTesting(&browser_client);
634 contents()->transition_cross_site = true;
635 TestRenderViewHost* orig_rvh = test_rvh();
636 RenderFrameHostImpl* orig_rfh =
637 contents()->GetFrameTree()->root()->current_frame_host();
638 int orig_rvh_delete_count = 0;
639 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
640 SiteInstanceImpl* orig_instance =
641 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
643 browser_client.set_assign_site_for_url(false);
644 // Navigate to an URL that will not assign a new SiteInstance.
645 const GURL native_url("non-site-url://stuffandthings");
646 controller().LoadURL(
647 native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
648 contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
650 EXPECT_FALSE(contents()->cross_navigation_pending());
651 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
652 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
653 EXPECT_EQ(native_url, contents()->GetVisibleURL());
654 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
655 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
656 EXPECT_FALSE(orig_instance->HasSite());
658 browser_client.set_assign_site_for_url(true);
659 // Navigate to new site (should keep same site instance).
660 const GURL url("http://www.google.com");
661 controller().LoadURL(
662 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
663 EXPECT_FALSE(contents()->cross_navigation_pending());
664 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
665 EXPECT_EQ(url, contents()->GetVisibleURL());
666 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
667 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
669 // Keep the number of active views in orig_rvh's SiteInstance
670 // non-zero so that orig_rvh doesn't get deleted when it gets
672 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
673 increment_active_view_count();
675 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
677 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
678 EXPECT_EQ(url, contents()->GetLastCommittedURL());
680 // Navigate to another new site (should create a new site instance).
681 const GURL url2("http://www.yahoo.com");
682 controller().LoadURL(
683 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
684 EXPECT_TRUE(contents()->cross_navigation_pending());
685 EXPECT_EQ(url, contents()->GetLastCommittedURL());
686 EXPECT_EQ(url2, contents()->GetVisibleURL());
687 TestRenderViewHost* pending_rvh =
688 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
689 int pending_rvh_delete_count = 0;
690 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
692 // Navigations should be suspended in pending_rvh until ShouldCloseACK.
693 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
694 orig_rvh->SendShouldCloseACK(true);
695 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
697 // DidNavigate from the pending page.
698 contents()->TestDidNavigate(
699 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
700 SiteInstance* new_instance = contents()->GetSiteInstance();
702 EXPECT_FALSE(contents()->cross_navigation_pending());
703 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
704 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
705 EXPECT_EQ(url2, contents()->GetVisibleURL());
706 EXPECT_NE(new_instance, orig_instance);
707 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
708 // We keep the original RFH around, swapped out.
709 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
711 EXPECT_EQ(orig_rvh_delete_count, 0);
713 // Close contents and ensure RVHs are deleted.
715 EXPECT_EQ(orig_rvh_delete_count, 1);
716 EXPECT_EQ(pending_rvh_delete_count, 1);
719 // Test that we can find an opener RVH even if it's pending.
720 // http://crbug.com/176252.
721 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
722 contents()->transition_cross_site = true;
723 TestRenderViewHost* orig_rvh = test_rvh();
725 // Navigate to a URL.
726 const GURL url("http://www.google.com");
727 controller().LoadURL(
728 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
729 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
731 // Start to navigate first tab to a new site, so that it has a pending RVH.
732 const GURL url2("http://www.yahoo.com");
733 controller().LoadURL(
734 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
735 orig_rvh->SendShouldCloseACK(true);
736 TestRenderViewHost* pending_rvh =
737 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
739 // While it is still pending, simulate opening a new tab with the first tab
740 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
741 // on the opener to ensure that an RVH exists.
742 int opener_routing_id = contents()->CreateOpenerRenderViews(
743 pending_rvh->GetSiteInstance());
745 // We should find the pending RVH and not create a new one.
746 EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
749 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
750 // to determine whether a navigation is cross-site.
751 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
752 contents()->transition_cross_site = true;
753 RenderViewHost* orig_rvh = rvh();
754 SiteInstance* instance1 = contents()->GetSiteInstance();
757 const GURL url("http://www.google.com");
758 controller().LoadURL(
759 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
760 contents()->TestDidNavigate(
761 orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
763 // Open a related contents to a second site.
764 scoped_ptr<TestWebContents> contents2(
765 TestWebContents::Create(browser_context(), instance1));
766 contents2->transition_cross_site = true;
767 const GURL url2("http://www.yahoo.com");
768 contents2->GetController().LoadURL(url2, Referrer(),
769 PAGE_TRANSITION_TYPED,
771 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
773 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
774 contents2->GetRenderViewHost());
775 EXPECT_FALSE(contents2->cross_navigation_pending());
776 contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
777 SiteInstance* instance2 = contents2->GetSiteInstance();
778 EXPECT_NE(instance1, instance2);
779 EXPECT_FALSE(contents2->cross_navigation_pending());
781 // Simulate a link click in first contents to second site. Doesn't switch
782 // SiteInstances, because we don't intercept WebKit navigations.
783 contents()->TestDidNavigate(
784 orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
785 SiteInstance* instance3 = contents()->GetSiteInstance();
786 EXPECT_EQ(instance1, instance3);
787 EXPECT_FALSE(contents()->cross_navigation_pending());
789 // Navigate to the new site. Doesn't switch SiteInstancees, because we
790 // compare against the current URL, not the SiteInstance's site.
791 const GURL url3("http://mail.yahoo.com");
792 controller().LoadURL(
793 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
794 EXPECT_FALSE(contents()->cross_navigation_pending());
795 contents()->TestDidNavigate(
796 orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
797 SiteInstance* instance4 = contents()->GetSiteInstance();
798 EXPECT_EQ(instance1, instance4);
801 // Test that the onbeforeunload and onunload handlers run when navigating
802 // across site boundaries.
803 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
804 contents()->transition_cross_site = true;
805 TestRenderViewHost* orig_rvh = test_rvh();
806 SiteInstance* instance1 = contents()->GetSiteInstance();
808 // Navigate to URL. First URL should use first RenderViewHost.
809 const GURL url("http://www.google.com");
810 controller().LoadURL(
811 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
812 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
813 EXPECT_FALSE(contents()->cross_navigation_pending());
814 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
816 // Navigate to new site, but simulate an onbeforeunload denial.
817 const GURL url2("http://www.yahoo.com");
818 controller().LoadURL(
819 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
820 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
821 base::TimeTicks now = base::TimeTicks::Now();
822 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, false, now, now));
823 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
824 EXPECT_FALSE(contents()->cross_navigation_pending());
825 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
827 // Navigate again, but simulate an onbeforeunload approval.
828 controller().LoadURL(
829 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
830 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
831 now = base::TimeTicks::Now();
832 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
833 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
834 EXPECT_TRUE(contents()->cross_navigation_pending());
835 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
836 contents()->GetPendingRenderViewHost());
838 // We won't hear DidNavigate until the onunload handler has finished running.
840 // DidNavigate from the pending page.
841 contents()->TestDidNavigate(
842 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
843 SiteInstance* instance2 = contents()->GetSiteInstance();
844 EXPECT_FALSE(contents()->cross_navigation_pending());
845 EXPECT_EQ(pending_rvh, rvh());
846 EXPECT_NE(instance1, instance2);
847 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
850 // Test that during a slow cross-site navigation, the original renderer can
851 // navigate to a different URL and have it displayed, canceling the slow
853 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
854 contents()->transition_cross_site = true;
855 TestRenderViewHost* orig_rvh = test_rvh();
856 SiteInstance* instance1 = contents()->GetSiteInstance();
858 // Navigate to URL. First URL should use first RenderViewHost.
859 const GURL url("http://www.google.com");
860 controller().LoadURL(
861 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
862 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
863 EXPECT_FALSE(contents()->cross_navigation_pending());
864 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
866 // Navigate to new site, simulating an onbeforeunload approval.
867 const GURL url2("http://www.yahoo.com");
868 controller().LoadURL(
869 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
870 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
871 base::TimeTicks now = base::TimeTicks::Now();
872 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
873 EXPECT_TRUE(contents()->cross_navigation_pending());
875 // Suppose the original renderer navigates before the new one is ready.
876 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
878 // Verify that the pending navigation is cancelled.
879 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
880 SiteInstance* instance2 = contents()->GetSiteInstance();
881 EXPECT_FALSE(contents()->cross_navigation_pending());
882 EXPECT_EQ(orig_rvh, rvh());
883 EXPECT_EQ(instance1, instance2);
884 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
887 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
888 contents()->transition_cross_site = true;
890 // Start with a web ui page, which gets a new RVH with WebUI bindings.
891 const GURL url1("chrome://blah");
892 controller().LoadURL(
893 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
894 TestRenderViewHost* ntp_rvh = test_rvh();
895 contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
896 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
897 SiteInstance* instance1 = contents()->GetSiteInstance();
899 EXPECT_FALSE(contents()->cross_navigation_pending());
900 EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
901 EXPECT_EQ(url1, entry1->GetURL());
903 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
904 EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
906 // Navigate to new site.
907 const GURL url2("http://www.google.com");
908 controller().LoadURL(
909 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
910 EXPECT_TRUE(contents()->cross_navigation_pending());
911 TestRenderViewHost* google_rvh =
912 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
914 // Simulate beforeunload approval.
915 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
916 base::TimeTicks now = base::TimeTicks::Now();
917 ntp_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
919 // DidNavigate from the pending page.
920 contents()->TestDidNavigate(
921 google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
922 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
923 SiteInstance* instance2 = contents()->GetSiteInstance();
925 EXPECT_FALSE(contents()->cross_navigation_pending());
926 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
927 EXPECT_NE(instance1, instance2);
928 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
929 EXPECT_EQ(url2, entry2->GetURL());
931 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
932 EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
934 // Navigate to third page on same site.
935 const GURL url3("http://news.google.com");
936 controller().LoadURL(
937 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
938 EXPECT_FALSE(contents()->cross_navigation_pending());
939 contents()->TestDidNavigate(
940 google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
941 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
942 SiteInstance* instance3 = contents()->GetSiteInstance();
944 EXPECT_FALSE(contents()->cross_navigation_pending());
945 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
946 EXPECT_EQ(instance2, instance3);
947 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
948 EXPECT_EQ(url3, entry3->GetURL());
950 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
952 // Go back within the site.
953 controller().GoBack();
954 EXPECT_FALSE(contents()->cross_navigation_pending());
955 EXPECT_EQ(entry2, controller().GetPendingEntry());
957 // Before that commits, go back again.
958 controller().GoBack();
959 EXPECT_TRUE(contents()->cross_navigation_pending());
960 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
961 EXPECT_EQ(entry1, controller().GetPendingEntry());
963 // Simulate beforeunload approval.
964 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
965 now = base::TimeTicks::Now();
966 google_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
968 // DidNavigate from the first back. This aborts the second back's pending RVH.
969 contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
971 // We should commit this page and forget about the second back.
972 EXPECT_FALSE(contents()->cross_navigation_pending());
973 EXPECT_FALSE(controller().GetPendingEntry());
974 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
975 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
977 // We should not have corrupted the NTP entry.
979 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
981 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
983 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
984 EXPECT_EQ(url1, entry1->GetURL());
987 // Test that during a slow cross-site navigation, a sub-frame navigation in the
988 // original renderer will not cancel the slow navigation (bug 42029).
989 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
990 contents()->transition_cross_site = true;
991 TestRenderViewHost* orig_rvh = test_rvh();
993 // Navigate to URL. First URL should use first RenderViewHost.
994 const GURL url("http://www.google.com");
995 controller().LoadURL(
996 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
997 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
998 EXPECT_FALSE(contents()->cross_navigation_pending());
999 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1001 // Start navigating to new site.
1002 const GURL url2("http://www.yahoo.com");
1003 controller().LoadURL(
1004 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1006 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1007 // waiting for a before unload response.
1008 orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
1009 PAGE_TRANSITION_AUTO_SUBFRAME);
1010 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1012 // Now simulate the onbeforeunload approval and verify the navigation is
1014 base::TimeTicks now = base::TimeTicks::Now();
1015 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1016 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1017 EXPECT_TRUE(contents()->cross_navigation_pending());
1020 // Test that a cross-site navigation is not preempted if the previous
1021 // renderer sends a FrameNavigate message just before being told to stop.
1022 // We should only preempt the cross-site navigation if the previous renderer
1023 // has started a new navigation. See http://crbug.com/79176.
1024 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1025 contents()->transition_cross_site = true;
1027 // Navigate to NTP URL.
1028 const GURL url("chrome://blah");
1029 controller().LoadURL(
1030 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1031 TestRenderViewHost* orig_rvh = test_rvh();
1032 EXPECT_FALSE(contents()->cross_navigation_pending());
1034 // Navigate to new site, with the beforeunload request in flight.
1035 const GURL url2("http://www.yahoo.com");
1036 controller().LoadURL(
1037 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1038 TestRenderViewHost* pending_rvh =
1039 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1040 EXPECT_TRUE(contents()->cross_navigation_pending());
1041 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1043 // Suppose the first navigation tries to commit now, with a
1044 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1045 // but it should act as if the beforeunload ack arrived.
1046 orig_rvh->SendNavigate(1, GURL("chrome://blah"));
1047 EXPECT_TRUE(contents()->cross_navigation_pending());
1048 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1049 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1051 // The pending navigation should be able to commit successfully.
1052 contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1053 EXPECT_FALSE(contents()->cross_navigation_pending());
1054 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
1057 // Test that the original renderer cannot preempt a cross-site navigation once
1058 // the unload request has been made. At this point, the cross-site navigation
1059 // is almost ready to be displayed, and the original renderer is only given a
1060 // short chance to run an unload handler. Prevents regression of bug 23942.
1061 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
1062 contents()->transition_cross_site = true;
1063 TestRenderViewHost* orig_rvh = test_rvh();
1064 SiteInstance* instance1 = contents()->GetSiteInstance();
1066 // Navigate to URL. First URL should use first RenderViewHost.
1067 const GURL url("http://www.google.com");
1068 controller().LoadURL(
1069 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1070 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1071 EXPECT_FALSE(contents()->cross_navigation_pending());
1072 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1074 // Navigate to new site, simulating an onbeforeunload approval.
1075 const GURL url2("http://www.yahoo.com");
1076 controller().LoadURL(
1077 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1078 base::TimeTicks now = base::TimeTicks::Now();
1079 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1080 EXPECT_TRUE(contents()->cross_navigation_pending());
1081 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
1082 contents()->GetPendingRenderViewHost());
1084 // Simulate the pending renderer's response, which leads to an unload request
1085 // being sent to orig_rvh.
1086 std::vector<GURL> url_chain;
1087 url_chain.push_back(GURL());
1088 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1089 pending_rvh, GlobalRequestID(0, 0), false, url_chain, Referrer(),
1090 PAGE_TRANSITION_TYPED, 1, false);
1092 // Suppose the original renderer navigates now, while the unload request is in
1093 // flight. We should ignore it, wait for the unload ack, and let the pending
1094 // request continue. Otherwise, the contents may close spontaneously or stop
1095 // responding to navigation requests. (See bug 23942.)
1096 ViewHostMsg_FrameNavigate_Params params1a;
1097 InitNavigateParams(¶ms1a, 2, GURL("http://www.google.com/foo"),
1098 PAGE_TRANSITION_TYPED);
1099 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1101 // Verify that the pending navigation is still in progress.
1102 EXPECT_TRUE(contents()->cross_navigation_pending());
1103 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
1105 // DidNavigate from the pending page should commit it.
1106 contents()->TestDidNavigate(
1107 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1108 SiteInstance* instance2 = contents()->GetSiteInstance();
1109 EXPECT_FALSE(contents()->cross_navigation_pending());
1110 EXPECT_EQ(pending_rvh, rvh());
1111 EXPECT_NE(instance1, instance2);
1112 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1115 // Test that a cross-site navigation that doesn't commit after the unload
1116 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1117 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1118 contents()->transition_cross_site = true;
1119 TestRenderViewHost* orig_rvh = test_rvh();
1120 SiteInstance* instance1 = contents()->GetSiteInstance();
1122 // Navigate to URL. First URL should use first RenderViewHost.
1123 const GURL url("http://www.google.com");
1124 controller().LoadURL(
1125 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1126 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1127 EXPECT_FALSE(contents()->cross_navigation_pending());
1128 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1130 // Navigate to new site, simulating an onbeforeunload approval.
1131 const GURL url2("http://www.yahoo.com");
1132 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1133 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1134 base::TimeTicks now = base::TimeTicks::Now();
1135 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1136 EXPECT_TRUE(contents()->cross_navigation_pending());
1138 // Simulate swap out message when the response arrives.
1139 orig_rvh->set_is_swapped_out(true);
1141 // Suppose the navigation doesn't get a chance to commit, and the user
1142 // navigates in the current RVH's SiteInstance.
1143 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1145 // Verify that the pending navigation is cancelled and the renderer is no
1146 // longer swapped out.
1147 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1148 SiteInstance* instance2 = contents()->GetSiteInstance();
1149 EXPECT_FALSE(contents()->cross_navigation_pending());
1150 EXPECT_EQ(orig_rvh, rvh());
1151 EXPECT_FALSE(orig_rvh->is_swapped_out());
1152 EXPECT_EQ(instance1, instance2);
1153 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1156 // Test that NavigationEntries have the correct page state after going
1157 // forward and back. Prevents regression for bug 1116137.
1158 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1159 TestRenderViewHost* orig_rvh = test_rvh();
1161 // Navigate to URL. There should be no committed entry yet.
1162 const GURL url("http://www.google.com");
1163 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1164 NavigationEntry* entry = controller().GetLastCommittedEntry();
1165 EXPECT_TRUE(entry == NULL);
1167 // Committed entry should have page state after DidNavigate.
1168 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1169 entry = controller().GetLastCommittedEntry();
1170 EXPECT_TRUE(entry->GetPageState().IsValid());
1172 // Navigate to same site.
1173 const GURL url2("http://images.google.com");
1174 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1175 entry = controller().GetLastCommittedEntry();
1176 EXPECT_TRUE(entry->GetPageState().IsValid());
1178 // Committed entry should have page state after DidNavigate.
1179 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1180 entry = controller().GetLastCommittedEntry();
1181 EXPECT_TRUE(entry->GetPageState().IsValid());
1183 // Now go back. Committed entry should still have page state.
1184 controller().GoBack();
1185 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1186 entry = controller().GetLastCommittedEntry();
1187 EXPECT_TRUE(entry->GetPageState().IsValid());
1190 // Test that NavigationEntries have the correct page state and SiteInstance
1191 // state after opening a new window to about:blank. Prevents regression for
1192 // bugs b/1116137 and http://crbug.com/111975.
1193 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1194 TestRenderViewHost* orig_rvh = test_rvh();
1196 // When opening a new window, it is navigated to about:blank internally.
1197 // Currently, this results in two DidNavigate events.
1198 const GURL url(kAboutBlankURL);
1199 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1200 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1202 // Should have a page state here.
1203 NavigationEntry* entry = controller().GetLastCommittedEntry();
1204 EXPECT_TRUE(entry->GetPageState().IsValid());
1206 // The SiteInstance should be available for other navigations to use.
1207 NavigationEntryImpl* entry_impl =
1208 NavigationEntryImpl::FromNavigationEntry(entry);
1209 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1210 int32 site_instance_id = entry_impl->site_instance()->GetId();
1212 // Navigating to a normal page should not cause a process swap.
1213 const GURL new_url("http://www.google.com");
1214 controller().LoadURL(new_url, Referrer(),
1215 PAGE_TRANSITION_TYPED, std::string());
1216 EXPECT_FALSE(contents()->cross_navigation_pending());
1217 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1218 contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1219 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1220 controller().GetLastCommittedEntry());
1221 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1222 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1225 ////////////////////////////////////////////////////////////////////////////////
1226 // Interstitial Tests
1227 ////////////////////////////////////////////////////////////////////////////////
1229 // Test navigating to a page (with the navigation initiated from the browser,
1230 // as when a URL is typed in the location bar) that shows an interstitial and
1231 // creates a new navigation entry, then hiding it without proceeding.
1232 TEST_F(WebContentsImplTest,
1233 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1234 // Navigate to a page.
1235 GURL url1("http://www.google.com");
1236 test_rvh()->SendNavigate(1, url1);
1237 EXPECT_EQ(1, controller().GetEntryCount());
1239 // Initiate a browser navigation that will trigger the interstitial
1240 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1241 PAGE_TRANSITION_TYPED, std::string());
1243 // Show an interstitial.
1244 TestInterstitialPage::InterstitialState state =
1245 TestInterstitialPage::INVALID;
1246 bool deleted = false;
1247 GURL url2("http://interstitial");
1248 TestInterstitialPage* interstitial =
1249 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1250 TestInterstitialPageStateGuard state_guard(interstitial);
1251 interstitial->Show();
1252 // The interstitial should not show until its navigation has committed.
1253 EXPECT_FALSE(interstitial->is_showing());
1254 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1255 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1256 // Let's commit the interstitial navigation.
1257 interstitial->TestDidNavigate(1, url2);
1258 EXPECT_TRUE(interstitial->is_showing());
1259 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1260 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1261 NavigationEntry* entry = controller().GetVisibleEntry();
1262 ASSERT_TRUE(entry != NULL);
1263 EXPECT_TRUE(entry->GetURL() == url2);
1265 // Now don't proceed.
1266 interstitial->DontProceed();
1267 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1268 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1269 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1270 entry = controller().GetVisibleEntry();
1271 ASSERT_TRUE(entry != NULL);
1272 EXPECT_TRUE(entry->GetURL() == url1);
1273 EXPECT_EQ(1, controller().GetEntryCount());
1275 RunAllPendingInMessageLoop();
1276 EXPECT_TRUE(deleted);
1279 // Test navigating to a page (with the navigation initiated from the renderer,
1280 // as when clicking on a link in the page) that shows an interstitial and
1281 // creates a new navigation entry, then hiding it without proceeding.
1282 TEST_F(WebContentsImplTest,
1283 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1284 // Navigate to a page.
1285 GURL url1("http://www.google.com");
1286 test_rvh()->SendNavigate(1, url1);
1287 EXPECT_EQ(1, controller().GetEntryCount());
1289 // Show an interstitial (no pending entry, the interstitial would have been
1290 // triggered by clicking on a link).
1291 TestInterstitialPage::InterstitialState state =
1292 TestInterstitialPage::INVALID;
1293 bool deleted = false;
1294 GURL url2("http://interstitial");
1295 TestInterstitialPage* interstitial =
1296 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1297 TestInterstitialPageStateGuard state_guard(interstitial);
1298 interstitial->Show();
1299 // The interstitial should not show until its navigation has committed.
1300 EXPECT_FALSE(interstitial->is_showing());
1301 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1302 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1303 // Let's commit the interstitial navigation.
1304 interstitial->TestDidNavigate(1, url2);
1305 EXPECT_TRUE(interstitial->is_showing());
1306 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1307 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1308 NavigationEntry* entry = controller().GetVisibleEntry();
1309 ASSERT_TRUE(entry != NULL);
1310 EXPECT_TRUE(entry->GetURL() == url2);
1312 // Now don't proceed.
1313 interstitial->DontProceed();
1314 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1315 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1316 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1317 entry = controller().GetVisibleEntry();
1318 ASSERT_TRUE(entry != NULL);
1319 EXPECT_TRUE(entry->GetURL() == url1);
1320 EXPECT_EQ(1, controller().GetEntryCount());
1322 RunAllPendingInMessageLoop();
1323 EXPECT_TRUE(deleted);
1326 // Test navigating to a page that shows an interstitial without creating a new
1327 // navigation entry (this happens when the interstitial is triggered by a
1328 // sub-resource in the page), then hiding it without proceeding.
1329 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1330 // Navigate to a page.
1331 GURL url1("http://www.google.com");
1332 test_rvh()->SendNavigate(1, url1);
1333 EXPECT_EQ(1, controller().GetEntryCount());
1335 // Show an interstitial.
1336 TestInterstitialPage::InterstitialState state =
1337 TestInterstitialPage::INVALID;
1338 bool deleted = false;
1339 GURL url2("http://interstitial");
1340 TestInterstitialPage* interstitial =
1341 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1342 TestInterstitialPageStateGuard state_guard(interstitial);
1343 interstitial->Show();
1344 // The interstitial should not show until its navigation has committed.
1345 EXPECT_FALSE(interstitial->is_showing());
1346 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1347 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1348 // Let's commit the interstitial navigation.
1349 interstitial->TestDidNavigate(1, url2);
1350 EXPECT_TRUE(interstitial->is_showing());
1351 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1352 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1353 NavigationEntry* entry = controller().GetVisibleEntry();
1354 ASSERT_TRUE(entry != NULL);
1355 // The URL specified to the interstitial should have been ignored.
1356 EXPECT_TRUE(entry->GetURL() == url1);
1358 // Now don't proceed.
1359 interstitial->DontProceed();
1360 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1361 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1362 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1363 entry = controller().GetVisibleEntry();
1364 ASSERT_TRUE(entry != NULL);
1365 EXPECT_TRUE(entry->GetURL() == url1);
1366 EXPECT_EQ(1, controller().GetEntryCount());
1368 RunAllPendingInMessageLoop();
1369 EXPECT_TRUE(deleted);
1372 // Test navigating to a page (with the navigation initiated from the browser,
1373 // as when a URL is typed in the location bar) that shows an interstitial and
1374 // creates a new navigation entry, then proceeding.
1375 TEST_F(WebContentsImplTest,
1376 ShowInterstitialFromBrowserNewNavigationProceed) {
1377 // Navigate to a page.
1378 GURL url1("http://www.google.com");
1379 test_rvh()->SendNavigate(1, url1);
1380 EXPECT_EQ(1, controller().GetEntryCount());
1382 // Initiate a browser navigation that will trigger the interstitial
1383 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1384 PAGE_TRANSITION_TYPED, std::string());
1386 // Show an interstitial.
1387 TestInterstitialPage::InterstitialState state =
1388 TestInterstitialPage::INVALID;
1389 bool deleted = false;
1390 GURL url2("http://interstitial");
1391 TestInterstitialPage* interstitial =
1392 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1393 TestInterstitialPageStateGuard state_guard(interstitial);
1394 interstitial->Show();
1395 // The interstitial should not show until its navigation has committed.
1396 EXPECT_FALSE(interstitial->is_showing());
1397 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1398 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1399 // Let's commit the interstitial navigation.
1400 interstitial->TestDidNavigate(1, url2);
1401 EXPECT_TRUE(interstitial->is_showing());
1402 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1403 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1404 NavigationEntry* entry = controller().GetVisibleEntry();
1405 ASSERT_TRUE(entry != NULL);
1406 EXPECT_TRUE(entry->GetURL() == url2);
1409 interstitial->Proceed();
1410 // The interstitial should show until the new navigation commits.
1411 RunAllPendingInMessageLoop();
1412 ASSERT_FALSE(deleted);
1413 EXPECT_EQ(TestInterstitialPage::OKED, state);
1414 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1415 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1417 // Simulate the navigation to the page, that's when the interstitial gets
1419 GURL url3("http://www.thepage.com");
1420 test_rvh()->SendNavigate(2, url3);
1422 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1423 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1424 entry = controller().GetVisibleEntry();
1425 ASSERT_TRUE(entry != NULL);
1426 EXPECT_TRUE(entry->GetURL() == url3);
1428 EXPECT_EQ(2, controller().GetEntryCount());
1430 RunAllPendingInMessageLoop();
1431 EXPECT_TRUE(deleted);
1434 // Test navigating to a page (with the navigation initiated from the renderer,
1435 // as when clicking on a link in the page) that shows an interstitial and
1436 // creates a new navigation entry, then proceeding.
1437 TEST_F(WebContentsImplTest,
1438 ShowInterstitialFromRendererNewNavigationProceed) {
1439 // Navigate to a page.
1440 GURL url1("http://www.google.com");
1441 test_rvh()->SendNavigate(1, url1);
1442 EXPECT_EQ(1, controller().GetEntryCount());
1444 // Show an interstitial.
1445 TestInterstitialPage::InterstitialState state =
1446 TestInterstitialPage::INVALID;
1447 bool deleted = false;
1448 GURL url2("http://interstitial");
1449 TestInterstitialPage* interstitial =
1450 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1451 TestInterstitialPageStateGuard state_guard(interstitial);
1452 interstitial->Show();
1453 // The interstitial should not show until its navigation has committed.
1454 EXPECT_FALSE(interstitial->is_showing());
1455 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1456 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1457 // Let's commit the interstitial navigation.
1458 interstitial->TestDidNavigate(1, url2);
1459 EXPECT_TRUE(interstitial->is_showing());
1460 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1461 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1462 NavigationEntry* entry = controller().GetVisibleEntry();
1463 ASSERT_TRUE(entry != NULL);
1464 EXPECT_TRUE(entry->GetURL() == url2);
1467 interstitial->Proceed();
1468 // The interstitial should show until the new navigation commits.
1469 RunAllPendingInMessageLoop();
1470 ASSERT_FALSE(deleted);
1471 EXPECT_EQ(TestInterstitialPage::OKED, state);
1472 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1473 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1475 // Simulate the navigation to the page, that's when the interstitial gets
1477 GURL url3("http://www.thepage.com");
1478 test_rvh()->SendNavigate(2, url3);
1480 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1481 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1482 entry = controller().GetVisibleEntry();
1483 ASSERT_TRUE(entry != NULL);
1484 EXPECT_TRUE(entry->GetURL() == url3);
1486 EXPECT_EQ(2, controller().GetEntryCount());
1488 RunAllPendingInMessageLoop();
1489 EXPECT_TRUE(deleted);
1492 // Test navigating to a page that shows an interstitial without creating a new
1493 // navigation entry (this happens when the interstitial is triggered by a
1494 // sub-resource in the page), then proceeding.
1495 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1496 // Navigate to a page so we have a navigation entry in the controller.
1497 GURL url1("http://www.google.com");
1498 test_rvh()->SendNavigate(1, url1);
1499 EXPECT_EQ(1, controller().GetEntryCount());
1501 // Show an interstitial.
1502 TestInterstitialPage::InterstitialState state =
1503 TestInterstitialPage::INVALID;
1504 bool deleted = false;
1505 GURL url2("http://interstitial");
1506 TestInterstitialPage* interstitial =
1507 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1508 TestInterstitialPageStateGuard state_guard(interstitial);
1509 interstitial->Show();
1510 // The interstitial should not show until its navigation has committed.
1511 EXPECT_FALSE(interstitial->is_showing());
1512 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1513 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1514 // Let's commit the interstitial navigation.
1515 interstitial->TestDidNavigate(1, url2);
1516 EXPECT_TRUE(interstitial->is_showing());
1517 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1518 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1519 NavigationEntry* entry = controller().GetVisibleEntry();
1520 ASSERT_TRUE(entry != NULL);
1521 // The URL specified to the interstitial should have been ignored.
1522 EXPECT_TRUE(entry->GetURL() == url1);
1525 interstitial->Proceed();
1526 // Since this is not a new navigation, the previous page is dismissed right
1527 // away and shows the original page.
1528 EXPECT_EQ(TestInterstitialPage::OKED, state);
1529 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1530 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1531 entry = controller().GetVisibleEntry();
1532 ASSERT_TRUE(entry != NULL);
1533 EXPECT_TRUE(entry->GetURL() == url1);
1535 EXPECT_EQ(1, controller().GetEntryCount());
1537 RunAllPendingInMessageLoop();
1538 EXPECT_TRUE(deleted);
1541 // Test navigating to a page that shows an interstitial, then navigating away.
1542 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1543 // Show interstitial.
1544 TestInterstitialPage::InterstitialState state =
1545 TestInterstitialPage::INVALID;
1546 bool deleted = false;
1547 GURL url("http://interstitial");
1548 TestInterstitialPage* interstitial =
1549 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1550 TestInterstitialPageStateGuard state_guard(interstitial);
1551 interstitial->Show();
1552 interstitial->TestDidNavigate(1, url);
1554 // While interstitial showing, navigate to a new URL.
1555 const GURL url2("http://www.yahoo.com");
1556 test_rvh()->SendNavigate(1, url2);
1558 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1560 RunAllPendingInMessageLoop();
1561 EXPECT_TRUE(deleted);
1564 // Test navigating to a page that shows an interstitial, then going back.
1565 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1566 // Navigate to a page so we have a navigation entry in the controller.
1567 GURL url1("http://www.google.com");
1568 test_rvh()->SendNavigate(1, url1);
1569 EXPECT_EQ(1, controller().GetEntryCount());
1571 // Show interstitial.
1572 TestInterstitialPage::InterstitialState state =
1573 TestInterstitialPage::INVALID;
1574 bool deleted = false;
1575 GURL interstitial_url("http://interstitial");
1576 TestInterstitialPage* interstitial =
1577 new TestInterstitialPage(contents(), true, interstitial_url,
1579 TestInterstitialPageStateGuard state_guard(interstitial);
1580 interstitial->Show();
1581 interstitial->TestDidNavigate(2, interstitial_url);
1583 // While the interstitial is showing, go back.
1584 controller().GoBack();
1585 test_rvh()->SendNavigate(1, url1);
1587 // Make sure we are back to the original page and that the interstitial is
1589 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1590 NavigationEntry* entry = controller().GetVisibleEntry();
1592 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1594 RunAllPendingInMessageLoop();
1595 EXPECT_TRUE(deleted);
1598 // Test navigating to a page that shows an interstitial, has a renderer crash,
1599 // and then goes back.
1600 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1601 // Navigate to a page so we have a navigation entry in the controller.
1602 GURL url1("http://www.google.com");
1603 test_rvh()->SendNavigate(1, url1);
1604 EXPECT_EQ(1, controller().GetEntryCount());
1606 // Show interstitial.
1607 TestInterstitialPage::InterstitialState state =
1608 TestInterstitialPage::INVALID;
1609 bool deleted = false;
1610 GURL interstitial_url("http://interstitial");
1611 TestInterstitialPage* interstitial =
1612 new TestInterstitialPage(contents(), true, interstitial_url,
1614 TestInterstitialPageStateGuard state_guard(interstitial);
1615 interstitial->Show();
1616 interstitial->TestDidNavigate(2, interstitial_url);
1618 // Crash the renderer
1619 test_rvh()->OnMessageReceived(
1620 ViewHostMsg_RenderProcessGone(
1621 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1623 // While the interstitial is showing, go back.
1624 controller().GoBack();
1625 test_rvh()->SendNavigate(1, url1);
1627 // Make sure we are back to the original page and that the interstitial is
1629 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1630 NavigationEntry* entry = controller().GetVisibleEntry();
1632 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1634 RunAllPendingInMessageLoop();
1635 EXPECT_TRUE(deleted);
1638 // Test navigating to a page that shows an interstitial, has the renderer crash,
1639 // and then navigates to the interstitial.
1640 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1641 // Navigate to a page so we have a navigation entry in the controller.
1642 GURL url1("http://www.google.com");
1643 test_rvh()->SendNavigate(1, url1);
1644 EXPECT_EQ(1, controller().GetEntryCount());
1646 // Show interstitial.
1647 TestInterstitialPage::InterstitialState state =
1648 TestInterstitialPage::INVALID;
1649 bool deleted = false;
1650 GURL interstitial_url("http://interstitial");
1651 TestInterstitialPage* interstitial =
1652 new TestInterstitialPage(contents(), true, interstitial_url,
1654 TestInterstitialPageStateGuard state_guard(interstitial);
1655 interstitial->Show();
1657 // Crash the renderer
1658 test_rvh()->OnMessageReceived(
1659 ViewHostMsg_RenderProcessGone(
1660 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1662 interstitial->TestDidNavigate(2, interstitial_url);
1665 // Test navigating to a page that shows an interstitial, then close the
1667 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
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);
1679 // Now close the contents.
1681 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1683 RunAllPendingInMessageLoop();
1684 EXPECT_TRUE(deleted);
1687 // Test navigating to a page that shows an interstitial, then close the
1689 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1690 // Show interstitial.
1691 TestInterstitialPage::InterstitialState state =
1692 TestInterstitialPage::INVALID;
1693 bool deleted = false;
1694 GURL url("http://interstitial");
1695 TestInterstitialPage* interstitial =
1696 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1697 TestInterstitialPageStateGuard state_guard(interstitial);
1698 interstitial->Show();
1699 interstitial->TestDidNavigate(1, url);
1700 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1701 interstitial->GetRenderViewHostForTesting());
1703 // Now close the contents.
1705 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1707 // Before the interstitial has a chance to process its shutdown task,
1708 // simulate quitting the browser. This goes through all processes and
1709 // tells them to destruct.
1710 rvh->OnMessageReceived(
1711 ViewHostMsg_RenderProcessGone(0, 0, 0));
1713 RunAllPendingInMessageLoop();
1714 EXPECT_TRUE(deleted);
1717 // Test that after Proceed is called and an interstitial is still shown, no more
1718 // commands get executed.
1719 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1720 // Navigate to a page so we have a navigation entry in the controller.
1721 GURL url1("http://www.google.com");
1722 test_rvh()->SendNavigate(1, url1);
1723 EXPECT_EQ(1, controller().GetEntryCount());
1725 // Show an interstitial.
1726 TestInterstitialPage::InterstitialState state =
1727 TestInterstitialPage::INVALID;
1728 bool deleted = false;
1729 GURL url2("http://interstitial");
1730 TestInterstitialPage* interstitial =
1731 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1732 TestInterstitialPageStateGuard state_guard(interstitial);
1733 interstitial->Show();
1734 interstitial->TestDidNavigate(1, url2);
1737 EXPECT_EQ(0, interstitial->command_received_count());
1738 interstitial->TestDomOperationResponse("toto");
1739 EXPECT_EQ(1, interstitial->command_received_count());
1742 interstitial->Proceed();
1743 RunAllPendingInMessageLoop();
1744 ASSERT_FALSE(deleted);
1746 // While the navigation to the new page is pending, send other commands, they
1747 // should be ignored.
1748 interstitial->TestDomOperationResponse("hello");
1749 interstitial->TestDomOperationResponse("hi");
1750 EXPECT_EQ(1, interstitial->command_received_count());
1753 // Test showing an interstitial while another interstitial is already showing.
1754 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1755 // Navigate to a page so we have a navigation entry in the controller.
1756 GURL start_url("http://www.google.com");
1757 test_rvh()->SendNavigate(1, start_url);
1758 EXPECT_EQ(1, controller().GetEntryCount());
1760 // Show an interstitial.
1761 TestInterstitialPage::InterstitialState state1 =
1762 TestInterstitialPage::INVALID;
1763 bool deleted1 = false;
1764 GURL url1("http://interstitial1");
1765 TestInterstitialPage* interstitial1 =
1766 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1767 TestInterstitialPageStateGuard state_guard1(interstitial1);
1768 interstitial1->Show();
1769 interstitial1->TestDidNavigate(1, url1);
1771 // Now show another interstitial.
1772 TestInterstitialPage::InterstitialState state2 =
1773 TestInterstitialPage::INVALID;
1774 bool deleted2 = false;
1775 GURL url2("http://interstitial2");
1776 TestInterstitialPage* interstitial2 =
1777 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1778 TestInterstitialPageStateGuard state_guard2(interstitial2);
1779 interstitial2->Show();
1780 interstitial2->TestDidNavigate(1, url2);
1782 // Showing interstitial2 should have caused interstitial1 to go away.
1783 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1784 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1786 RunAllPendingInMessageLoop();
1787 EXPECT_TRUE(deleted1);
1788 ASSERT_FALSE(deleted2);
1790 // Let's make sure interstitial2 is working as intended.
1791 interstitial2->Proceed();
1792 GURL landing_url("http://www.thepage.com");
1793 test_rvh()->SendNavigate(2, landing_url);
1795 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1796 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1797 NavigationEntry* entry = controller().GetVisibleEntry();
1798 ASSERT_TRUE(entry != NULL);
1799 EXPECT_TRUE(entry->GetURL() == landing_url);
1800 EXPECT_EQ(2, controller().GetEntryCount());
1801 RunAllPendingInMessageLoop();
1802 EXPECT_TRUE(deleted2);
1805 // Test showing an interstitial, proceeding and then navigating to another
1807 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
1808 // Navigate to a page so we have a navigation entry in the controller.
1809 GURL start_url("http://www.google.com");
1810 test_rvh()->SendNavigate(1, start_url);
1811 EXPECT_EQ(1, controller().GetEntryCount());
1813 // Show an interstitial.
1814 TestInterstitialPage::InterstitialState state1 =
1815 TestInterstitialPage::INVALID;
1816 bool deleted1 = false;
1817 GURL url1("http://interstitial1");
1818 TestInterstitialPage* interstitial1 =
1819 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1820 TestInterstitialPageStateGuard state_guard1(interstitial1);
1821 interstitial1->Show();
1822 interstitial1->TestDidNavigate(1, url1);
1824 // Take action. The interstitial won't be hidden until the navigation is
1826 interstitial1->Proceed();
1827 EXPECT_EQ(TestInterstitialPage::OKED, state1);
1829 // Now show another interstitial (simulating the navigation causing another
1831 TestInterstitialPage::InterstitialState state2 =
1832 TestInterstitialPage::INVALID;
1833 bool deleted2 = false;
1834 GURL url2("http://interstitial2");
1835 TestInterstitialPage* interstitial2 =
1836 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1837 TestInterstitialPageStateGuard state_guard2(interstitial2);
1838 interstitial2->Show();
1839 interstitial2->TestDidNavigate(1, url2);
1841 // Showing interstitial2 should have caused interstitial1 to go away.
1842 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1843 RunAllPendingInMessageLoop();
1844 EXPECT_TRUE(deleted1);
1845 ASSERT_FALSE(deleted2);
1847 // Let's make sure interstitial2 is working as intended.
1848 interstitial2->Proceed();
1849 GURL landing_url("http://www.thepage.com");
1850 test_rvh()->SendNavigate(2, landing_url);
1852 RunAllPendingInMessageLoop();
1853 EXPECT_TRUE(deleted2);
1854 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1855 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1856 NavigationEntry* entry = controller().GetVisibleEntry();
1857 ASSERT_TRUE(entry != NULL);
1858 EXPECT_TRUE(entry->GetURL() == landing_url);
1859 EXPECT_EQ(2, controller().GetEntryCount());
1862 // Test that navigating away from an interstitial while it's loading cause it
1864 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
1865 // Show an interstitial.
1866 TestInterstitialPage::InterstitialState state =
1867 TestInterstitialPage::INVALID;
1868 bool deleted = false;
1869 GURL interstitial_url("http://interstitial");
1870 TestInterstitialPage* interstitial =
1871 new TestInterstitialPage(contents(), true, interstitial_url,
1873 TestInterstitialPageStateGuard state_guard(interstitial);
1874 interstitial->Show();
1876 // Let's simulate a navigation initiated from the browser before the
1877 // interstitial finishes loading.
1878 const GURL url("http://www.google.com");
1879 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1880 EXPECT_FALSE(interstitial->is_showing());
1881 RunAllPendingInMessageLoop();
1882 ASSERT_FALSE(deleted);
1884 // Now let's make the interstitial navigation commit.
1885 interstitial->TestDidNavigate(1, interstitial_url);
1887 // After it loaded the interstitial should be gone.
1888 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1890 RunAllPendingInMessageLoop();
1891 EXPECT_TRUE(deleted);
1894 // Test that a new request to show an interstitial while an interstitial is
1895 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
1896 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
1897 GURL interstitial_url("http://interstitial");
1899 // Show a first interstitial.
1900 TestInterstitialPage::InterstitialState state1 =
1901 TestInterstitialPage::INVALID;
1902 bool deleted1 = false;
1903 TestInterstitialPage* interstitial1 =
1904 new TestInterstitialPage(contents(), true, interstitial_url,
1905 &state1, &deleted1);
1906 TestInterstitialPageStateGuard state_guard1(interstitial1);
1907 interstitial1->Show();
1909 // Show another interstitial on that same contents before the first one had
1911 TestInterstitialPage::InterstitialState state2 =
1912 TestInterstitialPage::INVALID;
1913 bool deleted2 = false;
1914 TestInterstitialPage* interstitial2 =
1915 new TestInterstitialPage(contents(), true, interstitial_url,
1916 &state2, &deleted2);
1917 TestInterstitialPageStateGuard state_guard2(interstitial2);
1918 interstitial2->Show();
1920 // The first interstitial should have been closed and deleted.
1921 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1922 // The 2nd one should still be OK.
1923 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1925 RunAllPendingInMessageLoop();
1926 EXPECT_TRUE(deleted1);
1927 ASSERT_FALSE(deleted2);
1929 // Make the interstitial navigation commit it should be showing.
1930 interstitial2->TestDidNavigate(1, interstitial_url);
1931 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
1934 // Test showing an interstitial and have its renderer crash.
1935 TEST_F(WebContentsImplTest, InterstitialCrasher) {
1936 // Show an interstitial.
1937 TestInterstitialPage::InterstitialState state =
1938 TestInterstitialPage::INVALID;
1939 bool deleted = false;
1940 GURL url("http://interstitial");
1941 TestInterstitialPage* interstitial =
1942 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1943 TestInterstitialPageStateGuard state_guard(interstitial);
1944 interstitial->Show();
1945 // Simulate a renderer crash before the interstitial is shown.
1946 interstitial->TestRenderViewTerminated(
1947 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1948 // The interstitial should have been dismissed.
1949 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1950 RunAllPendingInMessageLoop();
1951 EXPECT_TRUE(deleted);
1953 // Now try again but this time crash the intersitial after it was shown.
1955 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1956 interstitial->Show();
1957 interstitial->TestDidNavigate(1, url);
1958 // Simulate a renderer crash.
1959 interstitial->TestRenderViewTerminated(
1960 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1961 // The interstitial should have been dismissed.
1962 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1963 RunAllPendingInMessageLoop();
1964 EXPECT_TRUE(deleted);
1967 // Tests that showing an interstitial as a result of a browser initiated
1968 // navigation while an interstitial is showing does not remove the pending
1969 // entry (see http://crbug.com/9791).
1970 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
1971 const char kUrl[] = "http://www.badguys.com/";
1972 const GURL kGURL(kUrl);
1974 // Start a navigation to a page
1975 contents()->GetController().LoadURL(
1976 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1978 // Simulate that navigation triggering an interstitial.
1979 TestInterstitialPage::InterstitialState state =
1980 TestInterstitialPage::INVALID;
1981 bool deleted = false;
1982 TestInterstitialPage* interstitial =
1983 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
1984 TestInterstitialPageStateGuard state_guard(interstitial);
1985 interstitial->Show();
1986 interstitial->TestDidNavigate(1, kGURL);
1988 // Initiate a new navigation from the browser that also triggers an
1990 contents()->GetController().LoadURL(
1991 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1992 TestInterstitialPage::InterstitialState state2 =
1993 TestInterstitialPage::INVALID;
1994 bool deleted2 = false;
1995 TestInterstitialPage* interstitial2 =
1996 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
1997 TestInterstitialPageStateGuard state_guard2(interstitial2);
1998 interstitial2->Show();
1999 interstitial2->TestDidNavigate(1, kGURL);
2001 // Make sure we still have an entry.
2002 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2004 EXPECT_EQ(kUrl, entry->GetURL().spec());
2006 // And that the first interstitial is gone, but not the second.
2007 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2008 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2009 RunAllPendingInMessageLoop();
2010 EXPECT_TRUE(deleted);
2011 EXPECT_FALSE(deleted2);
2014 // Tests that Javascript messages are not shown while an interstitial is
2016 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2017 const char kUrl[] = "http://www.badguys.com/";
2018 const GURL kGURL(kUrl);
2020 // Start a navigation to a page
2021 contents()->GetController().LoadURL(
2022 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2023 // DidNavigate from the page
2024 contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
2026 // Simulate showing an interstitial while the page is showing.
2027 TestInterstitialPage::InterstitialState state =
2028 TestInterstitialPage::INVALID;
2029 bool deleted = false;
2030 TestInterstitialPage* interstitial =
2031 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2032 TestInterstitialPageStateGuard state_guard(interstitial);
2033 interstitial->Show();
2034 interstitial->TestDidNavigate(1, kGURL);
2036 // While the interstitial is showing, let's simulate the hidden page
2037 // attempting to show a JS message.
2038 IPC::Message* dummy_message = new IPC::Message;
2039 bool did_suppress_message = false;
2040 contents()->RunJavaScriptMessage(contents()->GetRenderViewHost(),
2041 base::ASCIIToUTF16("This is an informative message"),
2042 base::ASCIIToUTF16("OK"),
2043 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message,
2044 &did_suppress_message);
2045 EXPECT_TRUE(did_suppress_message);
2048 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2049 // interstitial it isn't copied over to the destination.
2050 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2051 // Navigate to a page.
2052 GURL url1("http://www.google.com");
2053 test_rvh()->SendNavigate(1, url1);
2054 EXPECT_EQ(1, controller().GetEntryCount());
2056 // Initiate a browser navigation that will trigger the interstitial
2057 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2058 PAGE_TRANSITION_TYPED, std::string());
2060 // Show an interstitial.
2061 TestInterstitialPage::InterstitialState state =
2062 TestInterstitialPage::INVALID;
2063 bool deleted = false;
2064 GURL url2("http://interstitial");
2065 TestInterstitialPage* interstitial =
2066 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2067 TestInterstitialPageStateGuard state_guard(interstitial);
2068 interstitial->Show();
2069 interstitial->TestDidNavigate(1, url2);
2070 EXPECT_TRUE(interstitial->is_showing());
2071 EXPECT_EQ(2, controller().GetEntryCount());
2073 // Create another NavigationController.
2074 GURL url3("http://foo2");
2075 scoped_ptr<TestWebContents> other_contents(
2076 static_cast<TestWebContents*>(CreateTestWebContents()));
2077 NavigationControllerImpl& other_controller = other_contents->GetController();
2078 other_contents->NavigateAndCommit(url3);
2079 other_contents->ExpectSetHistoryLengthAndPrune(
2080 NavigationEntryImpl::FromNavigationEntry(
2081 other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2082 other_controller.GetEntryAtIndex(0)->GetPageID());
2083 other_controller.CopyStateFromAndPrune(&controller(), false);
2085 // The merged controller should only have two entries: url1 and url2.
2086 ASSERT_EQ(2, other_controller.GetEntryCount());
2087 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2088 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2089 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2091 // And the merged controller shouldn't be showing an interstitial.
2092 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2095 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2096 // showing an interstitial.
2097 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2098 // Navigate to a page.
2099 GURL url1("http://www.google.com");
2100 contents()->NavigateAndCommit(url1);
2102 // Create another NavigationController.
2103 scoped_ptr<TestWebContents> other_contents(
2104 static_cast<TestWebContents*>(CreateTestWebContents()));
2105 NavigationControllerImpl& other_controller = other_contents->GetController();
2107 // Navigate it to url2.
2108 GURL url2("http://foo2");
2109 other_contents->NavigateAndCommit(url2);
2111 // Show an interstitial.
2112 TestInterstitialPage::InterstitialState state =
2113 TestInterstitialPage::INVALID;
2114 bool deleted = false;
2115 GURL url3("http://interstitial");
2116 TestInterstitialPage* interstitial =
2117 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2119 TestInterstitialPageStateGuard state_guard(interstitial);
2120 interstitial->Show();
2121 interstitial->TestDidNavigate(1, url3);
2122 EXPECT_TRUE(interstitial->is_showing());
2123 EXPECT_EQ(2, other_controller.GetEntryCount());
2125 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2126 // interstitial is showing in the target.
2127 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2130 // Regression test for http://crbug.com/168611 - the URLs passed by the
2131 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2132 TEST_F(WebContentsImplTest, FilterURLs) {
2133 TestWebContentsObserver observer(contents());
2135 // A navigation to about:whatever should always look like a navigation to
2137 GURL url_normalized(kAboutBlankURL);
2138 GURL url_from_ipc("about:whatever");
2140 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2141 // will use the given URL to create the NavigationEntry as well, and that
2142 // entry should contain the filtered URL.
2143 contents()->NavigateAndCommit(url_normalized);
2145 // Check that an IPC with about:whatever is correctly normalized.
2146 contents()->TestDidFinishLoad(1, url_from_ipc, true);
2148 EXPECT_EQ(url_normalized, observer.last_url());
2150 // Create and navigate another WebContents.
2151 scoped_ptr<TestWebContents> other_contents(
2152 static_cast<TestWebContents*>(CreateTestWebContents()));
2153 TestWebContentsObserver other_observer(other_contents.get());
2154 other_contents->NavigateAndCommit(url_normalized);
2156 // Check that an IPC with about:whatever is correctly normalized.
2157 other_contents->TestDidFailLoadWithError(
2158 1, url_from_ipc, true, 1, base::string16());
2159 EXPECT_EQ(url_normalized, other_observer.last_url());
2162 // Test that if a pending contents is deleted before it is shown, we don't
2164 TEST_F(WebContentsImplTest, PendingContents) {
2165 scoped_ptr<TestWebContents> other_contents(
2166 static_cast<TestWebContents*>(CreateTestWebContents()));
2167 contents()->AddPendingContents(other_contents.get());
2168 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2169 other_contents.reset();
2170 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2173 } // namespace content