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/cross_site_transferring_request.h"
10 #include "content/browser/renderer_host/render_view_host_impl.h"
11 #include "content/browser/site_instance_impl.h"
12 #include "content/browser/webui/web_ui_controller_factory_registry.h"
13 #include "content/common/frame_messages.h"
14 #include "content/common/view_messages.h"
15 #include "content/public/browser/global_request_id.h"
16 #include "content/public/browser/interstitial_page_delegate.h"
17 #include "content/public/browser/navigation_details.h"
18 #include "content/public/browser/notification_details.h"
19 #include "content/public/browser/notification_source.h"
20 #include "content/public/browser/render_widget_host_view.h"
21 #include "content/public/browser/web_contents_observer.h"
22 #include "content/public/browser/web_ui_controller.h"
23 #include "content/public/common/bindings_policy.h"
24 #include "content/public/common/content_constants.h"
25 #include "content/public/common/url_constants.h"
26 #include "content/public/common/url_utils.h"
27 #include "content/public/test/mock_render_process_host.h"
28 #include "content/public/test/test_utils.h"
29 #include "content/test/test_content_browser_client.h"
30 #include "content/test/test_content_client.h"
31 #include "content/test/test_render_view_host.h"
32 #include "content/test/test_web_contents.h"
33 #include "testing/gtest/include/gtest/gtest.h"
38 const char kTestWebUIUrl[] = "chrome://blah";
40 class WebContentsImplTestWebUIControllerFactory
41 : public WebUIControllerFactory {
43 virtual WebUIController* CreateWebUIControllerForURL(
44 WebUI* web_ui, const GURL& url) const OVERRIDE {
47 return new WebUIController(web_ui);
50 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
51 const GURL& url) const OVERRIDE {
52 return WebUI::kNoWebUI;
55 virtual bool UseWebUIForURL(BrowserContext* browser_context,
56 const GURL& url) const OVERRIDE {
60 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
61 const GURL& url) const OVERRIDE {
66 bool UseWebUI(const GURL& url) const {
67 return url == GURL(kTestWebUIUrl);
71 class TestInterstitialPage;
73 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
75 explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
76 : interstitial_page_(interstitial_page) {}
77 virtual void CommandReceived(const std::string& command) OVERRIDE;
78 virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
79 virtual void OnDontProceed() OVERRIDE;
80 virtual void OnProceed() OVERRIDE;
82 TestInterstitialPage* interstitial_page_;
85 class TestInterstitialPage : public InterstitialPageImpl {
87 enum InterstitialState {
88 INVALID = 0, // Hasn't yet been initialized.
89 UNDECIDED, // Initialized, but no decision taken yet.
90 OKED, // Proceed was called.
91 CANCELED // DontProceed was called.
96 virtual void TestInterstitialPageDeleted(
97 TestInterstitialPage* interstitial) = 0;
100 virtual ~Delegate() {}
103 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
104 // |deleted| (like all interstitial related tests do at this point), make sure
105 // to create an instance of the TestInterstitialPageStateGuard class on the
106 // stack in your test. This will ensure that the TestInterstitialPage states
107 // are cleared when the test finishes.
108 // Not doing so will cause stack trashing if your test does not hide the
109 // interstitial, as in such a case it will be destroyed in the test TearDown
110 // method and will dereference the |deleted| local variable which by then is
112 TestInterstitialPage(WebContentsImpl* contents,
115 InterstitialState* state,
117 : InterstitialPageImpl(
119 static_cast<RenderWidgetHostDelegate*>(contents),
120 new_navigation, url, new TestInterstitialPageDelegate(this)),
123 command_received_count_(0),
129 virtual ~TestInterstitialPage() {
133 delegate_->TestInterstitialPageDeleted(this);
136 void OnDontProceed() {
145 int command_received_count() const {
146 return command_received_count_;
149 void TestDomOperationResponse(const std::string& json_string) {
154 void TestDidNavigate(int page_id, const GURL& url) {
155 FrameHostMsg_DidCommitProvisionalLoad_Params params;
156 InitNavigateParams(¶ms, page_id, url, PAGE_TRANSITION_TYPED);
157 DidNavigate(GetRenderViewHostForTesting(), params);
160 void TestRenderViewTerminated(base::TerminationStatus status,
162 RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
165 bool is_showing() const {
166 return static_cast<TestRenderWidgetHostView*>(
167 GetRenderViewHostForTesting()->GetView())->is_showing();
176 void CommandReceived() {
177 command_received_count_++;
180 void set_delegate(Delegate* delegate) {
181 delegate_ = delegate;
185 virtual WebContentsView* CreateWebContentsView() OVERRIDE {
190 InterstitialState* state_;
192 int command_received_count_;
196 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
197 interstitial_page_->CommandReceived();
200 void TestInterstitialPageDelegate::OnDontProceed() {
201 interstitial_page_->OnDontProceed();
204 void TestInterstitialPageDelegate::OnProceed() {
205 interstitial_page_->OnProceed();
208 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
210 explicit TestInterstitialPageStateGuard(
211 TestInterstitialPage* interstitial_page)
212 : interstitial_page_(interstitial_page) {
213 DCHECK(interstitial_page_);
214 interstitial_page_->set_delegate(this);
216 virtual ~TestInterstitialPageStateGuard() {
217 if (interstitial_page_)
218 interstitial_page_->ClearStates();
221 virtual void TestInterstitialPageDeleted(
222 TestInterstitialPage* interstitial) OVERRIDE {
223 DCHECK(interstitial_page_ == interstitial);
224 interstitial_page_ = NULL;
228 TestInterstitialPage* interstitial_page_;
231 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
233 WebContentsImplTestBrowserClient()
234 : assign_site_for_url_(false) {}
236 virtual ~WebContentsImplTestBrowserClient() {}
238 virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
239 return assign_site_for_url_;
242 void set_assign_site_for_url(bool assign) {
243 assign_site_for_url_ = assign;
247 bool assign_site_for_url_;
250 class WebContentsImplTest : public RenderViewHostImplTestHarness {
252 virtual void SetUp() {
253 RenderViewHostImplTestHarness::SetUp();
254 WebUIControllerFactory::RegisterFactory(&factory_);
257 virtual void TearDown() {
258 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
259 RenderViewHostImplTestHarness::TearDown();
263 WebContentsImplTestWebUIControllerFactory factory_;
266 class TestWebContentsObserver : public WebContentsObserver {
268 explicit TestWebContentsObserver(WebContents* contents)
269 : WebContentsObserver(contents) {
271 virtual ~TestWebContentsObserver() {}
273 virtual void DidFinishLoad(int64 frame_id,
274 const GURL& validated_url,
276 RenderViewHost* render_view_host) OVERRIDE {
277 last_url_ = validated_url;
279 virtual void DidFailLoad(int64 frame_id,
280 const GURL& validated_url,
283 const base::string16& error_description,
284 RenderViewHost* render_view_host) OVERRIDE {
285 last_url_ = validated_url;
288 const GURL& last_url() const { return last_url_; }
293 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
298 // Test to make sure that title updates get stripped of whitespace.
299 TEST_F(WebContentsImplTest, UpdateTitle) {
300 NavigationControllerImpl& cont =
301 static_cast<NavigationControllerImpl&>(controller());
302 FrameHostMsg_DidCommitProvisionalLoad_Params params;
303 InitNavigateParams(¶ms, 0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED);
305 LoadCommittedDetails details;
306 cont.RendererDidNavigate(test_rvh(), params, &details);
308 contents()->UpdateTitle(rvh(), 0,
309 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
310 base::i18n::LEFT_TO_RIGHT);
311 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
314 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
315 const GURL kGURL("chrome://blah");
316 controller().LoadURL(
317 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
318 EXPECT_EQ(base::string16(), contents()->GetTitle());
321 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
322 const GURL kGURL("chrome://blah");
323 const base::string16 title = base::ASCIIToUTF16("My Title");
324 controller().LoadURL(
325 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
327 NavigationEntry* entry = controller().GetVisibleEntry();
328 ASSERT_EQ(kGURL, entry->GetURL());
329 entry->SetTitle(title);
331 EXPECT_EQ(title, contents()->GetTitle());
334 // Test view source mode for a webui page.
335 TEST_F(WebContentsImplTest, NTPViewSource) {
336 NavigationControllerImpl& cont =
337 static_cast<NavigationControllerImpl&>(controller());
338 const char kUrl[] = "view-source:chrome://blah";
339 const GURL kGURL(kUrl);
341 process()->sink().ClearMessages();
344 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
345 rvh()->GetDelegate()->RenderViewCreated(rvh());
346 // Did we get the expected message?
347 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
348 ViewMsg_EnableViewSourceMode::ID));
350 FrameHostMsg_DidCommitProvisionalLoad_Params params;
351 InitNavigateParams(¶ms, 0, kGURL, PAGE_TRANSITION_TYPED);
352 LoadCommittedDetails details;
353 cont.RendererDidNavigate(test_rvh(), params, &details);
354 // Also check title and url.
355 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
358 // Test to ensure UpdateMaxPageID is working properly.
359 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
360 SiteInstance* instance1 = contents()->GetSiteInstance();
361 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
364 EXPECT_EQ(-1, contents()->GetMaxPageID());
365 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
366 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
368 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
369 contents()->UpdateMaxPageID(3);
370 contents()->UpdateMaxPageID(1);
371 EXPECT_EQ(3, contents()->GetMaxPageID());
372 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
373 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
375 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
376 EXPECT_EQ(3, contents()->GetMaxPageID());
377 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
378 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
381 // Test simple same-SiteInstance navigation.
382 TEST_F(WebContentsImplTest, SimpleNavigation) {
383 TestRenderViewHost* orig_rvh = test_rvh();
384 SiteInstance* instance1 = contents()->GetSiteInstance();
385 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
388 const GURL url("http://www.google.com");
389 controller().LoadURL(
390 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
391 EXPECT_FALSE(contents()->cross_navigation_pending());
392 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
393 // Controller's pending entry will have a NULL site instance until we assign
394 // it in DidNavigate.
396 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
397 site_instance() == NULL);
399 // DidNavigate from the page
400 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
401 EXPECT_FALSE(contents()->cross_navigation_pending());
402 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
403 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
404 // Controller's entry should now have the SiteInstance, or else we won't be
405 // able to find it later.
408 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
412 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
413 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
414 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
415 const GURL url(std::string("http://example.org/").append(
416 GetMaxURLChars() + 1, 'a'));
418 controller().LoadURL(
419 url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
420 EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
423 // Test that navigating across a site boundary creates a new RenderViewHost
424 // with a new SiteInstance. Going back should do the same.
425 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
426 contents()->transition_cross_site = true;
427 TestRenderViewHost* orig_rvh = test_rvh();
428 RenderFrameHostImpl* orig_rfh =
429 contents()->GetFrameTree()->root()->current_frame_host();
430 int orig_rvh_delete_count = 0;
431 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
432 SiteInstance* instance1 = contents()->GetSiteInstance();
434 // Navigate to URL. First URL should use first RenderViewHost.
435 const GURL url("http://www.google.com");
436 controller().LoadURL(
437 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
438 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
440 // Keep the number of active views in orig_rvh's SiteInstance
441 // non-zero so that orig_rvh doesn't get deleted when it gets
443 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
444 increment_active_view_count();
446 EXPECT_FALSE(contents()->cross_navigation_pending());
447 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
448 EXPECT_EQ(url, contents()->GetLastCommittedURL());
449 EXPECT_EQ(url, contents()->GetVisibleURL());
451 // Navigate to new site
452 const GURL url2("http://www.yahoo.com");
453 controller().LoadURL(
454 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
455 EXPECT_TRUE(contents()->cross_navigation_pending());
456 EXPECT_EQ(url, contents()->GetLastCommittedURL());
457 EXPECT_EQ(url2, contents()->GetVisibleURL());
458 TestRenderViewHost* pending_rvh =
459 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
460 int pending_rvh_delete_count = 0;
461 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
462 RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()->
463 render_manager()->pending_frame_host();
465 // Navigations should be suspended in pending_rvh until ShouldCloseACK.
466 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
467 orig_rvh->SendShouldCloseACK(true);
468 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
470 // DidNavigate from the pending page
471 contents()->TestDidNavigate(
472 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
473 SiteInstance* instance2 = contents()->GetSiteInstance();
475 // Keep the number of active views in pending_rvh's SiteInstance
476 // non-zero so that orig_rvh doesn't get deleted when it gets
478 static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
479 increment_active_view_count();
481 EXPECT_FALSE(contents()->cross_navigation_pending());
482 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
483 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
484 EXPECT_EQ(url2, contents()->GetVisibleURL());
485 EXPECT_NE(instance1, instance2);
486 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
487 // We keep the original RFH around, swapped out.
488 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
490 EXPECT_EQ(orig_rvh_delete_count, 0);
492 // Going back should switch SiteInstances again. The first SiteInstance is
493 // stored in the NavigationEntry, so it should be the same as at the start.
494 // We should use the same RVH as before, swapping it back in.
495 controller().GoBack();
496 TestRenderViewHost* goback_rvh =
497 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
498 EXPECT_EQ(orig_rvh, goback_rvh);
499 EXPECT_TRUE(contents()->cross_navigation_pending());
501 // Navigations should be suspended in goback_rvh until ShouldCloseACK.
502 EXPECT_TRUE(goback_rvh->are_navigations_suspended());
503 pending_rvh->SendShouldCloseACK(true);
504 EXPECT_FALSE(goback_rvh->are_navigations_suspended());
506 // DidNavigate from the back action
507 contents()->TestDidNavigate(
508 goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
509 EXPECT_FALSE(contents()->cross_navigation_pending());
510 EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
511 EXPECT_EQ(instance1, contents()->GetSiteInstance());
512 // The pending RFH should now be swapped out, not deleted.
513 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
514 IsOnSwappedOutList(pending_rfh));
515 EXPECT_EQ(pending_rvh_delete_count, 0);
516 pending_rvh->OnSwappedOut(false);
518 // Close contents and ensure RVHs are deleted.
520 EXPECT_EQ(orig_rvh_delete_count, 1);
521 EXPECT_EQ(pending_rvh_delete_count, 1);
524 // Test that navigating across a site boundary after a crash creates a new
525 // RVH without requiring a cross-site transition (i.e., PENDING state).
526 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
527 contents()->transition_cross_site = true;
528 TestRenderViewHost* orig_rvh = test_rvh();
529 int orig_rvh_delete_count = 0;
530 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
531 SiteInstance* instance1 = contents()->GetSiteInstance();
533 // Navigate to URL. First URL should use first RenderViewHost.
534 const GURL url("http://www.google.com");
535 controller().LoadURL(
536 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
537 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
539 EXPECT_FALSE(contents()->cross_navigation_pending());
540 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
542 // Crash the renderer.
543 orig_rvh->set_render_view_created(false);
545 // Navigate to new site. We should not go into PENDING.
546 const GURL url2("http://www.yahoo.com");
547 controller().LoadURL(
548 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
549 RenderViewHost* new_rvh = rvh();
550 EXPECT_FALSE(contents()->cross_navigation_pending());
551 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
552 EXPECT_NE(orig_rvh, new_rvh);
553 EXPECT_EQ(orig_rvh_delete_count, 1);
555 // DidNavigate from the new page
556 contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
557 SiteInstance* instance2 = contents()->GetSiteInstance();
559 EXPECT_FALSE(contents()->cross_navigation_pending());
560 EXPECT_EQ(new_rvh, rvh());
561 EXPECT_NE(instance1, instance2);
562 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
564 // Close contents and ensure RVHs are deleted.
566 EXPECT_EQ(orig_rvh_delete_count, 1);
569 // Test that opening a new contents in the same SiteInstance and then navigating
570 // both contentses to a new site will place both contentses in a single
572 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
573 contents()->transition_cross_site = true;
574 TestRenderViewHost* orig_rvh = test_rvh();
575 SiteInstance* instance1 = contents()->GetSiteInstance();
577 // Navigate to URL. First URL should use first RenderViewHost.
578 const GURL url("http://www.google.com");
579 controller().LoadURL(
580 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
581 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
583 // Open a new contents with the same SiteInstance, navigated to the same site.
584 scoped_ptr<TestWebContents> contents2(
585 TestWebContents::Create(browser_context(), instance1));
586 contents2->transition_cross_site = true;
587 contents2->GetController().LoadURL(url, Referrer(),
588 PAGE_TRANSITION_TYPED,
590 // Need this page id to be 2 since the site instance is the same (which is the
591 // scope of page IDs) and we want to consider this a new page.
592 contents2->TestDidNavigate(
593 contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
595 // Navigate first contents to a new site.
596 const GURL url2a("http://www.yahoo.com");
597 controller().LoadURL(
598 url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
599 orig_rvh->SendShouldCloseACK(true);
600 TestRenderViewHost* pending_rvh_a =
601 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
602 contents()->TestDidNavigate(
603 pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
604 SiteInstance* instance2a = contents()->GetSiteInstance();
605 EXPECT_NE(instance1, instance2a);
607 // Navigate second contents to the same site as the first tab.
608 const GURL url2b("http://mail.yahoo.com");
609 contents2->GetController().LoadURL(url2b, Referrer(),
610 PAGE_TRANSITION_TYPED,
612 TestRenderViewHost* rvh2 =
613 static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
614 rvh2->SendShouldCloseACK(true);
615 TestRenderViewHost* pending_rvh_b =
616 static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
617 EXPECT_TRUE(pending_rvh_b != NULL);
618 EXPECT_TRUE(contents2->cross_navigation_pending());
620 // NOTE(creis): We used to be in danger of showing a crash page here if the
621 // second contents hadn't navigated somewhere first (bug 1145430). That case
622 // is now covered by the CrossSiteBoundariesAfterCrash test.
623 contents2->TestDidNavigate(
624 pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
625 SiteInstance* instance2b = contents2->GetSiteInstance();
626 EXPECT_NE(instance1, instance2b);
628 // Both contentses should now be in the same SiteInstance.
629 EXPECT_EQ(instance2a, instance2b);
632 TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
633 WebContentsImplTestBrowserClient browser_client;
634 SetBrowserClientForTesting(&browser_client);
636 contents()->transition_cross_site = true;
637 TestRenderViewHost* orig_rvh = test_rvh();
638 RenderFrameHostImpl* orig_rfh =
639 contents()->GetFrameTree()->root()->current_frame_host();
640 int orig_rvh_delete_count = 0;
641 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
642 SiteInstanceImpl* orig_instance =
643 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
645 browser_client.set_assign_site_for_url(false);
646 // Navigate to an URL that will not assign a new SiteInstance.
647 const GURL native_url("non-site-url://stuffandthings");
648 controller().LoadURL(
649 native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
650 contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
652 EXPECT_FALSE(contents()->cross_navigation_pending());
653 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
654 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
655 EXPECT_EQ(native_url, contents()->GetVisibleURL());
656 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
657 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
658 EXPECT_FALSE(orig_instance->HasSite());
660 browser_client.set_assign_site_for_url(true);
661 // Navigate to new site (should keep same site instance).
662 const GURL url("http://www.google.com");
663 controller().LoadURL(
664 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
665 EXPECT_FALSE(contents()->cross_navigation_pending());
666 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
667 EXPECT_EQ(url, contents()->GetVisibleURL());
668 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
669 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
671 // Keep the number of active views in orig_rvh's SiteInstance
672 // non-zero so that orig_rvh doesn't get deleted when it gets
674 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
675 increment_active_view_count();
677 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
679 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
680 EXPECT_EQ(url, contents()->GetLastCommittedURL());
682 // Navigate to another new site (should create a new site instance).
683 const GURL url2("http://www.yahoo.com");
684 controller().LoadURL(
685 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
686 EXPECT_TRUE(contents()->cross_navigation_pending());
687 EXPECT_EQ(url, contents()->GetLastCommittedURL());
688 EXPECT_EQ(url2, contents()->GetVisibleURL());
689 TestRenderViewHost* pending_rvh =
690 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
691 int pending_rvh_delete_count = 0;
692 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
694 // Navigations should be suspended in pending_rvh until ShouldCloseACK.
695 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
696 orig_rvh->SendShouldCloseACK(true);
697 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
699 // DidNavigate from the pending page.
700 contents()->TestDidNavigate(
701 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
702 SiteInstance* new_instance = contents()->GetSiteInstance();
704 EXPECT_FALSE(contents()->cross_navigation_pending());
705 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
706 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
707 EXPECT_EQ(url2, contents()->GetVisibleURL());
708 EXPECT_NE(new_instance, orig_instance);
709 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
710 // We keep the original RFH around, swapped out.
711 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
713 EXPECT_EQ(orig_rvh_delete_count, 0);
714 orig_rvh->OnSwappedOut(false);
716 // Close contents and ensure RVHs are deleted.
718 EXPECT_EQ(orig_rvh_delete_count, 1);
719 EXPECT_EQ(pending_rvh_delete_count, 1);
722 // Test that we can find an opener RVH even if it's pending.
723 // http://crbug.com/176252.
724 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
725 contents()->transition_cross_site = true;
726 TestRenderViewHost* orig_rvh = test_rvh();
728 // Navigate to a URL.
729 const GURL url("http://www.google.com");
730 controller().LoadURL(
731 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
732 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
734 // Start to navigate first tab to a new site, so that it has a pending RVH.
735 const GURL url2("http://www.yahoo.com");
736 controller().LoadURL(
737 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
738 orig_rvh->SendShouldCloseACK(true);
739 TestRenderViewHost* pending_rvh =
740 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
742 // While it is still pending, simulate opening a new tab with the first tab
743 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
744 // on the opener to ensure that an RVH exists.
745 int opener_routing_id = contents()->CreateOpenerRenderViews(
746 pending_rvh->GetSiteInstance());
748 // We should find the pending RVH and not create a new one.
749 EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
752 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
753 // to determine whether a navigation is cross-site.
754 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
755 contents()->transition_cross_site = true;
756 RenderViewHost* orig_rvh = rvh();
757 SiteInstance* instance1 = contents()->GetSiteInstance();
760 const GURL url("http://www.google.com");
761 controller().LoadURL(
762 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
763 contents()->TestDidNavigate(
764 orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
766 // Open a related contents to a second site.
767 scoped_ptr<TestWebContents> contents2(
768 TestWebContents::Create(browser_context(), instance1));
769 contents2->transition_cross_site = true;
770 const GURL url2("http://www.yahoo.com");
771 contents2->GetController().LoadURL(url2, Referrer(),
772 PAGE_TRANSITION_TYPED,
774 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
776 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
777 contents2->GetRenderViewHost());
778 EXPECT_FALSE(contents2->cross_navigation_pending());
779 contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
780 SiteInstance* instance2 = contents2->GetSiteInstance();
781 EXPECT_NE(instance1, instance2);
782 EXPECT_FALSE(contents2->cross_navigation_pending());
784 // Simulate a link click in first contents to second site. Doesn't switch
785 // SiteInstances, because we don't intercept WebKit navigations.
786 contents()->TestDidNavigate(
787 orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
788 SiteInstance* instance3 = contents()->GetSiteInstance();
789 EXPECT_EQ(instance1, instance3);
790 EXPECT_FALSE(contents()->cross_navigation_pending());
792 // Navigate to the new site. Doesn't switch SiteInstancees, because we
793 // compare against the current URL, not the SiteInstance's site.
794 const GURL url3("http://mail.yahoo.com");
795 controller().LoadURL(
796 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
797 EXPECT_FALSE(contents()->cross_navigation_pending());
798 contents()->TestDidNavigate(
799 orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
800 SiteInstance* instance4 = contents()->GetSiteInstance();
801 EXPECT_EQ(instance1, instance4);
804 // Test that the onbeforeunload and onunload handlers run when navigating
805 // across site boundaries.
806 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
807 contents()->transition_cross_site = true;
808 TestRenderViewHost* orig_rvh = test_rvh();
809 SiteInstance* instance1 = contents()->GetSiteInstance();
811 // Navigate to URL. First URL should use first RenderViewHost.
812 const GURL url("http://www.google.com");
813 controller().LoadURL(
814 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
815 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
816 EXPECT_FALSE(contents()->cross_navigation_pending());
817 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
819 // Navigate to new site, but simulate an onbeforeunload denial.
820 const GURL url2("http://www.yahoo.com");
821 controller().LoadURL(
822 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
823 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
824 base::TimeTicks now = base::TimeTicks::Now();
825 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, false, now, now));
826 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
827 EXPECT_FALSE(contents()->cross_navigation_pending());
828 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
830 // Navigate again, but simulate an onbeforeunload approval.
831 controller().LoadURL(
832 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
833 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
834 now = base::TimeTicks::Now();
835 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
836 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
837 EXPECT_TRUE(contents()->cross_navigation_pending());
838 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
839 contents()->GetPendingRenderViewHost());
841 // We won't hear DidNavigate until the onunload handler has finished running.
843 // DidNavigate from the pending page.
844 contents()->TestDidNavigate(
845 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
846 SiteInstance* instance2 = contents()->GetSiteInstance();
847 EXPECT_FALSE(contents()->cross_navigation_pending());
848 EXPECT_EQ(pending_rvh, rvh());
849 EXPECT_NE(instance1, instance2);
850 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
853 // Test that during a slow cross-site navigation, the original renderer can
854 // navigate to a different URL and have it displayed, canceling the slow
856 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
857 contents()->transition_cross_site = true;
858 TestRenderViewHost* orig_rvh = test_rvh();
859 SiteInstance* instance1 = contents()->GetSiteInstance();
861 // Navigate to URL. First URL should use first RenderViewHost.
862 const GURL url("http://www.google.com");
863 controller().LoadURL(
864 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
865 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
866 EXPECT_FALSE(contents()->cross_navigation_pending());
867 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
869 // Navigate to new site, simulating an onbeforeunload approval.
870 const GURL url2("http://www.yahoo.com");
871 controller().LoadURL(
872 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
873 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
874 base::TimeTicks now = base::TimeTicks::Now();
875 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
876 EXPECT_TRUE(contents()->cross_navigation_pending());
878 // Suppose the original renderer navigates before the new one is ready.
879 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
881 // Verify that the pending navigation is cancelled.
882 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
883 SiteInstance* instance2 = contents()->GetSiteInstance();
884 EXPECT_FALSE(contents()->cross_navigation_pending());
885 EXPECT_EQ(orig_rvh, rvh());
886 EXPECT_EQ(instance1, instance2);
887 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
890 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
891 contents()->transition_cross_site = true;
893 // Start with a web ui page, which gets a new RVH with WebUI bindings.
894 const GURL url1("chrome://blah");
895 controller().LoadURL(
896 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
897 TestRenderViewHost* ntp_rvh = test_rvh();
898 contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
899 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
900 SiteInstance* instance1 = contents()->GetSiteInstance();
902 EXPECT_FALSE(contents()->cross_navigation_pending());
903 EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
904 EXPECT_EQ(url1, entry1->GetURL());
906 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
907 EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
909 // Navigate to new site.
910 const GURL url2("http://www.google.com");
911 controller().LoadURL(
912 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
913 EXPECT_TRUE(contents()->cross_navigation_pending());
914 TestRenderViewHost* google_rvh =
915 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
917 // Simulate beforeunload approval.
918 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
919 base::TimeTicks now = base::TimeTicks::Now();
920 ntp_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
922 // DidNavigate from the pending page.
923 contents()->TestDidNavigate(
924 google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
925 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
926 SiteInstance* instance2 = contents()->GetSiteInstance();
928 EXPECT_FALSE(contents()->cross_navigation_pending());
929 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
930 EXPECT_NE(instance1, instance2);
931 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
932 EXPECT_EQ(url2, entry2->GetURL());
934 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
935 EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
937 // Navigate to third page on same site.
938 const GURL url3("http://news.google.com");
939 controller().LoadURL(
940 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
941 EXPECT_FALSE(contents()->cross_navigation_pending());
942 contents()->TestDidNavigate(
943 google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
944 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
945 SiteInstance* instance3 = contents()->GetSiteInstance();
947 EXPECT_FALSE(contents()->cross_navigation_pending());
948 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
949 EXPECT_EQ(instance2, instance3);
950 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
951 EXPECT_EQ(url3, entry3->GetURL());
953 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
955 // Go back within the site.
956 controller().GoBack();
957 EXPECT_FALSE(contents()->cross_navigation_pending());
958 EXPECT_EQ(entry2, controller().GetPendingEntry());
960 // Before that commits, go back again.
961 controller().GoBack();
962 EXPECT_TRUE(contents()->cross_navigation_pending());
963 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
964 EXPECT_EQ(entry1, controller().GetPendingEntry());
966 // Simulate beforeunload approval.
967 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
968 now = base::TimeTicks::Now();
969 google_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
971 // DidNavigate from the first back. This aborts the second back's pending RVH.
972 contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
974 // We should commit this page and forget about the second back.
975 EXPECT_FALSE(contents()->cross_navigation_pending());
976 EXPECT_FALSE(controller().GetPendingEntry());
977 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
978 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
980 // We should not have corrupted the NTP entry.
982 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
984 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
986 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
987 EXPECT_EQ(url1, entry1->GetURL());
990 // Test that during a slow cross-site navigation, a sub-frame navigation in the
991 // original renderer will not cancel the slow navigation (bug 42029).
992 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
993 contents()->transition_cross_site = true;
994 TestRenderViewHost* orig_rvh = test_rvh();
996 // Navigate to URL. First URL should use first RenderViewHost.
997 const GURL url("http://www.google.com");
998 controller().LoadURL(
999 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1000 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1001 EXPECT_FALSE(contents()->cross_navigation_pending());
1002 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1004 // Start navigating to new site.
1005 const GURL url2("http://www.yahoo.com");
1006 controller().LoadURL(
1007 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1009 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1010 // waiting for a before unload response.
1011 orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
1012 PAGE_TRANSITION_AUTO_SUBFRAME);
1013 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1015 // Now simulate the onbeforeunload approval and verify the navigation is
1017 base::TimeTicks now = base::TimeTicks::Now();
1018 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1019 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1020 EXPECT_TRUE(contents()->cross_navigation_pending());
1023 // Test that a cross-site navigation is not preempted if the previous
1024 // renderer sends a FrameNavigate message just before being told to stop.
1025 // We should only preempt the cross-site navigation if the previous renderer
1026 // has started a new navigation. See http://crbug.com/79176.
1027 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1028 contents()->transition_cross_site = true;
1030 // Navigate to NTP URL.
1031 const GURL url("chrome://blah");
1032 controller().LoadURL(
1033 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1034 TestRenderViewHost* orig_rvh = test_rvh();
1035 EXPECT_FALSE(contents()->cross_navigation_pending());
1037 // Navigate to new site, with the beforeunload request in flight.
1038 const GURL url2("http://www.yahoo.com");
1039 controller().LoadURL(
1040 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1041 TestRenderViewHost* pending_rvh =
1042 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1043 EXPECT_TRUE(contents()->cross_navigation_pending());
1044 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1046 // Suppose the first navigation tries to commit now, with a
1047 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1048 // but it should act as if the beforeunload ack arrived.
1049 orig_rvh->SendNavigate(1, GURL("chrome://blah"));
1050 EXPECT_TRUE(contents()->cross_navigation_pending());
1051 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1052 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1054 // The pending navigation should be able to commit successfully.
1055 contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1056 EXPECT_FALSE(contents()->cross_navigation_pending());
1057 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
1060 // Test that the original renderer cannot preempt a cross-site navigation once
1061 // the unload request has been made. At this point, the cross-site navigation
1062 // is almost ready to be displayed, and the original renderer is only given a
1063 // short chance to run an unload handler. Prevents regression of bug 23942.
1064 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
1065 contents()->transition_cross_site = true;
1066 TestRenderViewHost* orig_rvh = test_rvh();
1067 SiteInstance* instance1 = contents()->GetSiteInstance();
1069 // Navigate to URL. First URL should use first RenderViewHost.
1070 const GURL url("http://www.google.com");
1071 controller().LoadURL(
1072 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1073 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1074 EXPECT_FALSE(contents()->cross_navigation_pending());
1075 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1077 // Navigate to new site, simulating an onbeforeunload approval.
1078 const GURL url2("http://www.yahoo.com");
1079 controller().LoadURL(
1080 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1081 base::TimeTicks now = base::TimeTicks::Now();
1082 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1083 EXPECT_TRUE(contents()->cross_navigation_pending());
1084 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
1085 contents()->GetPendingRenderViewHost());
1087 // Simulate the pending renderer's response, which leads to an unload request
1088 // being sent to orig_rvh.
1089 std::vector<GURL> url_chain;
1090 url_chain.push_back(GURL());
1091 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1092 pending_rvh, GlobalRequestID(0, 0),
1093 scoped_ptr<CrossSiteTransferringRequest>(), url_chain,
1094 Referrer(), PAGE_TRANSITION_TYPED, 1, false);
1096 // Suppose the original renderer navigates now, while the unload request is in
1097 // flight. We should ignore it, wait for the unload ack, and let the pending
1098 // request continue. Otherwise, the contents may close spontaneously or stop
1099 // responding to navigation requests. (See bug 23942.)
1100 FrameHostMsg_DidCommitProvisionalLoad_Params params1a;
1101 InitNavigateParams(¶ms1a, 2, GURL("http://www.google.com/foo"),
1102 PAGE_TRANSITION_TYPED);
1103 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1105 // Verify that the pending navigation is still in progress.
1106 EXPECT_TRUE(contents()->cross_navigation_pending());
1107 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
1109 // DidNavigate from the pending page should commit it.
1110 contents()->TestDidNavigate(
1111 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1112 SiteInstance* instance2 = contents()->GetSiteInstance();
1113 EXPECT_FALSE(contents()->cross_navigation_pending());
1114 EXPECT_EQ(pending_rvh, rvh());
1115 EXPECT_NE(instance1, instance2);
1116 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1119 // Test that a cross-site navigation that doesn't commit after the unload
1120 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1121 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1122 contents()->transition_cross_site = true;
1123 TestRenderViewHost* orig_rvh = test_rvh();
1124 SiteInstance* instance1 = contents()->GetSiteInstance();
1126 // Navigate to URL. First URL should use first RenderViewHost.
1127 const GURL url("http://www.google.com");
1128 controller().LoadURL(
1129 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1130 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1131 EXPECT_FALSE(contents()->cross_navigation_pending());
1132 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1134 // Navigate to new site, simulating an onbeforeunload approval.
1135 const GURL url2("http://www.yahoo.com");
1136 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1137 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1138 base::TimeTicks now = base::TimeTicks::Now();
1139 orig_rvh->OnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true, now, now));
1140 EXPECT_TRUE(contents()->cross_navigation_pending());
1142 // Simulate swap out message when the response arrives.
1143 orig_rvh->OnSwappedOut(false);
1145 // Suppose the navigation doesn't get a chance to commit, and the user
1146 // navigates in the current RVH's SiteInstance.
1147 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1149 // Verify that the pending navigation is cancelled and the renderer is no
1150 // longer swapped out.
1151 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1152 SiteInstance* instance2 = contents()->GetSiteInstance();
1153 EXPECT_FALSE(contents()->cross_navigation_pending());
1154 EXPECT_EQ(orig_rvh, rvh());
1155 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, orig_rvh->rvh_state());
1156 EXPECT_EQ(instance1, instance2);
1157 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1160 // Test that NavigationEntries have the correct page state after going
1161 // forward and back. Prevents regression for bug 1116137.
1162 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1163 TestRenderViewHost* orig_rvh = test_rvh();
1165 // Navigate to URL. There should be no committed entry yet.
1166 const GURL url("http://www.google.com");
1167 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1168 NavigationEntry* entry = controller().GetLastCommittedEntry();
1169 EXPECT_TRUE(entry == NULL);
1171 // Committed entry should have page state after DidNavigate.
1172 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1173 entry = controller().GetLastCommittedEntry();
1174 EXPECT_TRUE(entry->GetPageState().IsValid());
1176 // Navigate to same site.
1177 const GURL url2("http://images.google.com");
1178 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1179 entry = controller().GetLastCommittedEntry();
1180 EXPECT_TRUE(entry->GetPageState().IsValid());
1182 // Committed entry should have page state after DidNavigate.
1183 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1184 entry = controller().GetLastCommittedEntry();
1185 EXPECT_TRUE(entry->GetPageState().IsValid());
1187 // Now go back. Committed entry should still have page state.
1188 controller().GoBack();
1189 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1190 entry = controller().GetLastCommittedEntry();
1191 EXPECT_TRUE(entry->GetPageState().IsValid());
1194 // Test that NavigationEntries have the correct page state and SiteInstance
1195 // state after opening a new window to about:blank. Prevents regression for
1196 // bugs b/1116137 and http://crbug.com/111975.
1197 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1198 TestRenderViewHost* orig_rvh = test_rvh();
1200 // When opening a new window, it is navigated to about:blank internally.
1201 // Currently, this results in two DidNavigate events.
1202 const GURL url(kAboutBlankURL);
1203 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1204 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1206 // Should have a page state here.
1207 NavigationEntry* entry = controller().GetLastCommittedEntry();
1208 EXPECT_TRUE(entry->GetPageState().IsValid());
1210 // The SiteInstance should be available for other navigations to use.
1211 NavigationEntryImpl* entry_impl =
1212 NavigationEntryImpl::FromNavigationEntry(entry);
1213 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1214 int32 site_instance_id = entry_impl->site_instance()->GetId();
1216 // Navigating to a normal page should not cause a process swap.
1217 const GURL new_url("http://www.google.com");
1218 controller().LoadURL(new_url, Referrer(),
1219 PAGE_TRANSITION_TYPED, std::string());
1220 EXPECT_FALSE(contents()->cross_navigation_pending());
1221 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1222 contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1223 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1224 controller().GetLastCommittedEntry());
1225 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1226 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1229 ////////////////////////////////////////////////////////////////////////////////
1230 // Interstitial Tests
1231 ////////////////////////////////////////////////////////////////////////////////
1233 // Test navigating to a page (with the navigation initiated from the browser,
1234 // as when a URL is typed in the location bar) that shows an interstitial and
1235 // creates a new navigation entry, then hiding it without proceeding.
1236 TEST_F(WebContentsImplTest,
1237 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1238 // Navigate to a page.
1239 GURL url1("http://www.google.com");
1240 test_rvh()->SendNavigate(1, url1);
1241 EXPECT_EQ(1, controller().GetEntryCount());
1243 // Initiate a browser navigation that will trigger the interstitial
1244 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1245 PAGE_TRANSITION_TYPED, std::string());
1247 // Show an interstitial.
1248 TestInterstitialPage::InterstitialState state =
1249 TestInterstitialPage::INVALID;
1250 bool deleted = false;
1251 GURL url2("http://interstitial");
1252 TestInterstitialPage* interstitial =
1253 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1254 TestInterstitialPageStateGuard state_guard(interstitial);
1255 interstitial->Show();
1256 // The interstitial should not show until its navigation has committed.
1257 EXPECT_FALSE(interstitial->is_showing());
1258 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1259 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1260 // Let's commit the interstitial navigation.
1261 interstitial->TestDidNavigate(1, url2);
1262 EXPECT_TRUE(interstitial->is_showing());
1263 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1264 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1265 NavigationEntry* entry = controller().GetVisibleEntry();
1266 ASSERT_TRUE(entry != NULL);
1267 EXPECT_TRUE(entry->GetURL() == url2);
1269 // Now don't proceed.
1270 interstitial->DontProceed();
1271 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1272 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1273 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1274 entry = controller().GetVisibleEntry();
1275 ASSERT_TRUE(entry != NULL);
1276 EXPECT_TRUE(entry->GetURL() == url1);
1277 EXPECT_EQ(1, controller().GetEntryCount());
1279 RunAllPendingInMessageLoop();
1280 EXPECT_TRUE(deleted);
1283 // Test navigating to a page (with the navigation initiated from the renderer,
1284 // as when clicking on a link in the page) that shows an interstitial and
1285 // creates a new navigation entry, then hiding it without proceeding.
1286 TEST_F(WebContentsImplTest,
1287 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1288 // Navigate to a page.
1289 GURL url1("http://www.google.com");
1290 test_rvh()->SendNavigate(1, url1);
1291 EXPECT_EQ(1, controller().GetEntryCount());
1293 // Show an interstitial (no pending entry, the interstitial would have been
1294 // triggered by clicking on a link).
1295 TestInterstitialPage::InterstitialState state =
1296 TestInterstitialPage::INVALID;
1297 bool deleted = false;
1298 GURL url2("http://interstitial");
1299 TestInterstitialPage* interstitial =
1300 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1301 TestInterstitialPageStateGuard state_guard(interstitial);
1302 interstitial->Show();
1303 // The interstitial should not show until its navigation has committed.
1304 EXPECT_FALSE(interstitial->is_showing());
1305 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1306 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1307 // Let's commit the interstitial navigation.
1308 interstitial->TestDidNavigate(1, url2);
1309 EXPECT_TRUE(interstitial->is_showing());
1310 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1311 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1312 NavigationEntry* entry = controller().GetVisibleEntry();
1313 ASSERT_TRUE(entry != NULL);
1314 EXPECT_TRUE(entry->GetURL() == url2);
1316 // Now don't proceed.
1317 interstitial->DontProceed();
1318 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1319 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1320 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1321 entry = controller().GetVisibleEntry();
1322 ASSERT_TRUE(entry != NULL);
1323 EXPECT_TRUE(entry->GetURL() == url1);
1324 EXPECT_EQ(1, controller().GetEntryCount());
1326 RunAllPendingInMessageLoop();
1327 EXPECT_TRUE(deleted);
1330 // Test navigating to a page that shows an interstitial without creating a new
1331 // navigation entry (this happens when the interstitial is triggered by a
1332 // sub-resource in the page), then hiding it without proceeding.
1333 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1334 // Navigate to a page.
1335 GURL url1("http://www.google.com");
1336 test_rvh()->SendNavigate(1, url1);
1337 EXPECT_EQ(1, controller().GetEntryCount());
1339 // Show an interstitial.
1340 TestInterstitialPage::InterstitialState state =
1341 TestInterstitialPage::INVALID;
1342 bool deleted = false;
1343 GURL url2("http://interstitial");
1344 TestInterstitialPage* interstitial =
1345 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1346 TestInterstitialPageStateGuard state_guard(interstitial);
1347 interstitial->Show();
1348 // The interstitial should not show until its navigation has committed.
1349 EXPECT_FALSE(interstitial->is_showing());
1350 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1351 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1352 // Let's commit the interstitial navigation.
1353 interstitial->TestDidNavigate(1, url2);
1354 EXPECT_TRUE(interstitial->is_showing());
1355 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1356 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1357 NavigationEntry* entry = controller().GetVisibleEntry();
1358 ASSERT_TRUE(entry != NULL);
1359 // The URL specified to the interstitial should have been ignored.
1360 EXPECT_TRUE(entry->GetURL() == url1);
1362 // Now don't proceed.
1363 interstitial->DontProceed();
1364 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1365 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1366 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1367 entry = controller().GetVisibleEntry();
1368 ASSERT_TRUE(entry != NULL);
1369 EXPECT_TRUE(entry->GetURL() == url1);
1370 EXPECT_EQ(1, controller().GetEntryCount());
1372 RunAllPendingInMessageLoop();
1373 EXPECT_TRUE(deleted);
1376 // Test navigating to a page (with the navigation initiated from the browser,
1377 // as when a URL is typed in the location bar) that shows an interstitial and
1378 // creates a new navigation entry, then proceeding.
1379 TEST_F(WebContentsImplTest,
1380 ShowInterstitialFromBrowserNewNavigationProceed) {
1381 // Navigate to a page.
1382 GURL url1("http://www.google.com");
1383 test_rvh()->SendNavigate(1, url1);
1384 EXPECT_EQ(1, controller().GetEntryCount());
1386 // Initiate a browser navigation that will trigger the interstitial
1387 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1388 PAGE_TRANSITION_TYPED, std::string());
1390 // Show an interstitial.
1391 TestInterstitialPage::InterstitialState state =
1392 TestInterstitialPage::INVALID;
1393 bool deleted = false;
1394 GURL url2("http://interstitial");
1395 TestInterstitialPage* interstitial =
1396 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1397 TestInterstitialPageStateGuard state_guard(interstitial);
1398 interstitial->Show();
1399 // The interstitial should not show until its navigation has committed.
1400 EXPECT_FALSE(interstitial->is_showing());
1401 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1402 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1403 // Let's commit the interstitial navigation.
1404 interstitial->TestDidNavigate(1, url2);
1405 EXPECT_TRUE(interstitial->is_showing());
1406 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1407 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1408 NavigationEntry* entry = controller().GetVisibleEntry();
1409 ASSERT_TRUE(entry != NULL);
1410 EXPECT_TRUE(entry->GetURL() == url2);
1413 interstitial->Proceed();
1414 // The interstitial should show until the new navigation commits.
1415 RunAllPendingInMessageLoop();
1416 ASSERT_FALSE(deleted);
1417 EXPECT_EQ(TestInterstitialPage::OKED, state);
1418 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1419 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1421 // Simulate the navigation to the page, that's when the interstitial gets
1423 GURL url3("http://www.thepage.com");
1424 test_rvh()->SendNavigate(2, url3);
1426 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1427 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1428 entry = controller().GetVisibleEntry();
1429 ASSERT_TRUE(entry != NULL);
1430 EXPECT_TRUE(entry->GetURL() == url3);
1432 EXPECT_EQ(2, controller().GetEntryCount());
1434 RunAllPendingInMessageLoop();
1435 EXPECT_TRUE(deleted);
1438 // Test navigating to a page (with the navigation initiated from the renderer,
1439 // as when clicking on a link in the page) that shows an interstitial and
1440 // creates a new navigation entry, then proceeding.
1441 TEST_F(WebContentsImplTest,
1442 ShowInterstitialFromRendererNewNavigationProceed) {
1443 // Navigate to a page.
1444 GURL url1("http://www.google.com");
1445 test_rvh()->SendNavigate(1, url1);
1446 EXPECT_EQ(1, controller().GetEntryCount());
1448 // Show an interstitial.
1449 TestInterstitialPage::InterstitialState state =
1450 TestInterstitialPage::INVALID;
1451 bool deleted = false;
1452 GURL url2("http://interstitial");
1453 TestInterstitialPage* interstitial =
1454 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1455 TestInterstitialPageStateGuard state_guard(interstitial);
1456 interstitial->Show();
1457 // The interstitial should not show until its navigation has committed.
1458 EXPECT_FALSE(interstitial->is_showing());
1459 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1460 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1461 // Let's commit the interstitial navigation.
1462 interstitial->TestDidNavigate(1, url2);
1463 EXPECT_TRUE(interstitial->is_showing());
1464 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1465 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1466 NavigationEntry* entry = controller().GetVisibleEntry();
1467 ASSERT_TRUE(entry != NULL);
1468 EXPECT_TRUE(entry->GetURL() == url2);
1471 interstitial->Proceed();
1472 // The interstitial should show until the new navigation commits.
1473 RunAllPendingInMessageLoop();
1474 ASSERT_FALSE(deleted);
1475 EXPECT_EQ(TestInterstitialPage::OKED, state);
1476 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1477 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1479 // Simulate the navigation to the page, that's when the interstitial gets
1481 GURL url3("http://www.thepage.com");
1482 test_rvh()->SendNavigate(2, url3);
1484 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1485 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1486 entry = controller().GetVisibleEntry();
1487 ASSERT_TRUE(entry != NULL);
1488 EXPECT_TRUE(entry->GetURL() == url3);
1490 EXPECT_EQ(2, controller().GetEntryCount());
1492 RunAllPendingInMessageLoop();
1493 EXPECT_TRUE(deleted);
1496 // Test navigating to a page that shows an interstitial without creating a new
1497 // navigation entry (this happens when the interstitial is triggered by a
1498 // sub-resource in the page), then proceeding.
1499 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1500 // Navigate to a page so we have a navigation entry in the controller.
1501 GURL url1("http://www.google.com");
1502 test_rvh()->SendNavigate(1, url1);
1503 EXPECT_EQ(1, controller().GetEntryCount());
1505 // Show an interstitial.
1506 TestInterstitialPage::InterstitialState state =
1507 TestInterstitialPage::INVALID;
1508 bool deleted = false;
1509 GURL url2("http://interstitial");
1510 TestInterstitialPage* interstitial =
1511 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1512 TestInterstitialPageStateGuard state_guard(interstitial);
1513 interstitial->Show();
1514 // The interstitial should not show until its navigation has committed.
1515 EXPECT_FALSE(interstitial->is_showing());
1516 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1517 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1518 // Let's commit the interstitial navigation.
1519 interstitial->TestDidNavigate(1, url2);
1520 EXPECT_TRUE(interstitial->is_showing());
1521 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1522 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1523 NavigationEntry* entry = controller().GetVisibleEntry();
1524 ASSERT_TRUE(entry != NULL);
1525 // The URL specified to the interstitial should have been ignored.
1526 EXPECT_TRUE(entry->GetURL() == url1);
1529 interstitial->Proceed();
1530 // Since this is not a new navigation, the previous page is dismissed right
1531 // away and shows the original page.
1532 EXPECT_EQ(TestInterstitialPage::OKED, state);
1533 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1534 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1535 entry = controller().GetVisibleEntry();
1536 ASSERT_TRUE(entry != NULL);
1537 EXPECT_TRUE(entry->GetURL() == url1);
1539 EXPECT_EQ(1, controller().GetEntryCount());
1541 RunAllPendingInMessageLoop();
1542 EXPECT_TRUE(deleted);
1545 // Test navigating to a page that shows an interstitial, then navigating away.
1546 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1547 // Show interstitial.
1548 TestInterstitialPage::InterstitialState state =
1549 TestInterstitialPage::INVALID;
1550 bool deleted = false;
1551 GURL url("http://interstitial");
1552 TestInterstitialPage* interstitial =
1553 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1554 TestInterstitialPageStateGuard state_guard(interstitial);
1555 interstitial->Show();
1556 interstitial->TestDidNavigate(1, url);
1558 // While interstitial showing, navigate to a new URL.
1559 const GURL url2("http://www.yahoo.com");
1560 test_rvh()->SendNavigate(1, url2);
1562 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1564 RunAllPendingInMessageLoop();
1565 EXPECT_TRUE(deleted);
1568 // Test navigating to a page that shows an interstitial, then going back.
1569 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1570 // Navigate to a page so we have a navigation entry in the controller.
1571 GURL url1("http://www.google.com");
1572 test_rvh()->SendNavigate(1, url1);
1573 EXPECT_EQ(1, controller().GetEntryCount());
1575 // Show interstitial.
1576 TestInterstitialPage::InterstitialState state =
1577 TestInterstitialPage::INVALID;
1578 bool deleted = false;
1579 GURL interstitial_url("http://interstitial");
1580 TestInterstitialPage* interstitial =
1581 new TestInterstitialPage(contents(), true, interstitial_url,
1583 TestInterstitialPageStateGuard state_guard(interstitial);
1584 interstitial->Show();
1585 interstitial->TestDidNavigate(2, interstitial_url);
1587 // While the interstitial is showing, go back.
1588 controller().GoBack();
1589 test_rvh()->SendNavigate(1, url1);
1591 // Make sure we are back to the original page and that the interstitial is
1593 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1594 NavigationEntry* entry = controller().GetVisibleEntry();
1596 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1598 RunAllPendingInMessageLoop();
1599 EXPECT_TRUE(deleted);
1602 // Test navigating to a page that shows an interstitial, has a renderer crash,
1603 // and then goes back.
1604 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1605 // Navigate to a page so we have a navigation entry in the controller.
1606 GURL url1("http://www.google.com");
1607 test_rvh()->SendNavigate(1, url1);
1608 EXPECT_EQ(1, controller().GetEntryCount());
1610 // Show interstitial.
1611 TestInterstitialPage::InterstitialState state =
1612 TestInterstitialPage::INVALID;
1613 bool deleted = false;
1614 GURL interstitial_url("http://interstitial");
1615 TestInterstitialPage* interstitial =
1616 new TestInterstitialPage(contents(), true, interstitial_url,
1618 TestInterstitialPageStateGuard state_guard(interstitial);
1619 interstitial->Show();
1620 interstitial->TestDidNavigate(2, interstitial_url);
1622 // Crash the renderer
1623 test_rvh()->OnMessageReceived(
1624 ViewHostMsg_RenderProcessGone(
1625 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1627 // While the interstitial is showing, go back.
1628 controller().GoBack();
1629 test_rvh()->SendNavigate(1, url1);
1631 // Make sure we are back to the original page and that the interstitial is
1633 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1634 NavigationEntry* entry = controller().GetVisibleEntry();
1636 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1638 RunAllPendingInMessageLoop();
1639 EXPECT_TRUE(deleted);
1642 // Test navigating to a page that shows an interstitial, has the renderer crash,
1643 // and then navigates to the interstitial.
1644 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1645 // Navigate to a page so we have a navigation entry in the controller.
1646 GURL url1("http://www.google.com");
1647 test_rvh()->SendNavigate(1, url1);
1648 EXPECT_EQ(1, controller().GetEntryCount());
1650 // Show interstitial.
1651 TestInterstitialPage::InterstitialState state =
1652 TestInterstitialPage::INVALID;
1653 bool deleted = false;
1654 GURL interstitial_url("http://interstitial");
1655 TestInterstitialPage* interstitial =
1656 new TestInterstitialPage(contents(), true, interstitial_url,
1658 TestInterstitialPageStateGuard state_guard(interstitial);
1659 interstitial->Show();
1661 // Crash the renderer
1662 test_rvh()->OnMessageReceived(
1663 ViewHostMsg_RenderProcessGone(
1664 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1666 interstitial->TestDidNavigate(2, interstitial_url);
1669 // Test navigating to a page that shows an interstitial, then close the
1671 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1672 // Show interstitial.
1673 TestInterstitialPage::InterstitialState state =
1674 TestInterstitialPage::INVALID;
1675 bool deleted = false;
1676 GURL url("http://interstitial");
1677 TestInterstitialPage* interstitial =
1678 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1679 TestInterstitialPageStateGuard state_guard(interstitial);
1680 interstitial->Show();
1681 interstitial->TestDidNavigate(1, url);
1683 // Now close the contents.
1685 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1687 RunAllPendingInMessageLoop();
1688 EXPECT_TRUE(deleted);
1691 // Test navigating to a page that shows an interstitial, then close the
1693 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1694 // Show interstitial.
1695 TestInterstitialPage::InterstitialState state =
1696 TestInterstitialPage::INVALID;
1697 bool deleted = false;
1698 GURL url("http://interstitial");
1699 TestInterstitialPage* interstitial =
1700 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1701 TestInterstitialPageStateGuard state_guard(interstitial);
1702 interstitial->Show();
1703 interstitial->TestDidNavigate(1, url);
1704 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1705 interstitial->GetRenderViewHostForTesting());
1707 // Now close the contents.
1709 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1711 // Before the interstitial has a chance to process its shutdown task,
1712 // simulate quitting the browser. This goes through all processes and
1713 // tells them to destruct.
1714 rvh->OnMessageReceived(
1715 ViewHostMsg_RenderProcessGone(0, 0, 0));
1717 RunAllPendingInMessageLoop();
1718 EXPECT_TRUE(deleted);
1721 // Test that after Proceed is called and an interstitial is still shown, no more
1722 // commands get executed.
1723 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1724 // Navigate to a page so we have a navigation entry in the controller.
1725 GURL url1("http://www.google.com");
1726 test_rvh()->SendNavigate(1, url1);
1727 EXPECT_EQ(1, controller().GetEntryCount());
1729 // Show an interstitial.
1730 TestInterstitialPage::InterstitialState state =
1731 TestInterstitialPage::INVALID;
1732 bool deleted = false;
1733 GURL url2("http://interstitial");
1734 TestInterstitialPage* interstitial =
1735 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1736 TestInterstitialPageStateGuard state_guard(interstitial);
1737 interstitial->Show();
1738 interstitial->TestDidNavigate(1, url2);
1741 EXPECT_EQ(0, interstitial->command_received_count());
1742 interstitial->TestDomOperationResponse("toto");
1743 EXPECT_EQ(1, interstitial->command_received_count());
1746 interstitial->Proceed();
1747 RunAllPendingInMessageLoop();
1748 ASSERT_FALSE(deleted);
1750 // While the navigation to the new page is pending, send other commands, they
1751 // should be ignored.
1752 interstitial->TestDomOperationResponse("hello");
1753 interstitial->TestDomOperationResponse("hi");
1754 EXPECT_EQ(1, interstitial->command_received_count());
1757 // Test showing an interstitial while another interstitial is already showing.
1758 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1759 // Navigate to a page so we have a navigation entry in the controller.
1760 GURL start_url("http://www.google.com");
1761 test_rvh()->SendNavigate(1, start_url);
1762 EXPECT_EQ(1, controller().GetEntryCount());
1764 // Show an interstitial.
1765 TestInterstitialPage::InterstitialState state1 =
1766 TestInterstitialPage::INVALID;
1767 bool deleted1 = false;
1768 GURL url1("http://interstitial1");
1769 TestInterstitialPage* interstitial1 =
1770 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1771 TestInterstitialPageStateGuard state_guard1(interstitial1);
1772 interstitial1->Show();
1773 interstitial1->TestDidNavigate(1, url1);
1775 // Now show another interstitial.
1776 TestInterstitialPage::InterstitialState state2 =
1777 TestInterstitialPage::INVALID;
1778 bool deleted2 = false;
1779 GURL url2("http://interstitial2");
1780 TestInterstitialPage* interstitial2 =
1781 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1782 TestInterstitialPageStateGuard state_guard2(interstitial2);
1783 interstitial2->Show();
1784 interstitial2->TestDidNavigate(1, url2);
1786 // Showing interstitial2 should have caused interstitial1 to go away.
1787 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1788 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1790 RunAllPendingInMessageLoop();
1791 EXPECT_TRUE(deleted1);
1792 ASSERT_FALSE(deleted2);
1794 // Let's make sure interstitial2 is working as intended.
1795 interstitial2->Proceed();
1796 GURL landing_url("http://www.thepage.com");
1797 test_rvh()->SendNavigate(2, landing_url);
1799 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1800 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1801 NavigationEntry* entry = controller().GetVisibleEntry();
1802 ASSERT_TRUE(entry != NULL);
1803 EXPECT_TRUE(entry->GetURL() == landing_url);
1804 EXPECT_EQ(2, controller().GetEntryCount());
1805 RunAllPendingInMessageLoop();
1806 EXPECT_TRUE(deleted2);
1809 // Test showing an interstitial, proceeding and then navigating to another
1811 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
1812 // Navigate to a page so we have a navigation entry in the controller.
1813 GURL start_url("http://www.google.com");
1814 test_rvh()->SendNavigate(1, start_url);
1815 EXPECT_EQ(1, controller().GetEntryCount());
1817 // Show an interstitial.
1818 TestInterstitialPage::InterstitialState state1 =
1819 TestInterstitialPage::INVALID;
1820 bool deleted1 = false;
1821 GURL url1("http://interstitial1");
1822 TestInterstitialPage* interstitial1 =
1823 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1824 TestInterstitialPageStateGuard state_guard1(interstitial1);
1825 interstitial1->Show();
1826 interstitial1->TestDidNavigate(1, url1);
1828 // Take action. The interstitial won't be hidden until the navigation is
1830 interstitial1->Proceed();
1831 EXPECT_EQ(TestInterstitialPage::OKED, state1);
1833 // Now show another interstitial (simulating the navigation causing another
1835 TestInterstitialPage::InterstitialState state2 =
1836 TestInterstitialPage::INVALID;
1837 bool deleted2 = false;
1838 GURL url2("http://interstitial2");
1839 TestInterstitialPage* interstitial2 =
1840 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1841 TestInterstitialPageStateGuard state_guard2(interstitial2);
1842 interstitial2->Show();
1843 interstitial2->TestDidNavigate(1, url2);
1845 // Showing interstitial2 should have caused interstitial1 to go away.
1846 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1847 RunAllPendingInMessageLoop();
1848 EXPECT_TRUE(deleted1);
1849 ASSERT_FALSE(deleted2);
1851 // Let's make sure interstitial2 is working as intended.
1852 interstitial2->Proceed();
1853 GURL landing_url("http://www.thepage.com");
1854 test_rvh()->SendNavigate(2, landing_url);
1856 RunAllPendingInMessageLoop();
1857 EXPECT_TRUE(deleted2);
1858 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1859 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1860 NavigationEntry* entry = controller().GetVisibleEntry();
1861 ASSERT_TRUE(entry != NULL);
1862 EXPECT_TRUE(entry->GetURL() == landing_url);
1863 EXPECT_EQ(2, controller().GetEntryCount());
1866 // Test that navigating away from an interstitial while it's loading cause it
1868 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
1869 // Show an interstitial.
1870 TestInterstitialPage::InterstitialState state =
1871 TestInterstitialPage::INVALID;
1872 bool deleted = false;
1873 GURL interstitial_url("http://interstitial");
1874 TestInterstitialPage* interstitial =
1875 new TestInterstitialPage(contents(), true, interstitial_url,
1877 TestInterstitialPageStateGuard state_guard(interstitial);
1878 interstitial->Show();
1880 // Let's simulate a navigation initiated from the browser before the
1881 // interstitial finishes loading.
1882 const GURL url("http://www.google.com");
1883 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1884 EXPECT_FALSE(interstitial->is_showing());
1885 RunAllPendingInMessageLoop();
1886 ASSERT_FALSE(deleted);
1888 // Now let's make the interstitial navigation commit.
1889 interstitial->TestDidNavigate(1, interstitial_url);
1891 // After it loaded the interstitial should be gone.
1892 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1894 RunAllPendingInMessageLoop();
1895 EXPECT_TRUE(deleted);
1898 // Test that a new request to show an interstitial while an interstitial is
1899 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
1900 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
1901 GURL interstitial_url("http://interstitial");
1903 // Show a first interstitial.
1904 TestInterstitialPage::InterstitialState state1 =
1905 TestInterstitialPage::INVALID;
1906 bool deleted1 = false;
1907 TestInterstitialPage* interstitial1 =
1908 new TestInterstitialPage(contents(), true, interstitial_url,
1909 &state1, &deleted1);
1910 TestInterstitialPageStateGuard state_guard1(interstitial1);
1911 interstitial1->Show();
1913 // Show another interstitial on that same contents before the first one had
1915 TestInterstitialPage::InterstitialState state2 =
1916 TestInterstitialPage::INVALID;
1917 bool deleted2 = false;
1918 TestInterstitialPage* interstitial2 =
1919 new TestInterstitialPage(contents(), true, interstitial_url,
1920 &state2, &deleted2);
1921 TestInterstitialPageStateGuard state_guard2(interstitial2);
1922 interstitial2->Show();
1924 // The first interstitial should have been closed and deleted.
1925 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1926 // The 2nd one should still be OK.
1927 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1929 RunAllPendingInMessageLoop();
1930 EXPECT_TRUE(deleted1);
1931 ASSERT_FALSE(deleted2);
1933 // Make the interstitial navigation commit it should be showing.
1934 interstitial2->TestDidNavigate(1, interstitial_url);
1935 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
1938 // Test showing an interstitial and have its renderer crash.
1939 TEST_F(WebContentsImplTest, InterstitialCrasher) {
1940 // Show an interstitial.
1941 TestInterstitialPage::InterstitialState state =
1942 TestInterstitialPage::INVALID;
1943 bool deleted = false;
1944 GURL url("http://interstitial");
1945 TestInterstitialPage* interstitial =
1946 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1947 TestInterstitialPageStateGuard state_guard(interstitial);
1948 interstitial->Show();
1949 // Simulate a renderer crash before the interstitial is shown.
1950 interstitial->TestRenderViewTerminated(
1951 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1952 // The interstitial should have been dismissed.
1953 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1954 RunAllPendingInMessageLoop();
1955 EXPECT_TRUE(deleted);
1957 // Now try again but this time crash the intersitial after it was shown.
1959 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1960 interstitial->Show();
1961 interstitial->TestDidNavigate(1, url);
1962 // Simulate a renderer crash.
1963 interstitial->TestRenderViewTerminated(
1964 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
1965 // The interstitial should have been dismissed.
1966 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1967 RunAllPendingInMessageLoop();
1968 EXPECT_TRUE(deleted);
1971 // Tests that showing an interstitial as a result of a browser initiated
1972 // navigation while an interstitial is showing does not remove the pending
1973 // entry (see http://crbug.com/9791).
1974 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
1975 const char kUrl[] = "http://www.badguys.com/";
1976 const GURL kGURL(kUrl);
1978 // Start a navigation to a page
1979 contents()->GetController().LoadURL(
1980 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1982 // Simulate that navigation triggering an interstitial.
1983 TestInterstitialPage::InterstitialState state =
1984 TestInterstitialPage::INVALID;
1985 bool deleted = false;
1986 TestInterstitialPage* interstitial =
1987 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
1988 TestInterstitialPageStateGuard state_guard(interstitial);
1989 interstitial->Show();
1990 interstitial->TestDidNavigate(1, kGURL);
1992 // Initiate a new navigation from the browser that also triggers an
1994 contents()->GetController().LoadURL(
1995 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1996 TestInterstitialPage::InterstitialState state2 =
1997 TestInterstitialPage::INVALID;
1998 bool deleted2 = false;
1999 TestInterstitialPage* interstitial2 =
2000 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
2001 TestInterstitialPageStateGuard state_guard2(interstitial2);
2002 interstitial2->Show();
2003 interstitial2->TestDidNavigate(1, kGURL);
2005 // Make sure we still have an entry.
2006 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2008 EXPECT_EQ(kUrl, entry->GetURL().spec());
2010 // And that the first interstitial is gone, but not the second.
2011 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2012 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2013 RunAllPendingInMessageLoop();
2014 EXPECT_TRUE(deleted);
2015 EXPECT_FALSE(deleted2);
2018 // Tests that Javascript messages are not shown while an interstitial is
2020 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2021 const char kUrl[] = "http://www.badguys.com/";
2022 const GURL kGURL(kUrl);
2024 // Start a navigation to a page
2025 contents()->GetController().LoadURL(
2026 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2027 // DidNavigate from the page
2028 contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
2030 // Simulate showing an interstitial while the page is showing.
2031 TestInterstitialPage::InterstitialState state =
2032 TestInterstitialPage::INVALID;
2033 bool deleted = false;
2034 TestInterstitialPage* interstitial =
2035 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2036 TestInterstitialPageStateGuard state_guard(interstitial);
2037 interstitial->Show();
2038 interstitial->TestDidNavigate(1, kGURL);
2040 // While the interstitial is showing, let's simulate the hidden page
2041 // attempting to show a JS message.
2042 IPC::Message* dummy_message = new IPC::Message;
2043 bool did_suppress_message = false;
2044 contents()->RunJavaScriptMessage(contents()->GetRenderViewHost(),
2045 base::ASCIIToUTF16("This is an informative message"),
2046 base::ASCIIToUTF16("OK"),
2047 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message,
2048 &did_suppress_message);
2049 EXPECT_TRUE(did_suppress_message);
2052 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2053 // interstitial it isn't copied over to the destination.
2054 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2055 // Navigate to a page.
2056 GURL url1("http://www.google.com");
2057 test_rvh()->SendNavigate(1, url1);
2058 EXPECT_EQ(1, controller().GetEntryCount());
2060 // Initiate a browser navigation that will trigger the interstitial
2061 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2062 PAGE_TRANSITION_TYPED, std::string());
2064 // Show an interstitial.
2065 TestInterstitialPage::InterstitialState state =
2066 TestInterstitialPage::INVALID;
2067 bool deleted = false;
2068 GURL url2("http://interstitial");
2069 TestInterstitialPage* interstitial =
2070 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2071 TestInterstitialPageStateGuard state_guard(interstitial);
2072 interstitial->Show();
2073 interstitial->TestDidNavigate(1, url2);
2074 EXPECT_TRUE(interstitial->is_showing());
2075 EXPECT_EQ(2, controller().GetEntryCount());
2077 // Create another NavigationController.
2078 GURL url3("http://foo2");
2079 scoped_ptr<TestWebContents> other_contents(
2080 static_cast<TestWebContents*>(CreateTestWebContents()));
2081 NavigationControllerImpl& other_controller = other_contents->GetController();
2082 other_contents->NavigateAndCommit(url3);
2083 other_contents->ExpectSetHistoryLengthAndPrune(
2084 NavigationEntryImpl::FromNavigationEntry(
2085 other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2086 other_controller.GetEntryAtIndex(0)->GetPageID());
2087 other_controller.CopyStateFromAndPrune(&controller(), false);
2089 // The merged controller should only have two entries: url1 and url2.
2090 ASSERT_EQ(2, other_controller.GetEntryCount());
2091 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2092 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2093 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2095 // And the merged controller shouldn't be showing an interstitial.
2096 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2099 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2100 // showing an interstitial.
2101 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2102 // Navigate to a page.
2103 GURL url1("http://www.google.com");
2104 contents()->NavigateAndCommit(url1);
2106 // Create another NavigationController.
2107 scoped_ptr<TestWebContents> other_contents(
2108 static_cast<TestWebContents*>(CreateTestWebContents()));
2109 NavigationControllerImpl& other_controller = other_contents->GetController();
2111 // Navigate it to url2.
2112 GURL url2("http://foo2");
2113 other_contents->NavigateAndCommit(url2);
2115 // Show an interstitial.
2116 TestInterstitialPage::InterstitialState state =
2117 TestInterstitialPage::INVALID;
2118 bool deleted = false;
2119 GURL url3("http://interstitial");
2120 TestInterstitialPage* interstitial =
2121 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2123 TestInterstitialPageStateGuard state_guard(interstitial);
2124 interstitial->Show();
2125 interstitial->TestDidNavigate(1, url3);
2126 EXPECT_TRUE(interstitial->is_showing());
2127 EXPECT_EQ(2, other_controller.GetEntryCount());
2129 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2130 // interstitial is showing in the target.
2131 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2134 // Regression test for http://crbug.com/168611 - the URLs passed by the
2135 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2136 TEST_F(WebContentsImplTest, FilterURLs) {
2137 TestWebContentsObserver observer(contents());
2139 // A navigation to about:whatever should always look like a navigation to
2141 GURL url_normalized(kAboutBlankURL);
2142 GURL url_from_ipc("about:whatever");
2144 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2145 // will use the given URL to create the NavigationEntry as well, and that
2146 // entry should contain the filtered URL.
2147 contents()->NavigateAndCommit(url_normalized);
2149 // Check that an IPC with about:whatever is correctly normalized.
2150 contents()->TestDidFinishLoad(1, url_from_ipc, true);
2152 EXPECT_EQ(url_normalized, observer.last_url());
2154 // Create and navigate another WebContents.
2155 scoped_ptr<TestWebContents> other_contents(
2156 static_cast<TestWebContents*>(CreateTestWebContents()));
2157 TestWebContentsObserver other_observer(other_contents.get());
2158 other_contents->NavigateAndCommit(url_normalized);
2160 // Check that an IPC with about:whatever is correctly normalized.
2161 other_contents->TestDidFailLoadWithError(
2162 1, url_from_ipc, true, 1, base::string16());
2163 EXPECT_EQ(url_normalized, other_observer.last_url());
2166 // Test that if a pending contents is deleted before it is shown, we don't
2168 TEST_F(WebContentsImplTest, PendingContents) {
2169 scoped_ptr<TestWebContents> other_contents(
2170 static_cast<TestWebContents*>(CreateTestWebContents()));
2171 contents()->AddPendingContents(other_contents.get());
2172 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2173 other_contents.reset();
2174 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2177 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
2178 const gfx::Size original_preferred_size(1024, 768);
2179 contents()->UpdatePreferredSize(original_preferred_size);
2181 // With no capturers, expect the preferred size to be the one propagated into
2182 // WebContentsImpl via the RenderViewHostDelegate interface.
2183 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2184 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2186 // Increment capturer count, but without specifying a capture size. Expect
2187 // a "not set" preferred size.
2188 contents()->IncrementCapturerCount(gfx::Size());
2189 EXPECT_EQ(1, contents()->GetCapturerCount());
2190 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2192 // Increment capturer count again, but with an overriding capture size.
2193 // Expect preferred size to now be overridden to the capture size.
2194 const gfx::Size capture_size(1280, 720);
2195 contents()->IncrementCapturerCount(capture_size);
2196 EXPECT_EQ(2, contents()->GetCapturerCount());
2197 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2199 // Increment capturer count a third time, but the expect that the preferred
2200 // size is still the first capture size.
2201 const gfx::Size another_capture_size(720, 480);
2202 contents()->IncrementCapturerCount(another_capture_size);
2203 EXPECT_EQ(3, contents()->GetCapturerCount());
2204 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2206 // Decrement capturer count twice, but expect the preferred size to still be
2208 contents()->DecrementCapturerCount();
2209 contents()->DecrementCapturerCount();
2210 EXPECT_EQ(1, contents()->GetCapturerCount());
2211 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2213 // Decrement capturer count, and since the count has dropped to zero, the
2214 // original preferred size should be restored.
2215 contents()->DecrementCapturerCount();
2216 EXPECT_EQ(0, contents()->GetCapturerCount());
2217 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2220 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2222 TEST_F(WebContentsImplTest, GetLastActiveTime) {
2223 // The WebContents starts with a valid creation time.
2224 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2226 // Reset the last active time to a known-bad value.
2227 contents()->last_active_time_ = base::TimeTicks();
2228 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2230 // Simulate activating the WebContents. The active time should update.
2231 contents()->WasShown();
2232 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2235 } // namespace content