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/cross_site_transferring_request.h"
8 #include "content/browser/frame_host/interstitial_page_impl.h"
9 #include "content/browser/frame_host/navigation_entry_impl.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/input/synthetic_web_input_event_builders.h"
15 #include "content/common/view_messages.h"
16 #include "content/public/browser/global_request_id.h"
17 #include "content/public/browser/interstitial_page_delegate.h"
18 #include "content/public/browser/navigation_details.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_source.h"
21 #include "content/public/browser/render_widget_host_view.h"
22 #include "content/public/browser/web_contents_delegate.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/browser/web_ui_controller.h"
25 #include "content/public/common/bindings_policy.h"
26 #include "content/public/common/content_constants.h"
27 #include "content/public/common/url_constants.h"
28 #include "content/public/common/url_utils.h"
29 #include "content/public/test/mock_render_process_host.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/test/test_content_browser_client.h"
32 #include "content/test/test_content_client.h"
33 #include "content/test/test_render_view_host.h"
34 #include "content/test/test_web_contents.h"
35 #include "testing/gtest/include/gtest/gtest.h"
40 const char kTestWebUIUrl[] = "chrome://blah";
42 class WebContentsImplTestWebUIControllerFactory
43 : public WebUIControllerFactory {
45 virtual WebUIController* CreateWebUIControllerForURL(
46 WebUI* web_ui, const GURL& url) const OVERRIDE {
49 return new WebUIController(web_ui);
52 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
53 const GURL& url) const OVERRIDE {
54 return WebUI::kNoWebUI;
57 virtual bool UseWebUIForURL(BrowserContext* browser_context,
58 const GURL& url) const OVERRIDE {
62 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
63 const GURL& url) const OVERRIDE {
68 bool UseWebUI(const GURL& url) const {
69 return url == GURL(kTestWebUIUrl);
73 class TestInterstitialPage;
75 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
77 explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
78 : interstitial_page_(interstitial_page) {}
79 virtual void CommandReceived(const std::string& command) OVERRIDE;
80 virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
81 virtual void OnDontProceed() OVERRIDE;
82 virtual void OnProceed() OVERRIDE;
84 TestInterstitialPage* interstitial_page_;
87 class TestInterstitialPage : public InterstitialPageImpl {
89 enum InterstitialState {
90 INVALID = 0, // Hasn't yet been initialized.
91 UNDECIDED, // Initialized, but no decision taken yet.
92 OKED, // Proceed was called.
93 CANCELED // DontProceed was called.
98 virtual void TestInterstitialPageDeleted(
99 TestInterstitialPage* interstitial) = 0;
102 virtual ~Delegate() {}
105 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
106 // |deleted| (like all interstitial related tests do at this point), make sure
107 // to create an instance of the TestInterstitialPageStateGuard class on the
108 // stack in your test. This will ensure that the TestInterstitialPage states
109 // are cleared when the test finishes.
110 // Not doing so will cause stack trashing if your test does not hide the
111 // interstitial, as in such a case it will be destroyed in the test TearDown
112 // method and will dereference the |deleted| local variable which by then is
114 TestInterstitialPage(WebContentsImpl* contents,
117 InterstitialState* state,
119 : InterstitialPageImpl(
121 static_cast<RenderWidgetHostDelegate*>(contents),
122 new_navigation, url, new TestInterstitialPageDelegate(this)),
125 command_received_count_(0),
131 virtual ~TestInterstitialPage() {
135 delegate_->TestInterstitialPageDeleted(this);
138 void OnDontProceed() {
147 int command_received_count() const {
148 return command_received_count_;
151 void TestDomOperationResponse(const std::string& json_string) {
156 void TestDidNavigate(int page_id, const GURL& url) {
157 FrameHostMsg_DidCommitProvisionalLoad_Params params;
158 InitNavigateParams(¶ms, page_id, url, PAGE_TRANSITION_TYPED);
159 DidNavigate(GetRenderViewHostForTesting(), params);
162 void TestRenderViewTerminated(base::TerminationStatus status,
164 RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
167 bool is_showing() const {
168 return static_cast<TestRenderWidgetHostView*>(
169 GetRenderViewHostForTesting()->GetView())->is_showing();
178 void CommandReceived() {
179 command_received_count_++;
182 void set_delegate(Delegate* delegate) {
183 delegate_ = delegate;
187 virtual WebContentsView* CreateWebContentsView() OVERRIDE {
192 InterstitialState* state_;
194 int command_received_count_;
198 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
199 interstitial_page_->CommandReceived();
202 void TestInterstitialPageDelegate::OnDontProceed() {
203 interstitial_page_->OnDontProceed();
206 void TestInterstitialPageDelegate::OnProceed() {
207 interstitial_page_->OnProceed();
210 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
212 explicit TestInterstitialPageStateGuard(
213 TestInterstitialPage* interstitial_page)
214 : interstitial_page_(interstitial_page) {
215 DCHECK(interstitial_page_);
216 interstitial_page_->set_delegate(this);
218 virtual ~TestInterstitialPageStateGuard() {
219 if (interstitial_page_)
220 interstitial_page_->ClearStates();
223 virtual void TestInterstitialPageDeleted(
224 TestInterstitialPage* interstitial) OVERRIDE {
225 DCHECK(interstitial_page_ == interstitial);
226 interstitial_page_ = NULL;
230 TestInterstitialPage* interstitial_page_;
233 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
235 WebContentsImplTestBrowserClient()
236 : assign_site_for_url_(false) {}
238 virtual ~WebContentsImplTestBrowserClient() {}
240 virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
241 return assign_site_for_url_;
244 void set_assign_site_for_url(bool assign) {
245 assign_site_for_url_ = assign;
249 bool assign_site_for_url_;
252 class WebContentsImplTest : public RenderViewHostImplTestHarness {
254 virtual void SetUp() {
255 RenderViewHostImplTestHarness::SetUp();
256 WebUIControllerFactory::RegisterFactory(&factory_);
259 virtual void TearDown() {
260 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
261 RenderViewHostImplTestHarness::TearDown();
265 WebContentsImplTestWebUIControllerFactory factory_;
268 class TestWebContentsObserver : public WebContentsObserver {
270 explicit TestWebContentsObserver(WebContents* contents)
271 : WebContentsObserver(contents) {
273 virtual ~TestWebContentsObserver() {}
275 virtual void DidFinishLoad(int64 frame_id,
276 const GURL& validated_url,
278 RenderViewHost* render_view_host) OVERRIDE {
279 last_url_ = validated_url;
281 virtual void DidFailLoad(int64 frame_id,
282 const GURL& validated_url,
285 const base::string16& error_description,
286 RenderViewHost* render_view_host) OVERRIDE {
287 last_url_ = validated_url;
290 const GURL& last_url() const { return last_url_; }
295 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
298 // Pretends to be a normal browser that receives toggles and transitions to/from
299 // a fullscreened state.
300 class FakeFullscreenDelegate : public WebContentsDelegate {
302 FakeFullscreenDelegate() : fullscreened_contents_(NULL) {}
303 virtual ~FakeFullscreenDelegate() {}
305 virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
306 bool enter_fullscreen) OVERRIDE {
307 fullscreened_contents_ = enter_fullscreen ? web_contents : NULL;
310 virtual bool IsFullscreenForTabOrPending(const WebContents* web_contents)
312 return fullscreened_contents_ && web_contents == fullscreened_contents_;
316 WebContents* fullscreened_contents_;
318 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate);
321 class FakeValidationMessageDelegate : public WebContentsDelegate {
323 FakeValidationMessageDelegate()
324 : hide_validation_message_was_called_(false) {}
325 virtual ~FakeValidationMessageDelegate() {}
327 virtual void HideValidationMessage(WebContents* web_contents) OVERRIDE {
328 hide_validation_message_was_called_ = true;
331 bool hide_validation_message_was_called() const {
332 return hide_validation_message_was_called_;
336 bool hide_validation_message_was_called_;
338 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate);
343 // Test to make sure that title updates get stripped of whitespace.
344 TEST_F(WebContentsImplTest, UpdateTitle) {
345 NavigationControllerImpl& cont =
346 static_cast<NavigationControllerImpl&>(controller());
347 FrameHostMsg_DidCommitProvisionalLoad_Params params;
349 ¶ms, 0, GURL(url::kAboutBlankURL), PAGE_TRANSITION_TYPED);
351 LoadCommittedDetails details;
352 cont.RendererDidNavigate(main_test_rfh(), params, &details);
354 contents()->UpdateTitle(main_test_rfh(), 0,
355 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
356 base::i18n::LEFT_TO_RIGHT);
357 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
360 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
361 const GURL kGURL("chrome://blah");
362 controller().LoadURL(
363 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
364 EXPECT_EQ(base::string16(), contents()->GetTitle());
367 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
368 const GURL kGURL("chrome://blah");
369 const base::string16 title = base::ASCIIToUTF16("My Title");
370 controller().LoadURL(
371 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
373 NavigationEntry* entry = controller().GetVisibleEntry();
374 ASSERT_EQ(kGURL, entry->GetURL());
375 entry->SetTitle(title);
377 EXPECT_EQ(title, contents()->GetTitle());
380 // Test view source mode for a webui page.
381 TEST_F(WebContentsImplTest, NTPViewSource) {
382 NavigationControllerImpl& cont =
383 static_cast<NavigationControllerImpl&>(controller());
384 const char kUrl[] = "view-source:chrome://blah";
385 const GURL kGURL(kUrl);
387 process()->sink().ClearMessages();
390 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
391 rvh()->GetDelegate()->RenderViewCreated(rvh());
392 // Did we get the expected message?
393 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
394 ViewMsg_EnableViewSourceMode::ID));
396 FrameHostMsg_DidCommitProvisionalLoad_Params params;
397 InitNavigateParams(¶ms, 0, kGURL, PAGE_TRANSITION_TYPED);
398 LoadCommittedDetails details;
399 cont.RendererDidNavigate(main_test_rfh(), params, &details);
400 // Also check title and url.
401 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
404 // Test to ensure UpdateMaxPageID is working properly.
405 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
406 SiteInstance* instance1 = contents()->GetSiteInstance();
407 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
410 EXPECT_EQ(-1, contents()->GetMaxPageID());
411 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
412 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
414 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
415 contents()->UpdateMaxPageID(3);
416 contents()->UpdateMaxPageID(1);
417 EXPECT_EQ(3, contents()->GetMaxPageID());
418 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
419 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
421 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
422 EXPECT_EQ(3, contents()->GetMaxPageID());
423 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
424 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
427 // Test simple same-SiteInstance navigation.
428 TEST_F(WebContentsImplTest, SimpleNavigation) {
429 TestRenderViewHost* orig_rvh = test_rvh();
430 SiteInstance* instance1 = contents()->GetSiteInstance();
431 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
434 const GURL url("http://www.google.com");
435 controller().LoadURL(
436 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
437 EXPECT_FALSE(contents()->cross_navigation_pending());
438 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
439 // Controller's pending entry will have a NULL site instance until we assign
440 // it in DidNavigate.
442 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
443 site_instance() == NULL);
445 // DidNavigate from the page
446 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
447 EXPECT_FALSE(contents()->cross_navigation_pending());
448 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
449 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
450 // Controller's entry should now have the SiteInstance, or else we won't be
451 // able to find it later.
454 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
458 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
459 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
460 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
461 const GURL url(std::string("http://example.org/").append(
462 GetMaxURLChars() + 1, 'a'));
464 controller().LoadURL(
465 url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
466 EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
469 // Test that navigating across a site boundary creates a new RenderViewHost
470 // with a new SiteInstance. Going back should do the same.
471 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
472 TestRenderViewHost* orig_rvh = test_rvh();
473 RenderFrameHostImpl* orig_rfh =
474 contents()->GetFrameTree()->root()->current_frame_host();
475 int orig_rvh_delete_count = 0;
476 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
477 SiteInstance* instance1 = contents()->GetSiteInstance();
479 // Navigate to URL. First URL should use first RenderViewHost.
480 const GURL url("http://www.google.com");
481 controller().LoadURL(
482 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
483 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
485 // Keep the number of active views in orig_rvh's SiteInstance
486 // non-zero so that orig_rvh doesn't get deleted when it gets
488 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
489 increment_active_view_count();
491 EXPECT_FALSE(contents()->cross_navigation_pending());
492 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
493 EXPECT_EQ(url, contents()->GetLastCommittedURL());
494 EXPECT_EQ(url, contents()->GetVisibleURL());
496 // Navigate to new site
497 const GURL url2("http://www.yahoo.com");
498 controller().LoadURL(
499 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
500 EXPECT_TRUE(contents()->cross_navigation_pending());
501 EXPECT_EQ(url, contents()->GetLastCommittedURL());
502 EXPECT_EQ(url2, contents()->GetVisibleURL());
503 TestRenderViewHost* pending_rvh =
504 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
505 int pending_rvh_delete_count = 0;
506 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
507 RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()->
508 render_manager()->pending_frame_host();
510 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
511 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
512 orig_rvh->SendBeforeUnloadACK(true);
513 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
515 // DidNavigate from the pending page
516 contents()->TestDidNavigate(
517 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
518 SiteInstance* instance2 = contents()->GetSiteInstance();
520 // Keep the number of active views in pending_rvh's SiteInstance
521 // non-zero so that orig_rvh doesn't get deleted when it gets
523 static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
524 increment_active_view_count();
526 EXPECT_FALSE(contents()->cross_navigation_pending());
527 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
528 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
529 EXPECT_EQ(url2, contents()->GetVisibleURL());
530 EXPECT_NE(instance1, instance2);
531 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
532 // We keep the original RFH around, swapped out.
533 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
535 EXPECT_EQ(orig_rvh_delete_count, 0);
537 // Going back should switch SiteInstances again. The first SiteInstance is
538 // stored in the NavigationEntry, so it should be the same as at the start.
539 // We should use the same RVH as before, swapping it back in.
540 controller().GoBack();
541 TestRenderViewHost* goback_rvh =
542 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
543 EXPECT_EQ(orig_rvh, goback_rvh);
544 EXPECT_TRUE(contents()->cross_navigation_pending());
546 // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
547 EXPECT_TRUE(goback_rvh->are_navigations_suspended());
548 pending_rvh->SendBeforeUnloadACK(true);
549 EXPECT_FALSE(goback_rvh->are_navigations_suspended());
551 // DidNavigate from the back action
552 contents()->TestDidNavigate(
553 goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
554 EXPECT_FALSE(contents()->cross_navigation_pending());
555 EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
556 EXPECT_EQ(instance1, contents()->GetSiteInstance());
557 // The pending RFH should now be swapped out, not deleted.
558 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
559 IsOnSwappedOutList(pending_rfh));
560 EXPECT_EQ(pending_rvh_delete_count, 0);
561 pending_rvh->OnSwappedOut(false);
563 // Close contents and ensure RVHs are deleted.
565 EXPECT_EQ(orig_rvh_delete_count, 1);
566 EXPECT_EQ(pending_rvh_delete_count, 1);
569 // Test that navigating across a site boundary after a crash creates a new
570 // RVH without requiring a cross-site transition (i.e., PENDING state).
571 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
572 TestRenderViewHost* orig_rvh = test_rvh();
573 int orig_rvh_delete_count = 0;
574 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
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 EXPECT_FALSE(contents()->cross_navigation_pending());
584 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
586 // Crash the renderer.
587 orig_rvh->set_render_view_created(false);
589 // Navigate to new site. We should not go into PENDING.
590 const GURL url2("http://www.yahoo.com");
591 controller().LoadURL(
592 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
593 RenderViewHost* new_rvh = rvh();
594 EXPECT_FALSE(contents()->cross_navigation_pending());
595 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
596 EXPECT_NE(orig_rvh, new_rvh);
597 EXPECT_EQ(orig_rvh_delete_count, 1);
599 // DidNavigate from the new page
600 contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
601 SiteInstance* instance2 = contents()->GetSiteInstance();
603 EXPECT_FALSE(contents()->cross_navigation_pending());
604 EXPECT_EQ(new_rvh, rvh());
605 EXPECT_NE(instance1, instance2);
606 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
608 // Close contents and ensure RVHs are deleted.
610 EXPECT_EQ(orig_rvh_delete_count, 1);
613 // Test that opening a new contents in the same SiteInstance and then navigating
614 // both contentses to a new site will place both contentses in a single
616 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
617 TestRenderViewHost* orig_rvh = test_rvh();
618 SiteInstance* instance1 = contents()->GetSiteInstance();
620 // Navigate to URL. First URL should use first RenderViewHost.
621 const GURL url("http://www.google.com");
622 controller().LoadURL(
623 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
624 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
626 // Open a new contents with the same SiteInstance, navigated to the same site.
627 scoped_ptr<TestWebContents> contents2(
628 TestWebContents::Create(browser_context(), instance1));
629 contents2->GetController().LoadURL(url, Referrer(),
630 PAGE_TRANSITION_TYPED,
632 // Need this page id to be 2 since the site instance is the same (which is the
633 // scope of page IDs) and we want to consider this a new page.
634 contents2->TestDidNavigate(
635 contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
637 // Navigate first contents to a new site.
638 const GURL url2a("http://www.yahoo.com");
639 controller().LoadURL(
640 url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
641 orig_rvh->SendBeforeUnloadACK(true);
642 TestRenderViewHost* pending_rvh_a =
643 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
644 contents()->TestDidNavigate(
645 pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
646 SiteInstance* instance2a = contents()->GetSiteInstance();
647 EXPECT_NE(instance1, instance2a);
649 // Navigate second contents to the same site as the first tab.
650 const GURL url2b("http://mail.yahoo.com");
651 contents2->GetController().LoadURL(url2b, Referrer(),
652 PAGE_TRANSITION_TYPED,
654 TestRenderViewHost* rvh2 =
655 static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
656 rvh2->SendBeforeUnloadACK(true);
657 TestRenderViewHost* pending_rvh_b =
658 static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
659 EXPECT_TRUE(pending_rvh_b != NULL);
660 EXPECT_TRUE(contents2->cross_navigation_pending());
662 // NOTE(creis): We used to be in danger of showing a crash page here if the
663 // second contents hadn't navigated somewhere first (bug 1145430). That case
664 // is now covered by the CrossSiteBoundariesAfterCrash test.
665 contents2->TestDidNavigate(
666 pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
667 SiteInstance* instance2b = contents2->GetSiteInstance();
668 EXPECT_NE(instance1, instance2b);
670 // Both contentses should now be in the same SiteInstance.
671 EXPECT_EQ(instance2a, instance2b);
674 TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
675 WebContentsImplTestBrowserClient browser_client;
676 SetBrowserClientForTesting(&browser_client);
678 TestRenderViewHost* orig_rvh = test_rvh();
679 RenderFrameHostImpl* orig_rfh =
680 contents()->GetFrameTree()->root()->current_frame_host();
681 int orig_rvh_delete_count = 0;
682 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
683 SiteInstanceImpl* orig_instance =
684 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
686 browser_client.set_assign_site_for_url(false);
687 // Navigate to an URL that will not assign a new SiteInstance.
688 const GURL native_url("non-site-url://stuffandthings");
689 controller().LoadURL(
690 native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
691 contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
693 EXPECT_FALSE(contents()->cross_navigation_pending());
694 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
695 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
696 EXPECT_EQ(native_url, contents()->GetVisibleURL());
697 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
698 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
699 EXPECT_FALSE(orig_instance->HasSite());
701 browser_client.set_assign_site_for_url(true);
702 // Navigate to new site (should keep same site instance).
703 const GURL url("http://www.google.com");
704 controller().LoadURL(
705 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
706 EXPECT_FALSE(contents()->cross_navigation_pending());
707 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
708 EXPECT_EQ(url, contents()->GetVisibleURL());
709 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
710 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
712 // Keep the number of active views in orig_rvh's SiteInstance
713 // non-zero so that orig_rvh doesn't get deleted when it gets
715 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
716 increment_active_view_count();
718 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
720 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
721 EXPECT_EQ(url, contents()->GetLastCommittedURL());
723 // Navigate to another new site (should create a new site instance).
724 const GURL url2("http://www.yahoo.com");
725 controller().LoadURL(
726 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
727 EXPECT_TRUE(contents()->cross_navigation_pending());
728 EXPECT_EQ(url, contents()->GetLastCommittedURL());
729 EXPECT_EQ(url2, contents()->GetVisibleURL());
730 TestRenderViewHost* pending_rvh =
731 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
732 int pending_rvh_delete_count = 0;
733 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
735 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
736 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
737 orig_rvh->SendBeforeUnloadACK(true);
738 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
740 // DidNavigate from the pending page.
741 contents()->TestDidNavigate(
742 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
743 SiteInstance* new_instance = contents()->GetSiteInstance();
745 EXPECT_FALSE(contents()->cross_navigation_pending());
746 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
747 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
748 EXPECT_EQ(url2, contents()->GetVisibleURL());
749 EXPECT_NE(new_instance, orig_instance);
750 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
751 // We keep the original RFH around, swapped out.
752 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
754 EXPECT_EQ(orig_rvh_delete_count, 0);
755 orig_rvh->OnSwappedOut(false);
757 // Close contents and ensure RVHs are deleted.
759 EXPECT_EQ(orig_rvh_delete_count, 1);
760 EXPECT_EQ(pending_rvh_delete_count, 1);
763 // Test that we can find an opener RVH even if it's pending.
764 // http://crbug.com/176252.
765 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
766 TestRenderViewHost* orig_rvh = test_rvh();
768 // Navigate to a URL.
769 const GURL url("http://www.google.com");
770 controller().LoadURL(
771 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
772 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
774 // Start to navigate first tab to a new site, so that it has a pending RVH.
775 const GURL url2("http://www.yahoo.com");
776 controller().LoadURL(
777 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
778 orig_rvh->SendBeforeUnloadACK(true);
779 TestRenderViewHost* pending_rvh =
780 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
782 // While it is still pending, simulate opening a new tab with the first tab
783 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
784 // on the opener to ensure that an RVH exists.
785 int opener_routing_id = contents()->CreateOpenerRenderViews(
786 pending_rvh->GetSiteInstance());
788 // We should find the pending RVH and not create a new one.
789 EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
792 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
793 // to determine whether a navigation is cross-site.
794 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
795 RenderViewHost* orig_rvh = rvh();
796 SiteInstance* instance1 = contents()->GetSiteInstance();
799 const GURL url("http://www.google.com");
800 controller().LoadURL(
801 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
802 contents()->TestDidNavigate(
803 orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
805 // Open a related contents to a second site.
806 scoped_ptr<TestWebContents> contents2(
807 TestWebContents::Create(browser_context(), instance1));
808 const GURL url2("http://www.yahoo.com");
809 contents2->GetController().LoadURL(url2, Referrer(),
810 PAGE_TRANSITION_TYPED,
812 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
814 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
815 contents2->GetRenderViewHost());
816 EXPECT_FALSE(contents2->cross_navigation_pending());
817 contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
818 SiteInstance* instance2 = contents2->GetSiteInstance();
819 EXPECT_NE(instance1, instance2);
820 EXPECT_FALSE(contents2->cross_navigation_pending());
822 // Simulate a link click in first contents to second site. Doesn't switch
823 // SiteInstances, because we don't intercept WebKit navigations.
824 contents()->TestDidNavigate(
825 orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
826 SiteInstance* instance3 = contents()->GetSiteInstance();
827 EXPECT_EQ(instance1, instance3);
828 EXPECT_FALSE(contents()->cross_navigation_pending());
830 // Navigate to the new site. Doesn't switch SiteInstancees, because we
831 // compare against the current URL, not the SiteInstance's site.
832 const GURL url3("http://mail.yahoo.com");
833 controller().LoadURL(
834 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
835 EXPECT_FALSE(contents()->cross_navigation_pending());
836 contents()->TestDidNavigate(
837 orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
838 SiteInstance* instance4 = contents()->GetSiteInstance();
839 EXPECT_EQ(instance1, instance4);
842 // Test that the onbeforeunload and onunload handlers run when navigating
843 // across site boundaries.
844 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
845 TestRenderViewHost* orig_rvh = test_rvh();
846 SiteInstance* instance1 = contents()->GetSiteInstance();
848 // Navigate to URL. First URL should use first RenderViewHost.
849 const GURL url("http://www.google.com");
850 controller().LoadURL(
851 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
852 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
853 EXPECT_FALSE(contents()->cross_navigation_pending());
854 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
856 // Navigate to new site, but simulate an onbeforeunload denial.
857 const GURL url2("http://www.yahoo.com");
858 controller().LoadURL(
859 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
860 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
861 base::TimeTicks now = base::TimeTicks::Now();
862 orig_rvh->GetMainFrame()->OnMessageReceived(
863 FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
864 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
865 EXPECT_FALSE(contents()->cross_navigation_pending());
866 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
868 // Navigate again, but simulate an onbeforeunload approval.
869 controller().LoadURL(
870 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
871 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
872 now = base::TimeTicks::Now();
873 orig_rvh->GetMainFrame()->OnMessageReceived(
874 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
875 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
876 EXPECT_TRUE(contents()->cross_navigation_pending());
877 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
878 contents()->GetPendingRenderViewHost());
880 // We won't hear DidNavigate until the onunload handler has finished running.
882 // DidNavigate from the pending page.
883 contents()->TestDidNavigate(
884 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
885 SiteInstance* instance2 = contents()->GetSiteInstance();
886 EXPECT_FALSE(contents()->cross_navigation_pending());
887 EXPECT_EQ(pending_rvh, rvh());
888 EXPECT_NE(instance1, instance2);
889 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
892 // Test that during a slow cross-site navigation, the original renderer can
893 // navigate to a different URL and have it displayed, canceling the slow
895 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
896 TestRenderViewHost* orig_rvh = test_rvh();
897 SiteInstance* instance1 = contents()->GetSiteInstance();
899 // Navigate to URL. First URL should use first RenderViewHost.
900 const GURL url("http://www.google.com");
901 controller().LoadURL(
902 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
903 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
904 EXPECT_FALSE(contents()->cross_navigation_pending());
905 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
907 // Navigate to new site, simulating an onbeforeunload approval.
908 const GURL url2("http://www.yahoo.com");
909 controller().LoadURL(
910 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
911 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
912 base::TimeTicks now = base::TimeTicks::Now();
913 orig_rvh->GetMainFrame()->OnMessageReceived(
914 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
915 EXPECT_TRUE(contents()->cross_navigation_pending());
917 // Suppose the original renderer navigates before the new one is ready.
918 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
920 // Verify that the pending navigation is cancelled.
921 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
922 SiteInstance* instance2 = contents()->GetSiteInstance();
923 EXPECT_FALSE(contents()->cross_navigation_pending());
924 EXPECT_EQ(orig_rvh, rvh());
925 EXPECT_EQ(instance1, instance2);
926 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
929 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
930 // Start with a web ui page, which gets a new RVH with WebUI bindings.
931 const GURL url1("chrome://blah");
932 controller().LoadURL(
933 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
934 TestRenderViewHost* ntp_rvh = test_rvh();
935 contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
936 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
937 SiteInstance* instance1 = contents()->GetSiteInstance();
939 EXPECT_FALSE(contents()->cross_navigation_pending());
940 EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
941 EXPECT_EQ(url1, entry1->GetURL());
943 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
944 EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
946 // Navigate to new site.
947 const GURL url2("http://www.google.com");
948 controller().LoadURL(
949 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
950 EXPECT_TRUE(contents()->cross_navigation_pending());
951 TestRenderViewHost* google_rvh =
952 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
954 // Simulate beforeunload approval.
955 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
956 base::TimeTicks now = base::TimeTicks::Now();
957 ntp_rvh->GetMainFrame()->OnMessageReceived(
958 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
960 // DidNavigate from the pending page.
961 contents()->TestDidNavigate(
962 google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
963 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
964 SiteInstance* instance2 = contents()->GetSiteInstance();
966 EXPECT_FALSE(contents()->cross_navigation_pending());
967 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
968 EXPECT_NE(instance1, instance2);
969 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
970 EXPECT_EQ(url2, entry2->GetURL());
972 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
973 EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
975 // Navigate to third page on same site.
976 const GURL url3("http://news.google.com");
977 controller().LoadURL(
978 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
979 EXPECT_FALSE(contents()->cross_navigation_pending());
980 contents()->TestDidNavigate(
981 google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
982 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
983 SiteInstance* instance3 = contents()->GetSiteInstance();
985 EXPECT_FALSE(contents()->cross_navigation_pending());
986 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
987 EXPECT_EQ(instance2, instance3);
988 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
989 EXPECT_EQ(url3, entry3->GetURL());
991 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
993 // Go back within the site.
994 controller().GoBack();
995 EXPECT_FALSE(contents()->cross_navigation_pending());
996 EXPECT_EQ(entry2, controller().GetPendingEntry());
998 // Before that commits, go back again.
999 controller().GoBack();
1000 EXPECT_TRUE(contents()->cross_navigation_pending());
1001 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
1002 EXPECT_EQ(entry1, controller().GetPendingEntry());
1004 // Simulate beforeunload approval.
1005 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
1006 now = base::TimeTicks::Now();
1007 google_rvh->GetMainFrame()->OnMessageReceived(
1008 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1010 // DidNavigate from the first back. This aborts the second back's pending RVH.
1011 contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1013 // We should commit this page and forget about the second back.
1014 EXPECT_FALSE(contents()->cross_navigation_pending());
1015 EXPECT_FALSE(controller().GetPendingEntry());
1016 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
1017 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
1019 // We should not have corrupted the NTP entry.
1020 EXPECT_EQ(instance3,
1021 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1022 EXPECT_EQ(instance2,
1023 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1024 EXPECT_EQ(instance1,
1025 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1026 EXPECT_EQ(url1, entry1->GetURL());
1029 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1030 // original renderer will not cancel the slow navigation (bug 42029).
1031 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
1032 TestRenderViewHost* orig_rvh = test_rvh();
1034 // Navigate to URL. First URL should use first RenderViewHost.
1035 const GURL url("http://www.google.com");
1036 controller().LoadURL(
1037 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1038 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1039 EXPECT_FALSE(contents()->cross_navigation_pending());
1040 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1042 // Start navigating to new site.
1043 const GURL url2("http://www.yahoo.com");
1044 controller().LoadURL(
1045 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1047 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1048 // waiting for a before unload response.
1049 orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
1050 PAGE_TRANSITION_AUTO_SUBFRAME);
1051 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1053 // Now simulate the onbeforeunload approval and verify the navigation is
1055 base::TimeTicks now = base::TimeTicks::Now();
1056 orig_rvh->GetMainFrame()->OnMessageReceived(
1057 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1058 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1059 EXPECT_TRUE(contents()->cross_navigation_pending());
1062 // Test that a cross-site navigation is not preempted if the previous
1063 // renderer sends a FrameNavigate message just before being told to stop.
1064 // We should only preempt the cross-site navigation if the previous renderer
1065 // has started a new navigation. See http://crbug.com/79176.
1066 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1067 // Navigate to NTP URL.
1068 const GURL url("chrome://blah");
1069 controller().LoadURL(
1070 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1071 TestRenderViewHost* orig_rvh = test_rvh();
1072 EXPECT_FALSE(contents()->cross_navigation_pending());
1074 // Navigate to new site, with the beforeunload request in flight.
1075 const GURL url2("http://www.yahoo.com");
1076 controller().LoadURL(
1077 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1078 TestRenderViewHost* pending_rvh =
1079 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1080 EXPECT_TRUE(contents()->cross_navigation_pending());
1081 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1083 // Suppose the first navigation tries to commit now, with a
1084 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1085 // but it should act as if the beforeunload ack arrived.
1086 orig_rvh->SendNavigate(1, GURL("chrome://blah"));
1087 EXPECT_TRUE(contents()->cross_navigation_pending());
1088 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1089 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1091 // The pending navigation should be able to commit successfully.
1092 contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1093 EXPECT_FALSE(contents()->cross_navigation_pending());
1094 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
1097 // Test that the original renderer cannot preempt a cross-site navigation once
1098 // the unload request has been made. At this point, the cross-site navigation
1099 // is almost ready to be displayed, and the original renderer is only given a
1100 // short chance to run an unload handler. Prevents regression of bug 23942.
1101 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
1102 TestRenderViewHost* orig_rvh = test_rvh();
1103 SiteInstance* instance1 = contents()->GetSiteInstance();
1105 // Navigate to URL. First URL should use first RenderViewHost.
1106 const GURL url("http://www.google.com");
1107 controller().LoadURL(
1108 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1109 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1110 EXPECT_FALSE(contents()->cross_navigation_pending());
1111 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1113 // Navigate to new site, simulating an onbeforeunload approval.
1114 const GURL url2("http://www.yahoo.com");
1115 controller().LoadURL(
1116 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1117 base::TimeTicks now = base::TimeTicks::Now();
1118 orig_rvh->GetMainFrame()->OnMessageReceived(
1119 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1120 EXPECT_TRUE(contents()->cross_navigation_pending());
1121 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
1122 contents()->GetPendingRenderViewHost());
1124 // Simulate the pending renderer's response, which leads to an unload request
1125 // being sent to orig_rvh.
1126 std::vector<GURL> url_chain;
1127 url_chain.push_back(GURL());
1128 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1129 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1130 GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
1131 url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
1133 // Suppose the original renderer navigates now, while the unload request is in
1134 // flight. We should ignore it, wait for the unload ack, and let the pending
1135 // request continue. Otherwise, the contents may close spontaneously or stop
1136 // responding to navigation requests. (See bug 23942.)
1137 FrameHostMsg_DidCommitProvisionalLoad_Params params1a;
1138 InitNavigateParams(¶ms1a, 2, GURL("http://www.google.com/foo"),
1139 PAGE_TRANSITION_TYPED);
1140 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1142 // Verify that the pending navigation is still in progress.
1143 EXPECT_TRUE(contents()->cross_navigation_pending());
1144 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
1146 // DidNavigate from the pending page should commit it.
1147 contents()->TestDidNavigate(
1148 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1149 SiteInstance* instance2 = contents()->GetSiteInstance();
1150 EXPECT_FALSE(contents()->cross_navigation_pending());
1151 EXPECT_EQ(pending_rvh, rvh());
1152 EXPECT_NE(instance1, instance2);
1153 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1156 // Test that a cross-site navigation that doesn't commit after the unload
1157 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1158 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1159 TestRenderViewHost* orig_rvh = test_rvh();
1160 SiteInstance* instance1 = contents()->GetSiteInstance();
1162 // Navigate to URL. First URL should use first RenderViewHost.
1163 const GURL url("http://www.google.com");
1164 controller().LoadURL(
1165 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1166 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1167 EXPECT_FALSE(contents()->cross_navigation_pending());
1168 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1170 // Navigate to new site, simulating an onbeforeunload approval.
1171 const GURL url2("http://www.yahoo.com");
1172 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1173 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1174 base::TimeTicks now = base::TimeTicks::Now();
1175 orig_rvh->GetMainFrame()->OnMessageReceived(
1176 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1177 EXPECT_TRUE(contents()->cross_navigation_pending());
1179 // Simulate swap out message when the response arrives.
1180 orig_rvh->OnSwappedOut(false);
1182 // Suppose the navigation doesn't get a chance to commit, and the user
1183 // navigates in the current RVH's SiteInstance.
1184 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1186 // Verify that the pending navigation is cancelled and the renderer is no
1187 // longer swapped out.
1188 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1189 SiteInstance* instance2 = contents()->GetSiteInstance();
1190 EXPECT_FALSE(contents()->cross_navigation_pending());
1191 EXPECT_EQ(orig_rvh, rvh());
1192 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, orig_rvh->rvh_state());
1193 EXPECT_EQ(instance1, instance2);
1194 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1197 // Test that NavigationEntries have the correct page state after going
1198 // forward and back. Prevents regression for bug 1116137.
1199 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1200 TestRenderViewHost* orig_rvh = test_rvh();
1202 // Navigate to URL. There should be no committed entry yet.
1203 const GURL url("http://www.google.com");
1204 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1205 NavigationEntry* entry = controller().GetLastCommittedEntry();
1206 EXPECT_TRUE(entry == NULL);
1208 // Committed entry should have page state after DidNavigate.
1209 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1210 entry = controller().GetLastCommittedEntry();
1211 EXPECT_TRUE(entry->GetPageState().IsValid());
1213 // Navigate to same site.
1214 const GURL url2("http://images.google.com");
1215 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1216 entry = controller().GetLastCommittedEntry();
1217 EXPECT_TRUE(entry->GetPageState().IsValid());
1219 // Committed entry should have page state after DidNavigate.
1220 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1221 entry = controller().GetLastCommittedEntry();
1222 EXPECT_TRUE(entry->GetPageState().IsValid());
1224 // Now go back. Committed entry should still have page state.
1225 controller().GoBack();
1226 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1227 entry = controller().GetLastCommittedEntry();
1228 EXPECT_TRUE(entry->GetPageState().IsValid());
1231 // Test that NavigationEntries have the correct page state and SiteInstance
1232 // state after opening a new window to about:blank. Prevents regression for
1233 // bugs b/1116137 and http://crbug.com/111975.
1234 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1235 TestRenderViewHost* orig_rvh = test_rvh();
1237 // When opening a new window, it is navigated to about:blank internally.
1238 // Currently, this results in two DidNavigate events.
1239 const GURL url(url::kAboutBlankURL);
1240 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1241 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1243 // Should have a page state here.
1244 NavigationEntry* entry = controller().GetLastCommittedEntry();
1245 EXPECT_TRUE(entry->GetPageState().IsValid());
1247 // The SiteInstance should be available for other navigations to use.
1248 NavigationEntryImpl* entry_impl =
1249 NavigationEntryImpl::FromNavigationEntry(entry);
1250 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1251 int32 site_instance_id = entry_impl->site_instance()->GetId();
1253 // Navigating to a normal page should not cause a process swap.
1254 const GURL new_url("http://www.google.com");
1255 controller().LoadURL(new_url, Referrer(),
1256 PAGE_TRANSITION_TYPED, std::string());
1257 EXPECT_FALSE(contents()->cross_navigation_pending());
1258 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1259 contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1260 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1261 controller().GetLastCommittedEntry());
1262 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1263 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1266 // Tests that fullscreen is exited throughout the object hierarchy when
1267 // navigating to a new page.
1268 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
1269 FakeFullscreenDelegate fake_delegate;
1270 contents()->SetDelegate(&fake_delegate);
1271 TestRenderViewHost* orig_rvh = test_rvh();
1273 // Navigate to a site.
1274 const GURL url("http://www.google.com");
1275 controller().LoadURL(
1276 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1277 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1278 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1280 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1281 EXPECT_FALSE(orig_rvh->IsFullscreen());
1282 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1283 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1284 orig_rvh->OnMessageReceived(
1285 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1286 EXPECT_TRUE(orig_rvh->IsFullscreen());
1287 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1288 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1290 // Navigate to a new site.
1291 const GURL url2("http://www.yahoo.com");
1292 controller().LoadURL(
1293 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1294 RenderViewHost* const pending_rvh = contents()->GetPendingRenderViewHost();
1295 contents()->TestDidNavigate(
1296 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1298 // Confirm fullscreen has exited.
1299 EXPECT_FALSE(orig_rvh->IsFullscreen());
1300 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1301 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1303 contents()->SetDelegate(NULL);
1306 // Tests that fullscreen is exited throughout the object hierarchy when
1307 // instructing NavigationController to GoBack() or GoForward().
1308 TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
1309 FakeFullscreenDelegate fake_delegate;
1310 contents()->SetDelegate(&fake_delegate);
1311 TestRenderViewHost* const orig_rvh = test_rvh();
1313 // Navigate to a site.
1314 const GURL url("http://www.google.com");
1315 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1316 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1317 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1319 // Now, navigate to another page on the same site.
1320 const GURL url2("http://www.google.com/search?q=kittens");
1321 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1322 EXPECT_FALSE(contents()->cross_navigation_pending());
1323 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1324 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1326 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1327 EXPECT_FALSE(orig_rvh->IsFullscreen());
1328 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1329 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1331 for (int i = 0; i < 2; ++i) {
1332 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1333 orig_rvh->OnMessageReceived(
1334 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1335 EXPECT_TRUE(orig_rvh->IsFullscreen());
1336 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1337 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1339 // Navigate backward (or forward).
1341 controller().GoBack();
1343 controller().GoForward();
1344 EXPECT_FALSE(contents()->cross_navigation_pending());
1345 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1346 contents()->TestDidNavigate(
1347 orig_rvh, i + 1, url, PAGE_TRANSITION_FORWARD_BACK);
1349 // Confirm fullscreen has exited.
1350 EXPECT_FALSE(orig_rvh->IsFullscreen());
1351 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1352 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1355 contents()->SetDelegate(NULL);
1358 TEST_F(WebContentsImplTest, TerminateHidesValidationMessage) {
1359 FakeValidationMessageDelegate fake_delegate;
1360 contents()->SetDelegate(&fake_delegate);
1361 EXPECT_FALSE(fake_delegate.hide_validation_message_was_called());
1363 // Crash the renderer.
1364 test_rvh()->OnMessageReceived(
1365 ViewHostMsg_RenderProcessGone(
1366 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1368 // Confirm HideValidationMessage was called.
1369 EXPECT_TRUE(fake_delegate.hide_validation_message_was_called());
1371 contents()->SetDelegate(NULL);
1374 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1376 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
1377 FakeFullscreenDelegate fake_delegate;
1378 contents()->SetDelegate(&fake_delegate);
1380 // Navigate to a site.
1381 const GURL url("http://www.google.com");
1382 controller().LoadURL(
1383 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1384 contents()->TestDidNavigate(test_rvh(), 1, url, PAGE_TRANSITION_TYPED);
1385 EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
1387 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1388 EXPECT_FALSE(test_rvh()->IsFullscreen());
1389 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1390 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1391 test_rvh()->OnMessageReceived(
1392 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1393 EXPECT_TRUE(test_rvh()->IsFullscreen());
1394 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1395 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1397 // Crash the renderer.
1398 test_rvh()->OnMessageReceived(
1399 ViewHostMsg_RenderProcessGone(
1400 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1402 // Confirm fullscreen has exited.
1403 EXPECT_FALSE(test_rvh()->IsFullscreen());
1404 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1405 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1407 contents()->SetDelegate(NULL);
1410 ////////////////////////////////////////////////////////////////////////////////
1411 // Interstitial Tests
1412 ////////////////////////////////////////////////////////////////////////////////
1414 // Test navigating to a page (with the navigation initiated from the browser,
1415 // as when a URL is typed in the location bar) that shows an interstitial and
1416 // creates a new navigation entry, then hiding it without proceeding.
1417 TEST_F(WebContentsImplTest,
1418 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1419 // Navigate to a page.
1420 GURL url1("http://www.google.com");
1421 test_rvh()->SendNavigate(1, url1);
1422 EXPECT_EQ(1, controller().GetEntryCount());
1424 // Initiate a browser navigation that will trigger the interstitial
1425 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1426 PAGE_TRANSITION_TYPED, std::string());
1428 // Show an interstitial.
1429 TestInterstitialPage::InterstitialState state =
1430 TestInterstitialPage::INVALID;
1431 bool deleted = false;
1432 GURL url2("http://interstitial");
1433 TestInterstitialPage* interstitial =
1434 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1435 TestInterstitialPageStateGuard state_guard(interstitial);
1436 interstitial->Show();
1437 // The interstitial should not show until its navigation has committed.
1438 EXPECT_FALSE(interstitial->is_showing());
1439 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1440 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1441 // Let's commit the interstitial navigation.
1442 interstitial->TestDidNavigate(1, url2);
1443 EXPECT_TRUE(interstitial->is_showing());
1444 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1445 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1446 NavigationEntry* entry = controller().GetVisibleEntry();
1447 ASSERT_TRUE(entry != NULL);
1448 EXPECT_TRUE(entry->GetURL() == url2);
1450 // Now don't proceed.
1451 interstitial->DontProceed();
1452 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1453 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1454 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1455 entry = controller().GetVisibleEntry();
1456 ASSERT_TRUE(entry != NULL);
1457 EXPECT_TRUE(entry->GetURL() == url1);
1458 EXPECT_EQ(1, controller().GetEntryCount());
1460 RunAllPendingInMessageLoop();
1461 EXPECT_TRUE(deleted);
1464 // Test navigating to a page (with the navigation initiated from the renderer,
1465 // as when clicking on a link in the page) that shows an interstitial and
1466 // creates a new navigation entry, then hiding it without proceeding.
1467 TEST_F(WebContentsImplTest,
1468 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1469 // Navigate to a page.
1470 GURL url1("http://www.google.com");
1471 test_rvh()->SendNavigate(1, url1);
1472 EXPECT_EQ(1, controller().GetEntryCount());
1474 // Show an interstitial (no pending entry, the interstitial would have been
1475 // triggered by clicking on a link).
1476 TestInterstitialPage::InterstitialState state =
1477 TestInterstitialPage::INVALID;
1478 bool deleted = false;
1479 GURL url2("http://interstitial");
1480 TestInterstitialPage* interstitial =
1481 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1482 TestInterstitialPageStateGuard state_guard(interstitial);
1483 interstitial->Show();
1484 // The interstitial should not show until its navigation has committed.
1485 EXPECT_FALSE(interstitial->is_showing());
1486 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1487 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1488 // Let's commit the interstitial navigation.
1489 interstitial->TestDidNavigate(1, url2);
1490 EXPECT_TRUE(interstitial->is_showing());
1491 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1492 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1493 NavigationEntry* entry = controller().GetVisibleEntry();
1494 ASSERT_TRUE(entry != NULL);
1495 EXPECT_TRUE(entry->GetURL() == url2);
1497 // Now don't proceed.
1498 interstitial->DontProceed();
1499 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1500 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1501 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1502 entry = controller().GetVisibleEntry();
1503 ASSERT_TRUE(entry != NULL);
1504 EXPECT_TRUE(entry->GetURL() == url1);
1505 EXPECT_EQ(1, controller().GetEntryCount());
1507 RunAllPendingInMessageLoop();
1508 EXPECT_TRUE(deleted);
1511 // Test navigating to a page that shows an interstitial without creating a new
1512 // navigation entry (this happens when the interstitial is triggered by a
1513 // sub-resource in the page), then hiding it without proceeding.
1514 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1515 // Navigate to a page.
1516 GURL url1("http://www.google.com");
1517 test_rvh()->SendNavigate(1, url1);
1518 EXPECT_EQ(1, controller().GetEntryCount());
1520 // Show an interstitial.
1521 TestInterstitialPage::InterstitialState state =
1522 TestInterstitialPage::INVALID;
1523 bool deleted = false;
1524 GURL url2("http://interstitial");
1525 TestInterstitialPage* interstitial =
1526 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1527 TestInterstitialPageStateGuard state_guard(interstitial);
1528 interstitial->Show();
1529 // The interstitial should not show until its navigation has committed.
1530 EXPECT_FALSE(interstitial->is_showing());
1531 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1532 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1533 // Let's commit the interstitial navigation.
1534 interstitial->TestDidNavigate(1, url2);
1535 EXPECT_TRUE(interstitial->is_showing());
1536 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1537 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1538 NavigationEntry* entry = controller().GetVisibleEntry();
1539 ASSERT_TRUE(entry != NULL);
1540 // The URL specified to the interstitial should have been ignored.
1541 EXPECT_TRUE(entry->GetURL() == url1);
1543 // Now don't proceed.
1544 interstitial->DontProceed();
1545 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1546 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1547 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1548 entry = controller().GetVisibleEntry();
1549 ASSERT_TRUE(entry != NULL);
1550 EXPECT_TRUE(entry->GetURL() == url1);
1551 EXPECT_EQ(1, controller().GetEntryCount());
1553 RunAllPendingInMessageLoop();
1554 EXPECT_TRUE(deleted);
1557 // Test navigating to a page (with the navigation initiated from the browser,
1558 // as when a URL is typed in the location bar) that shows an interstitial and
1559 // creates a new navigation entry, then proceeding.
1560 TEST_F(WebContentsImplTest,
1561 ShowInterstitialFromBrowserNewNavigationProceed) {
1562 // Navigate to a page.
1563 GURL url1("http://www.google.com");
1564 test_rvh()->SendNavigate(1, url1);
1565 EXPECT_EQ(1, controller().GetEntryCount());
1567 // Initiate a browser navigation that will trigger the interstitial
1568 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1569 PAGE_TRANSITION_TYPED, std::string());
1571 // Show an interstitial.
1572 TestInterstitialPage::InterstitialState state =
1573 TestInterstitialPage::INVALID;
1574 bool deleted = false;
1575 GURL url2("http://interstitial");
1576 TestInterstitialPage* interstitial =
1577 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1578 TestInterstitialPageStateGuard state_guard(interstitial);
1579 interstitial->Show();
1580 // The interstitial should not show until its navigation has committed.
1581 EXPECT_FALSE(interstitial->is_showing());
1582 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1583 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1584 // Let's commit the interstitial navigation.
1585 interstitial->TestDidNavigate(1, url2);
1586 EXPECT_TRUE(interstitial->is_showing());
1587 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1588 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1589 NavigationEntry* entry = controller().GetVisibleEntry();
1590 ASSERT_TRUE(entry != NULL);
1591 EXPECT_TRUE(entry->GetURL() == url2);
1594 interstitial->Proceed();
1595 // The interstitial should show until the new navigation commits.
1596 RunAllPendingInMessageLoop();
1597 ASSERT_FALSE(deleted);
1598 EXPECT_EQ(TestInterstitialPage::OKED, state);
1599 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1600 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1602 // Simulate the navigation to the page, that's when the interstitial gets
1604 GURL url3("http://www.thepage.com");
1605 test_rvh()->SendNavigate(2, url3);
1607 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1608 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1609 entry = controller().GetVisibleEntry();
1610 ASSERT_TRUE(entry != NULL);
1611 EXPECT_TRUE(entry->GetURL() == url3);
1613 EXPECT_EQ(2, controller().GetEntryCount());
1615 RunAllPendingInMessageLoop();
1616 EXPECT_TRUE(deleted);
1619 // Test navigating to a page (with the navigation initiated from the renderer,
1620 // as when clicking on a link in the page) that shows an interstitial and
1621 // creates a new navigation entry, then proceeding.
1622 TEST_F(WebContentsImplTest,
1623 ShowInterstitialFromRendererNewNavigationProceed) {
1624 // Navigate to a page.
1625 GURL url1("http://www.google.com");
1626 test_rvh()->SendNavigate(1, url1);
1627 EXPECT_EQ(1, controller().GetEntryCount());
1629 // Show an interstitial.
1630 TestInterstitialPage::InterstitialState state =
1631 TestInterstitialPage::INVALID;
1632 bool deleted = false;
1633 GURL url2("http://interstitial");
1634 TestInterstitialPage* interstitial =
1635 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1636 TestInterstitialPageStateGuard state_guard(interstitial);
1637 interstitial->Show();
1638 // The interstitial should not show until its navigation has committed.
1639 EXPECT_FALSE(interstitial->is_showing());
1640 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1641 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1642 // Let's commit the interstitial navigation.
1643 interstitial->TestDidNavigate(1, url2);
1644 EXPECT_TRUE(interstitial->is_showing());
1645 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1646 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1647 NavigationEntry* entry = controller().GetVisibleEntry();
1648 ASSERT_TRUE(entry != NULL);
1649 EXPECT_TRUE(entry->GetURL() == url2);
1652 interstitial->Proceed();
1653 // The interstitial should show until the new navigation commits.
1654 RunAllPendingInMessageLoop();
1655 ASSERT_FALSE(deleted);
1656 EXPECT_EQ(TestInterstitialPage::OKED, state);
1657 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1658 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1660 // Simulate the navigation to the page, that's when the interstitial gets
1662 GURL url3("http://www.thepage.com");
1663 test_rvh()->SendNavigate(2, url3);
1665 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1666 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1667 entry = controller().GetVisibleEntry();
1668 ASSERT_TRUE(entry != NULL);
1669 EXPECT_TRUE(entry->GetURL() == url3);
1671 EXPECT_EQ(2, controller().GetEntryCount());
1673 RunAllPendingInMessageLoop();
1674 EXPECT_TRUE(deleted);
1677 // Test navigating to a page that shows an interstitial without creating a new
1678 // navigation entry (this happens when the interstitial is triggered by a
1679 // sub-resource in the page), then proceeding.
1680 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1681 // Navigate to a page so we have a navigation entry in the controller.
1682 GURL url1("http://www.google.com");
1683 test_rvh()->SendNavigate(1, url1);
1684 EXPECT_EQ(1, controller().GetEntryCount());
1686 // Show an interstitial.
1687 TestInterstitialPage::InterstitialState state =
1688 TestInterstitialPage::INVALID;
1689 bool deleted = false;
1690 GURL url2("http://interstitial");
1691 TestInterstitialPage* interstitial =
1692 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1693 TestInterstitialPageStateGuard state_guard(interstitial);
1694 interstitial->Show();
1695 // The interstitial should not show until its navigation has committed.
1696 EXPECT_FALSE(interstitial->is_showing());
1697 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1698 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1699 // Let's commit the interstitial navigation.
1700 interstitial->TestDidNavigate(1, url2);
1701 EXPECT_TRUE(interstitial->is_showing());
1702 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1703 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1704 NavigationEntry* entry = controller().GetVisibleEntry();
1705 ASSERT_TRUE(entry != NULL);
1706 // The URL specified to the interstitial should have been ignored.
1707 EXPECT_TRUE(entry->GetURL() == url1);
1710 interstitial->Proceed();
1711 // Since this is not a new navigation, the previous page is dismissed right
1712 // away and shows the original page.
1713 EXPECT_EQ(TestInterstitialPage::OKED, state);
1714 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1715 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1716 entry = controller().GetVisibleEntry();
1717 ASSERT_TRUE(entry != NULL);
1718 EXPECT_TRUE(entry->GetURL() == url1);
1720 EXPECT_EQ(1, controller().GetEntryCount());
1722 RunAllPendingInMessageLoop();
1723 EXPECT_TRUE(deleted);
1726 // Test navigating to a page that shows an interstitial, then navigating away.
1727 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1728 // Show interstitial.
1729 TestInterstitialPage::InterstitialState state =
1730 TestInterstitialPage::INVALID;
1731 bool deleted = false;
1732 GURL url("http://interstitial");
1733 TestInterstitialPage* interstitial =
1734 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1735 TestInterstitialPageStateGuard state_guard(interstitial);
1736 interstitial->Show();
1737 interstitial->TestDidNavigate(1, url);
1739 // While interstitial showing, navigate to a new URL.
1740 const GURL url2("http://www.yahoo.com");
1741 test_rvh()->SendNavigate(1, url2);
1743 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1745 RunAllPendingInMessageLoop();
1746 EXPECT_TRUE(deleted);
1749 // Test navigating to a page that shows an interstitial, then going back.
1750 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1751 // Navigate to a page so we have a navigation entry in the controller.
1752 GURL url1("http://www.google.com");
1753 test_rvh()->SendNavigate(1, url1);
1754 EXPECT_EQ(1, controller().GetEntryCount());
1756 // Show interstitial.
1757 TestInterstitialPage::InterstitialState state =
1758 TestInterstitialPage::INVALID;
1759 bool deleted = false;
1760 GURL interstitial_url("http://interstitial");
1761 TestInterstitialPage* interstitial =
1762 new TestInterstitialPage(contents(), true, interstitial_url,
1764 TestInterstitialPageStateGuard state_guard(interstitial);
1765 interstitial->Show();
1766 interstitial->TestDidNavigate(2, interstitial_url);
1768 // While the interstitial is showing, go back.
1769 controller().GoBack();
1770 test_rvh()->SendNavigate(1, url1);
1772 // Make sure we are back to the original page and that the interstitial is
1774 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1775 NavigationEntry* entry = controller().GetVisibleEntry();
1777 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1779 RunAllPendingInMessageLoop();
1780 EXPECT_TRUE(deleted);
1783 // Test navigating to a page that shows an interstitial, has a renderer crash,
1784 // and then goes back.
1785 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1786 // Navigate to a page so we have a navigation entry in the controller.
1787 GURL url1("http://www.google.com");
1788 test_rvh()->SendNavigate(1, url1);
1789 EXPECT_EQ(1, controller().GetEntryCount());
1791 // Show interstitial.
1792 TestInterstitialPage::InterstitialState state =
1793 TestInterstitialPage::INVALID;
1794 bool deleted = false;
1795 GURL interstitial_url("http://interstitial");
1796 TestInterstitialPage* interstitial =
1797 new TestInterstitialPage(contents(), true, interstitial_url,
1799 TestInterstitialPageStateGuard state_guard(interstitial);
1800 interstitial->Show();
1801 interstitial->TestDidNavigate(2, interstitial_url);
1803 // Crash the renderer
1804 test_rvh()->OnMessageReceived(
1805 ViewHostMsg_RenderProcessGone(
1806 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1808 // While the interstitial is showing, go back.
1809 controller().GoBack();
1810 test_rvh()->SendNavigate(1, url1);
1812 // Make sure we are back to the original page and that the interstitial is
1814 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1815 NavigationEntry* entry = controller().GetVisibleEntry();
1817 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1819 RunAllPendingInMessageLoop();
1820 EXPECT_TRUE(deleted);
1823 // Test navigating to a page that shows an interstitial, has the renderer crash,
1824 // and then navigates to the interstitial.
1825 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1826 // Navigate to a page so we have a navigation entry in the controller.
1827 GURL url1("http://www.google.com");
1828 test_rvh()->SendNavigate(1, url1);
1829 EXPECT_EQ(1, controller().GetEntryCount());
1831 // Show interstitial.
1832 TestInterstitialPage::InterstitialState state =
1833 TestInterstitialPage::INVALID;
1834 bool deleted = false;
1835 GURL interstitial_url("http://interstitial");
1836 TestInterstitialPage* interstitial =
1837 new TestInterstitialPage(contents(), true, interstitial_url,
1839 TestInterstitialPageStateGuard state_guard(interstitial);
1840 interstitial->Show();
1842 // Crash the renderer
1843 test_rvh()->OnMessageReceived(
1844 ViewHostMsg_RenderProcessGone(
1845 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1847 interstitial->TestDidNavigate(2, interstitial_url);
1850 // Test navigating to a page that shows an interstitial, then close the
1852 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1853 // Show interstitial.
1854 TestInterstitialPage::InterstitialState state =
1855 TestInterstitialPage::INVALID;
1856 bool deleted = false;
1857 GURL url("http://interstitial");
1858 TestInterstitialPage* interstitial =
1859 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1860 TestInterstitialPageStateGuard state_guard(interstitial);
1861 interstitial->Show();
1862 interstitial->TestDidNavigate(1, url);
1864 // Now close the contents.
1866 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1868 RunAllPendingInMessageLoop();
1869 EXPECT_TRUE(deleted);
1872 // Test navigating to a page that shows an interstitial, then close the
1874 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1875 // Show interstitial.
1876 TestInterstitialPage::InterstitialState state =
1877 TestInterstitialPage::INVALID;
1878 bool deleted = false;
1879 GURL url("http://interstitial");
1880 TestInterstitialPage* interstitial =
1881 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1882 TestInterstitialPageStateGuard state_guard(interstitial);
1883 interstitial->Show();
1884 interstitial->TestDidNavigate(1, url);
1885 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1886 interstitial->GetRenderViewHostForTesting());
1888 // Now close the contents.
1890 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1892 // Before the interstitial has a chance to process its shutdown task,
1893 // simulate quitting the browser. This goes through all processes and
1894 // tells them to destruct.
1895 rvh->OnMessageReceived(
1896 ViewHostMsg_RenderProcessGone(0, 0, 0));
1898 RunAllPendingInMessageLoop();
1899 EXPECT_TRUE(deleted);
1902 // Test that after Proceed is called and an interstitial is still shown, no more
1903 // commands get executed.
1904 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1905 // Navigate to a page so we have a navigation entry in the controller.
1906 GURL url1("http://www.google.com");
1907 test_rvh()->SendNavigate(1, url1);
1908 EXPECT_EQ(1, controller().GetEntryCount());
1910 // Show an interstitial.
1911 TestInterstitialPage::InterstitialState state =
1912 TestInterstitialPage::INVALID;
1913 bool deleted = false;
1914 GURL url2("http://interstitial");
1915 TestInterstitialPage* interstitial =
1916 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1917 TestInterstitialPageStateGuard state_guard(interstitial);
1918 interstitial->Show();
1919 interstitial->TestDidNavigate(1, url2);
1922 EXPECT_EQ(0, interstitial->command_received_count());
1923 interstitial->TestDomOperationResponse("toto");
1924 EXPECT_EQ(1, interstitial->command_received_count());
1927 interstitial->Proceed();
1928 RunAllPendingInMessageLoop();
1929 ASSERT_FALSE(deleted);
1931 // While the navigation to the new page is pending, send other commands, they
1932 // should be ignored.
1933 interstitial->TestDomOperationResponse("hello");
1934 interstitial->TestDomOperationResponse("hi");
1935 EXPECT_EQ(1, interstitial->command_received_count());
1938 // Test showing an interstitial while another interstitial is already showing.
1939 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1940 // Navigate to a page so we have a navigation entry in the controller.
1941 GURL start_url("http://www.google.com");
1942 test_rvh()->SendNavigate(1, start_url);
1943 EXPECT_EQ(1, controller().GetEntryCount());
1945 // Show an interstitial.
1946 TestInterstitialPage::InterstitialState state1 =
1947 TestInterstitialPage::INVALID;
1948 bool deleted1 = false;
1949 GURL url1("http://interstitial1");
1950 TestInterstitialPage* interstitial1 =
1951 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1952 TestInterstitialPageStateGuard state_guard1(interstitial1);
1953 interstitial1->Show();
1954 interstitial1->TestDidNavigate(1, url1);
1956 // Now show another interstitial.
1957 TestInterstitialPage::InterstitialState state2 =
1958 TestInterstitialPage::INVALID;
1959 bool deleted2 = false;
1960 GURL url2("http://interstitial2");
1961 TestInterstitialPage* interstitial2 =
1962 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1963 TestInterstitialPageStateGuard state_guard2(interstitial2);
1964 interstitial2->Show();
1965 interstitial2->TestDidNavigate(1, url2);
1967 // Showing interstitial2 should have caused interstitial1 to go away.
1968 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1969 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1971 RunAllPendingInMessageLoop();
1972 EXPECT_TRUE(deleted1);
1973 ASSERT_FALSE(deleted2);
1975 // Let's make sure interstitial2 is working as intended.
1976 interstitial2->Proceed();
1977 GURL landing_url("http://www.thepage.com");
1978 test_rvh()->SendNavigate(2, landing_url);
1980 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1981 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1982 NavigationEntry* entry = controller().GetVisibleEntry();
1983 ASSERT_TRUE(entry != NULL);
1984 EXPECT_TRUE(entry->GetURL() == landing_url);
1985 EXPECT_EQ(2, controller().GetEntryCount());
1986 RunAllPendingInMessageLoop();
1987 EXPECT_TRUE(deleted2);
1990 // Test showing an interstitial, proceeding and then navigating to another
1992 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
1993 // Navigate to a page so we have a navigation entry in the controller.
1994 GURL start_url("http://www.google.com");
1995 test_rvh()->SendNavigate(1, start_url);
1996 EXPECT_EQ(1, controller().GetEntryCount());
1998 // Show an interstitial.
1999 TestInterstitialPage::InterstitialState state1 =
2000 TestInterstitialPage::INVALID;
2001 bool deleted1 = false;
2002 GURL url1("http://interstitial1");
2003 TestInterstitialPage* interstitial1 =
2004 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
2005 TestInterstitialPageStateGuard state_guard1(interstitial1);
2006 interstitial1->Show();
2007 interstitial1->TestDidNavigate(1, url1);
2009 // Take action. The interstitial won't be hidden until the navigation is
2011 interstitial1->Proceed();
2012 EXPECT_EQ(TestInterstitialPage::OKED, state1);
2014 // Now show another interstitial (simulating the navigation causing another
2016 TestInterstitialPage::InterstitialState state2 =
2017 TestInterstitialPage::INVALID;
2018 bool deleted2 = false;
2019 GURL url2("http://interstitial2");
2020 TestInterstitialPage* interstitial2 =
2021 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2022 TestInterstitialPageStateGuard state_guard2(interstitial2);
2023 interstitial2->Show();
2024 interstitial2->TestDidNavigate(1, url2);
2026 // Showing interstitial2 should have caused interstitial1 to go away.
2027 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2028 RunAllPendingInMessageLoop();
2029 EXPECT_TRUE(deleted1);
2030 ASSERT_FALSE(deleted2);
2032 // Let's make sure interstitial2 is working as intended.
2033 interstitial2->Proceed();
2034 GURL landing_url("http://www.thepage.com");
2035 test_rvh()->SendNavigate(2, landing_url);
2037 RunAllPendingInMessageLoop();
2038 EXPECT_TRUE(deleted2);
2039 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2040 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
2041 NavigationEntry* entry = controller().GetVisibleEntry();
2042 ASSERT_TRUE(entry != NULL);
2043 EXPECT_TRUE(entry->GetURL() == landing_url);
2044 EXPECT_EQ(2, controller().GetEntryCount());
2047 // Test that navigating away from an interstitial while it's loading cause it
2049 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
2050 // Show an interstitial.
2051 TestInterstitialPage::InterstitialState state =
2052 TestInterstitialPage::INVALID;
2053 bool deleted = false;
2054 GURL interstitial_url("http://interstitial");
2055 TestInterstitialPage* interstitial =
2056 new TestInterstitialPage(contents(), true, interstitial_url,
2058 TestInterstitialPageStateGuard state_guard(interstitial);
2059 interstitial->Show();
2061 // Let's simulate a navigation initiated from the browser before the
2062 // interstitial finishes loading.
2063 const GURL url("http://www.google.com");
2064 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2065 EXPECT_FALSE(interstitial->is_showing());
2066 RunAllPendingInMessageLoop();
2067 ASSERT_FALSE(deleted);
2069 // Now let's make the interstitial navigation commit.
2070 interstitial->TestDidNavigate(1, interstitial_url);
2072 // After it loaded the interstitial should be gone.
2073 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2075 RunAllPendingInMessageLoop();
2076 EXPECT_TRUE(deleted);
2079 // Test that a new request to show an interstitial while an interstitial is
2080 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2081 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
2082 GURL interstitial_url("http://interstitial");
2084 // Show a first interstitial.
2085 TestInterstitialPage::InterstitialState state1 =
2086 TestInterstitialPage::INVALID;
2087 bool deleted1 = false;
2088 TestInterstitialPage* interstitial1 =
2089 new TestInterstitialPage(contents(), true, interstitial_url,
2090 &state1, &deleted1);
2091 TestInterstitialPageStateGuard state_guard1(interstitial1);
2092 interstitial1->Show();
2094 // Show another interstitial on that same contents before the first one had
2096 TestInterstitialPage::InterstitialState state2 =
2097 TestInterstitialPage::INVALID;
2098 bool deleted2 = false;
2099 TestInterstitialPage* interstitial2 =
2100 new TestInterstitialPage(contents(), true, interstitial_url,
2101 &state2, &deleted2);
2102 TestInterstitialPageStateGuard state_guard2(interstitial2);
2103 interstitial2->Show();
2105 // The first interstitial should have been closed and deleted.
2106 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2107 // The 2nd one should still be OK.
2108 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2110 RunAllPendingInMessageLoop();
2111 EXPECT_TRUE(deleted1);
2112 ASSERT_FALSE(deleted2);
2114 // Make the interstitial navigation commit it should be showing.
2115 interstitial2->TestDidNavigate(1, interstitial_url);
2116 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
2119 // Test showing an interstitial and have its renderer crash.
2120 TEST_F(WebContentsImplTest, InterstitialCrasher) {
2121 // Show an interstitial.
2122 TestInterstitialPage::InterstitialState state =
2123 TestInterstitialPage::INVALID;
2124 bool deleted = false;
2125 GURL url("http://interstitial");
2126 TestInterstitialPage* interstitial =
2127 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2128 TestInterstitialPageStateGuard state_guard(interstitial);
2129 interstitial->Show();
2130 // Simulate a renderer crash before the interstitial is shown.
2131 interstitial->TestRenderViewTerminated(
2132 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2133 // The interstitial should have been dismissed.
2134 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2135 RunAllPendingInMessageLoop();
2136 EXPECT_TRUE(deleted);
2138 // Now try again but this time crash the intersitial after it was shown.
2140 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2141 interstitial->Show();
2142 interstitial->TestDidNavigate(1, url);
2143 // Simulate a renderer crash.
2144 interstitial->TestRenderViewTerminated(
2145 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2146 // The interstitial should have been dismissed.
2147 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2148 RunAllPendingInMessageLoop();
2149 EXPECT_TRUE(deleted);
2152 // Tests that showing an interstitial as a result of a browser initiated
2153 // navigation while an interstitial is showing does not remove the pending
2154 // entry (see http://crbug.com/9791).
2155 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
2156 const char kUrl[] = "http://www.badguys.com/";
2157 const GURL kGURL(kUrl);
2159 // Start a navigation to a page
2160 contents()->GetController().LoadURL(
2161 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2163 // Simulate that navigation triggering an interstitial.
2164 TestInterstitialPage::InterstitialState state =
2165 TestInterstitialPage::INVALID;
2166 bool deleted = false;
2167 TestInterstitialPage* interstitial =
2168 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2169 TestInterstitialPageStateGuard state_guard(interstitial);
2170 interstitial->Show();
2171 interstitial->TestDidNavigate(1, kGURL);
2173 // Initiate a new navigation from the browser that also triggers an
2175 contents()->GetController().LoadURL(
2176 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2177 TestInterstitialPage::InterstitialState state2 =
2178 TestInterstitialPage::INVALID;
2179 bool deleted2 = false;
2180 TestInterstitialPage* interstitial2 =
2181 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
2182 TestInterstitialPageStateGuard state_guard2(interstitial2);
2183 interstitial2->Show();
2184 interstitial2->TestDidNavigate(1, kGURL);
2186 // Make sure we still have an entry.
2187 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2189 EXPECT_EQ(kUrl, entry->GetURL().spec());
2191 // And that the first interstitial is gone, but not the second.
2192 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2193 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2194 RunAllPendingInMessageLoop();
2195 EXPECT_TRUE(deleted);
2196 EXPECT_FALSE(deleted2);
2199 // Tests that Javascript messages are not shown while an interstitial is
2201 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2202 const char kUrl[] = "http://www.badguys.com/";
2203 const GURL kGURL(kUrl);
2205 // Start a navigation to a page
2206 contents()->GetController().LoadURL(
2207 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2208 // DidNavigate from the page
2209 contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
2211 // Simulate showing an interstitial while the page is showing.
2212 TestInterstitialPage::InterstitialState state =
2213 TestInterstitialPage::INVALID;
2214 bool deleted = false;
2215 TestInterstitialPage* interstitial =
2216 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2217 TestInterstitialPageStateGuard state_guard(interstitial);
2218 interstitial->Show();
2219 interstitial->TestDidNavigate(1, kGURL);
2221 // While the interstitial is showing, let's simulate the hidden page
2222 // attempting to show a JS message.
2223 IPC::Message* dummy_message = new IPC::Message;
2224 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2225 base::ASCIIToUTF16("This is an informative message"),
2226 base::ASCIIToUTF16("OK"),
2227 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message);
2228 EXPECT_TRUE(contents()->last_dialog_suppressed_);
2231 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2232 // interstitial it isn't copied over to the destination.
2233 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2234 // Navigate to a page.
2235 GURL url1("http://www.google.com");
2236 test_rvh()->SendNavigate(1, url1);
2237 EXPECT_EQ(1, controller().GetEntryCount());
2239 // Initiate a browser navigation that will trigger the interstitial
2240 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2241 PAGE_TRANSITION_TYPED, std::string());
2243 // Show an interstitial.
2244 TestInterstitialPage::InterstitialState state =
2245 TestInterstitialPage::INVALID;
2246 bool deleted = false;
2247 GURL url2("http://interstitial");
2248 TestInterstitialPage* interstitial =
2249 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2250 TestInterstitialPageStateGuard state_guard(interstitial);
2251 interstitial->Show();
2252 interstitial->TestDidNavigate(1, url2);
2253 EXPECT_TRUE(interstitial->is_showing());
2254 EXPECT_EQ(2, controller().GetEntryCount());
2256 // Create another NavigationController.
2257 GURL url3("http://foo2");
2258 scoped_ptr<TestWebContents> other_contents(
2259 static_cast<TestWebContents*>(CreateTestWebContents()));
2260 NavigationControllerImpl& other_controller = other_contents->GetController();
2261 other_contents->NavigateAndCommit(url3);
2262 other_contents->ExpectSetHistoryLengthAndPrune(
2263 NavigationEntryImpl::FromNavigationEntry(
2264 other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2265 other_controller.GetEntryAtIndex(0)->GetPageID());
2266 other_controller.CopyStateFromAndPrune(&controller(), false);
2268 // The merged controller should only have two entries: url1 and url2.
2269 ASSERT_EQ(2, other_controller.GetEntryCount());
2270 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2271 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2272 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2274 // And the merged controller shouldn't be showing an interstitial.
2275 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2278 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2279 // showing an interstitial.
2280 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2281 // Navigate to a page.
2282 GURL url1("http://www.google.com");
2283 contents()->NavigateAndCommit(url1);
2285 // Create another NavigationController.
2286 scoped_ptr<TestWebContents> other_contents(
2287 static_cast<TestWebContents*>(CreateTestWebContents()));
2288 NavigationControllerImpl& other_controller = other_contents->GetController();
2290 // Navigate it to url2.
2291 GURL url2("http://foo2");
2292 other_contents->NavigateAndCommit(url2);
2294 // Show an interstitial.
2295 TestInterstitialPage::InterstitialState state =
2296 TestInterstitialPage::INVALID;
2297 bool deleted = false;
2298 GURL url3("http://interstitial");
2299 TestInterstitialPage* interstitial =
2300 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2302 TestInterstitialPageStateGuard state_guard(interstitial);
2303 interstitial->Show();
2304 interstitial->TestDidNavigate(1, url3);
2305 EXPECT_TRUE(interstitial->is_showing());
2306 EXPECT_EQ(2, other_controller.GetEntryCount());
2308 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2309 // interstitial is showing in the target.
2310 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2313 // Regression test for http://crbug.com/168611 - the URLs passed by the
2314 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2315 TEST_F(WebContentsImplTest, FilterURLs) {
2316 TestWebContentsObserver observer(contents());
2318 // A navigation to about:whatever should always look like a navigation to
2320 GURL url_normalized(url::kAboutBlankURL);
2321 GURL url_from_ipc("about:whatever");
2323 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2324 // will use the given URL to create the NavigationEntry as well, and that
2325 // entry should contain the filtered URL.
2326 contents()->NavigateAndCommit(url_normalized);
2328 // Check that an IPC with about:whatever is correctly normalized.
2329 contents()->TestDidFinishLoad(url_from_ipc);
2331 EXPECT_EQ(url_normalized, observer.last_url());
2333 // Create and navigate another WebContents.
2334 scoped_ptr<TestWebContents> other_contents(
2335 static_cast<TestWebContents*>(CreateTestWebContents()));
2336 TestWebContentsObserver other_observer(other_contents.get());
2337 other_contents->NavigateAndCommit(url_normalized);
2339 // Check that an IPC with about:whatever is correctly normalized.
2340 other_contents->TestDidFailLoadWithError(
2341 url_from_ipc, 1, base::string16());
2342 EXPECT_EQ(url_normalized, other_observer.last_url());
2345 // Test that if a pending contents is deleted before it is shown, we don't
2347 TEST_F(WebContentsImplTest, PendingContents) {
2348 scoped_ptr<TestWebContents> other_contents(
2349 static_cast<TestWebContents*>(CreateTestWebContents()));
2350 contents()->AddPendingContents(other_contents.get());
2351 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2352 other_contents.reset();
2353 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2356 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
2357 const gfx::Size original_preferred_size(1024, 768);
2358 contents()->UpdatePreferredSize(original_preferred_size);
2360 // With no capturers, expect the preferred size to be the one propagated into
2361 // WebContentsImpl via the RenderViewHostDelegate interface.
2362 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2363 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2365 // Increment capturer count, but without specifying a capture size. Expect
2366 // a "not set" preferred size.
2367 contents()->IncrementCapturerCount(gfx::Size());
2368 EXPECT_EQ(1, contents()->GetCapturerCount());
2369 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2371 // Increment capturer count again, but with an overriding capture size.
2372 // Expect preferred size to now be overridden to the capture size.
2373 const gfx::Size capture_size(1280, 720);
2374 contents()->IncrementCapturerCount(capture_size);
2375 EXPECT_EQ(2, contents()->GetCapturerCount());
2376 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2378 // Increment capturer count a third time, but the expect that the preferred
2379 // size is still the first capture size.
2380 const gfx::Size another_capture_size(720, 480);
2381 contents()->IncrementCapturerCount(another_capture_size);
2382 EXPECT_EQ(3, contents()->GetCapturerCount());
2383 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2385 // Decrement capturer count twice, but expect the preferred size to still be
2387 contents()->DecrementCapturerCount();
2388 contents()->DecrementCapturerCount();
2389 EXPECT_EQ(1, contents()->GetCapturerCount());
2390 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2392 // Decrement capturer count, and since the count has dropped to zero, the
2393 // original preferred size should be restored.
2394 contents()->DecrementCapturerCount();
2395 EXPECT_EQ(0, contents()->GetCapturerCount());
2396 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2399 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2401 TEST_F(WebContentsImplTest, GetLastActiveTime) {
2402 // The WebContents starts with a valid creation time.
2403 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2405 // Reset the last active time to a known-bad value.
2406 contents()->last_active_time_ = base::TimeTicks();
2407 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2409 // Simulate activating the WebContents. The active time should update.
2410 contents()->WasShown();
2411 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2414 class ContentsZoomChangedDelegate : public WebContentsDelegate {
2416 ContentsZoomChangedDelegate() :
2417 contents_zoom_changed_call_count_(0),
2418 last_zoom_in_(false) {
2421 int GetAndResetContentsZoomChangedCallCount() {
2422 int count = contents_zoom_changed_call_count_;
2423 contents_zoom_changed_call_count_ = 0;
2427 bool last_zoom_in() const {
2428 return last_zoom_in_;
2431 // WebContentsDelegate:
2432 virtual void ContentsZoomChange(bool zoom_in) OVERRIDE {
2433 contents_zoom_changed_call_count_++;
2434 last_zoom_in_ = zoom_in;
2438 int contents_zoom_changed_call_count_;
2441 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
2444 // Tests that some mouseehweel events get turned into browser zoom requests.
2445 TEST_F(WebContentsImplTest, HandleWheelEvent) {
2446 using blink::WebInputEvent;
2448 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2449 new ContentsZoomChangedDelegate());
2450 contents()->SetDelegate(delegate.get());
2453 // Verify that normal mouse wheel events do nothing to change the zoom level.
2454 blink::WebMouseWheelEvent event =
2455 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2456 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2457 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2459 modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey;
2460 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2461 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2462 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2464 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2465 // Except on MacOS where we never want to adjust zoom with mousewheel.
2466 modifiers = WebInputEvent::ControlKey;
2467 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2468 bool handled = contents()->HandleWheelEvent(event);
2469 #if defined(OS_MACOSX)
2470 EXPECT_FALSE(handled);
2471 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2473 EXPECT_TRUE(handled);
2474 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2475 EXPECT_TRUE(delegate->last_zoom_in());
2478 modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
2479 WebInputEvent::AltKey;
2480 event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false);
2481 handled = contents()->HandleWheelEvent(event);
2482 #if defined(OS_MACOSX)
2483 EXPECT_FALSE(handled);
2484 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2486 EXPECT_TRUE(handled);
2487 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2488 EXPECT_FALSE(delegate->last_zoom_in());
2491 // Unless there is no vertical movement.
2492 event = SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers, false);
2493 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2494 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2496 // Events containing precise scrolling deltas also shouldn't result in the
2497 // zoom being adjusted, to avoid accidental adjustments caused by
2498 // two-finger-scrolling on a touchpad.
2499 modifiers = WebInputEvent::ControlKey;
2500 event = SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers, true);
2501 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2502 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2504 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2505 contents()->SetDelegate(NULL);
2508 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2509 TEST_F(WebContentsImplTest, HandleGestureEvent) {
2510 using blink::WebGestureEvent;
2511 using blink::WebInputEvent;
2513 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2514 new ContentsZoomChangedDelegate());
2515 contents()->SetDelegate(delegate.get());
2517 const float kZoomStepValue = 0.6f;
2518 blink::WebGestureEvent event = SyntheticWebGestureEventBuilder::Build(
2519 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchpad);
2521 // A pinch less than the step value doesn't change the zoom level.
2522 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 0.8f;
2523 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2524 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2526 // But repeating the event so the combined scale is greater does.
2527 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2528 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2529 EXPECT_TRUE(delegate->last_zoom_in());
2531 // Pinching back out one step goes back to 100%.
2532 event.data.pinchUpdate.scale = 1.0f - kZoomStepValue;
2533 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2534 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2535 EXPECT_FALSE(delegate->last_zoom_in());
2537 // Pinching out again doesn't zoom (step is twice as large around 100%).
2538 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2539 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2541 // And again now it zooms once per step.
2542 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2543 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2544 EXPECT_FALSE(delegate->last_zoom_in());
2546 // No other type of gesture event is handled by WebContentsImpl (for example
2547 // a touchscreen pinch gesture).
2548 event = SyntheticWebGestureEventBuilder::Build(
2549 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchscreen);
2550 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 3;
2551 EXPECT_FALSE(contents()->HandleGestureEvent(event));
2552 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2554 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2555 contents()->SetDelegate(NULL);
2558 // Tests that GetRelatedActiveContentsCount is shared between related
2559 // SiteInstances and includes WebContents that have not navigated yet.
2560 TEST_F(WebContentsImplTest, ActiveContentsCountBasic) {
2561 scoped_refptr<SiteInstance> instance1(
2562 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2563 scoped_refptr<SiteInstance> instance2(
2564 instance1->GetRelatedSiteInstance(GURL("http://b.com")));
2566 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2567 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2569 scoped_ptr<TestWebContents> contents1(
2570 TestWebContents::Create(browser_context(), instance1));
2571 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2572 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2574 scoped_ptr<TestWebContents> contents2(
2575 TestWebContents::Create(browser_context(), instance1));
2576 EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount());
2577 EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount());
2580 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2581 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2584 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2585 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2588 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2589 // same-site and cross-site navigations.
2590 TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
2591 scoped_refptr<SiteInstance> instance(
2592 SiteInstance::Create(browser_context()));
2594 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2596 scoped_ptr<TestWebContents> contents(
2597 TestWebContents::Create(browser_context(), instance));
2598 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2600 // Navigate to a URL.
2601 contents->GetController().LoadURL(
2602 GURL("http://a.com/1"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2603 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2604 contents->CommitPendingNavigation();
2605 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2607 // Navigate to a URL in the same site.
2608 contents->GetController().LoadURL(
2609 GURL("http://a.com/2"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2610 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2611 contents->CommitPendingNavigation();
2612 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2614 // Navigate to a URL in a different site.
2615 contents->GetController().LoadURL(
2616 GURL("http://b.com"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2617 EXPECT_TRUE(contents->cross_navigation_pending());
2618 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2619 contents->CommitPendingNavigation();
2620 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2623 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2626 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2628 TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
2629 scoped_refptr<SiteInstance> instance(
2630 SiteInstance::Create(browser_context()));
2632 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2634 scoped_ptr<TestWebContents> contents(
2635 TestWebContents::Create(browser_context(), instance));
2636 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2638 // Navigate to a URL.
2639 contents->NavigateAndCommit(GURL("http://a.com"));
2640 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2642 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2643 contents->GetController().LoadURL(
2644 GURL(kTestWebUIUrl), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2645 EXPECT_TRUE(contents->cross_navigation_pending());
2646 scoped_refptr<SiteInstance> instance_webui(
2647 contents->GetPendingRenderViewHost()->GetSiteInstance());
2648 EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
2650 // At this point, contents still counts for the old BrowsingInstance.
2651 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2652 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2654 // Commit and contents counts for the new one.
2655 contents->CommitPendingNavigation();
2656 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2657 EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount());
2660 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2661 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2664 } // namespace content