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);
323 // Test to make sure that title updates get stripped of whitespace.
324 TEST_F(WebContentsImplTest, UpdateTitle) {
325 NavigationControllerImpl& cont =
326 static_cast<NavigationControllerImpl&>(controller());
327 FrameHostMsg_DidCommitProvisionalLoad_Params params;
328 InitNavigateParams(¶ms, 0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED);
330 LoadCommittedDetails details;
331 cont.RendererDidNavigate(main_test_rfh(), params, &details);
333 contents()->UpdateTitle(rvh(), 0,
334 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
335 base::i18n::LEFT_TO_RIGHT);
336 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
339 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
340 const GURL kGURL("chrome://blah");
341 controller().LoadURL(
342 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
343 EXPECT_EQ(base::string16(), contents()->GetTitle());
346 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
347 const GURL kGURL("chrome://blah");
348 const base::string16 title = base::ASCIIToUTF16("My Title");
349 controller().LoadURL(
350 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
352 NavigationEntry* entry = controller().GetVisibleEntry();
353 ASSERT_EQ(kGURL, entry->GetURL());
354 entry->SetTitle(title);
356 EXPECT_EQ(title, contents()->GetTitle());
359 // Test view source mode for a webui page.
360 TEST_F(WebContentsImplTest, NTPViewSource) {
361 NavigationControllerImpl& cont =
362 static_cast<NavigationControllerImpl&>(controller());
363 const char kUrl[] = "view-source:chrome://blah";
364 const GURL kGURL(kUrl);
366 process()->sink().ClearMessages();
369 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
370 rvh()->GetDelegate()->RenderViewCreated(rvh());
371 // Did we get the expected message?
372 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
373 ViewMsg_EnableViewSourceMode::ID));
375 FrameHostMsg_DidCommitProvisionalLoad_Params params;
376 InitNavigateParams(¶ms, 0, kGURL, PAGE_TRANSITION_TYPED);
377 LoadCommittedDetails details;
378 cont.RendererDidNavigate(main_test_rfh(), params, &details);
379 // Also check title and url.
380 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
383 // Test to ensure UpdateMaxPageID is working properly.
384 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
385 SiteInstance* instance1 = contents()->GetSiteInstance();
386 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
389 EXPECT_EQ(-1, contents()->GetMaxPageID());
390 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
391 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
393 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
394 contents()->UpdateMaxPageID(3);
395 contents()->UpdateMaxPageID(1);
396 EXPECT_EQ(3, contents()->GetMaxPageID());
397 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
398 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
400 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
401 EXPECT_EQ(3, contents()->GetMaxPageID());
402 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
403 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
406 // Test simple same-SiteInstance navigation.
407 TEST_F(WebContentsImplTest, SimpleNavigation) {
408 TestRenderViewHost* orig_rvh = test_rvh();
409 SiteInstance* instance1 = contents()->GetSiteInstance();
410 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
413 const GURL url("http://www.google.com");
414 controller().LoadURL(
415 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
416 EXPECT_FALSE(contents()->cross_navigation_pending());
417 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
418 // Controller's pending entry will have a NULL site instance until we assign
419 // it in DidNavigate.
421 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
422 site_instance() == NULL);
424 // DidNavigate from the page
425 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
426 EXPECT_FALSE(contents()->cross_navigation_pending());
427 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
428 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
429 // Controller's entry should now have the SiteInstance, or else we won't be
430 // able to find it later.
433 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
437 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
438 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
439 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
440 const GURL url(std::string("http://example.org/").append(
441 GetMaxURLChars() + 1, 'a'));
443 controller().LoadURL(
444 url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
445 EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
448 // Test that navigating across a site boundary creates a new RenderViewHost
449 // with a new SiteInstance. Going back should do the same.
450 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
451 contents()->transition_cross_site = true;
452 TestRenderViewHost* orig_rvh = test_rvh();
453 RenderFrameHostImpl* orig_rfh =
454 contents()->GetFrameTree()->root()->current_frame_host();
455 int orig_rvh_delete_count = 0;
456 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
457 SiteInstance* instance1 = contents()->GetSiteInstance();
459 // Navigate to URL. First URL should use first RenderViewHost.
460 const GURL url("http://www.google.com");
461 controller().LoadURL(
462 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
463 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
465 // Keep the number of active views in orig_rvh's SiteInstance
466 // non-zero so that orig_rvh doesn't get deleted when it gets
468 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
469 increment_active_view_count();
471 EXPECT_FALSE(contents()->cross_navigation_pending());
472 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
473 EXPECT_EQ(url, contents()->GetLastCommittedURL());
474 EXPECT_EQ(url, contents()->GetVisibleURL());
476 // Navigate to new site
477 const GURL url2("http://www.yahoo.com");
478 controller().LoadURL(
479 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
480 EXPECT_TRUE(contents()->cross_navigation_pending());
481 EXPECT_EQ(url, contents()->GetLastCommittedURL());
482 EXPECT_EQ(url2, contents()->GetVisibleURL());
483 TestRenderViewHost* pending_rvh =
484 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
485 int pending_rvh_delete_count = 0;
486 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
487 RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()->
488 render_manager()->pending_frame_host();
490 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
491 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
492 orig_rvh->SendBeforeUnloadACK(true);
493 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
495 // DidNavigate from the pending page
496 contents()->TestDidNavigate(
497 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
498 SiteInstance* instance2 = contents()->GetSiteInstance();
500 // Keep the number of active views in pending_rvh's SiteInstance
501 // non-zero so that orig_rvh doesn't get deleted when it gets
503 static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
504 increment_active_view_count();
506 EXPECT_FALSE(contents()->cross_navigation_pending());
507 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
508 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
509 EXPECT_EQ(url2, contents()->GetVisibleURL());
510 EXPECT_NE(instance1, instance2);
511 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
512 // We keep the original RFH around, swapped out.
513 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
515 EXPECT_EQ(orig_rvh_delete_count, 0);
517 // Going back should switch SiteInstances again. The first SiteInstance is
518 // stored in the NavigationEntry, so it should be the same as at the start.
519 // We should use the same RVH as before, swapping it back in.
520 controller().GoBack();
521 TestRenderViewHost* goback_rvh =
522 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
523 EXPECT_EQ(orig_rvh, goback_rvh);
524 EXPECT_TRUE(contents()->cross_navigation_pending());
526 // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
527 EXPECT_TRUE(goback_rvh->are_navigations_suspended());
528 pending_rvh->SendBeforeUnloadACK(true);
529 EXPECT_FALSE(goback_rvh->are_navigations_suspended());
531 // DidNavigate from the back action
532 contents()->TestDidNavigate(
533 goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
534 EXPECT_FALSE(contents()->cross_navigation_pending());
535 EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
536 EXPECT_EQ(instance1, contents()->GetSiteInstance());
537 // The pending RFH should now be swapped out, not deleted.
538 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
539 IsOnSwappedOutList(pending_rfh));
540 EXPECT_EQ(pending_rvh_delete_count, 0);
541 pending_rvh->OnSwappedOut(false);
543 // Close contents and ensure RVHs are deleted.
545 EXPECT_EQ(orig_rvh_delete_count, 1);
546 EXPECT_EQ(pending_rvh_delete_count, 1);
549 // Test that navigating across a site boundary after a crash creates a new
550 // RVH without requiring a cross-site transition (i.e., PENDING state).
551 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
552 contents()->transition_cross_site = true;
553 TestRenderViewHost* orig_rvh = test_rvh();
554 int orig_rvh_delete_count = 0;
555 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
556 SiteInstance* instance1 = contents()->GetSiteInstance();
558 // Navigate to URL. First URL should use first RenderViewHost.
559 const GURL url("http://www.google.com");
560 controller().LoadURL(
561 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
562 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
564 EXPECT_FALSE(contents()->cross_navigation_pending());
565 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
567 // Crash the renderer.
568 orig_rvh->set_render_view_created(false);
570 // Navigate to new site. We should not go into PENDING.
571 const GURL url2("http://www.yahoo.com");
572 controller().LoadURL(
573 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
574 RenderViewHost* new_rvh = rvh();
575 EXPECT_FALSE(contents()->cross_navigation_pending());
576 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
577 EXPECT_NE(orig_rvh, new_rvh);
578 EXPECT_EQ(orig_rvh_delete_count, 1);
580 // DidNavigate from the new page
581 contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
582 SiteInstance* instance2 = contents()->GetSiteInstance();
584 EXPECT_FALSE(contents()->cross_navigation_pending());
585 EXPECT_EQ(new_rvh, rvh());
586 EXPECT_NE(instance1, instance2);
587 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
589 // Close contents and ensure RVHs are deleted.
591 EXPECT_EQ(orig_rvh_delete_count, 1);
594 // Test that opening a new contents in the same SiteInstance and then navigating
595 // both contentses to a new site will place both contentses in a single
597 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
598 contents()->transition_cross_site = true;
599 TestRenderViewHost* orig_rvh = test_rvh();
600 SiteInstance* instance1 = contents()->GetSiteInstance();
602 // Navigate to URL. First URL should use first RenderViewHost.
603 const GURL url("http://www.google.com");
604 controller().LoadURL(
605 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
606 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
608 // Open a new contents with the same SiteInstance, navigated to the same site.
609 scoped_ptr<TestWebContents> contents2(
610 TestWebContents::Create(browser_context(), instance1));
611 contents2->transition_cross_site = true;
612 contents2->GetController().LoadURL(url, Referrer(),
613 PAGE_TRANSITION_TYPED,
615 // Need this page id to be 2 since the site instance is the same (which is the
616 // scope of page IDs) and we want to consider this a new page.
617 contents2->TestDidNavigate(
618 contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
620 // Navigate first contents to a new site.
621 const GURL url2a("http://www.yahoo.com");
622 controller().LoadURL(
623 url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
624 orig_rvh->SendBeforeUnloadACK(true);
625 TestRenderViewHost* pending_rvh_a =
626 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
627 contents()->TestDidNavigate(
628 pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
629 SiteInstance* instance2a = contents()->GetSiteInstance();
630 EXPECT_NE(instance1, instance2a);
632 // Navigate second contents to the same site as the first tab.
633 const GURL url2b("http://mail.yahoo.com");
634 contents2->GetController().LoadURL(url2b, Referrer(),
635 PAGE_TRANSITION_TYPED,
637 TestRenderViewHost* rvh2 =
638 static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
639 rvh2->SendBeforeUnloadACK(true);
640 TestRenderViewHost* pending_rvh_b =
641 static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
642 EXPECT_TRUE(pending_rvh_b != NULL);
643 EXPECT_TRUE(contents2->cross_navigation_pending());
645 // NOTE(creis): We used to be in danger of showing a crash page here if the
646 // second contents hadn't navigated somewhere first (bug 1145430). That case
647 // is now covered by the CrossSiteBoundariesAfterCrash test.
648 contents2->TestDidNavigate(
649 pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
650 SiteInstance* instance2b = contents2->GetSiteInstance();
651 EXPECT_NE(instance1, instance2b);
653 // Both contentses should now be in the same SiteInstance.
654 EXPECT_EQ(instance2a, instance2b);
657 TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
658 WebContentsImplTestBrowserClient browser_client;
659 SetBrowserClientForTesting(&browser_client);
661 contents()->transition_cross_site = true;
662 TestRenderViewHost* orig_rvh = test_rvh();
663 RenderFrameHostImpl* orig_rfh =
664 contents()->GetFrameTree()->root()->current_frame_host();
665 int orig_rvh_delete_count = 0;
666 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
667 SiteInstanceImpl* orig_instance =
668 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
670 browser_client.set_assign_site_for_url(false);
671 // Navigate to an URL that will not assign a new SiteInstance.
672 const GURL native_url("non-site-url://stuffandthings");
673 controller().LoadURL(
674 native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
675 contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
677 EXPECT_FALSE(contents()->cross_navigation_pending());
678 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
679 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
680 EXPECT_EQ(native_url, contents()->GetVisibleURL());
681 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
682 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
683 EXPECT_FALSE(orig_instance->HasSite());
685 browser_client.set_assign_site_for_url(true);
686 // Navigate to new site (should keep same site instance).
687 const GURL url("http://www.google.com");
688 controller().LoadURL(
689 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
690 EXPECT_FALSE(contents()->cross_navigation_pending());
691 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
692 EXPECT_EQ(url, contents()->GetVisibleURL());
693 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
694 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
696 // Keep the number of active views in orig_rvh's SiteInstance
697 // non-zero so that orig_rvh doesn't get deleted when it gets
699 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
700 increment_active_view_count();
702 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
704 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
705 EXPECT_EQ(url, contents()->GetLastCommittedURL());
707 // Navigate to another new site (should create a new site instance).
708 const GURL url2("http://www.yahoo.com");
709 controller().LoadURL(
710 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
711 EXPECT_TRUE(contents()->cross_navigation_pending());
712 EXPECT_EQ(url, contents()->GetLastCommittedURL());
713 EXPECT_EQ(url2, contents()->GetVisibleURL());
714 TestRenderViewHost* pending_rvh =
715 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
716 int pending_rvh_delete_count = 0;
717 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
719 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
720 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
721 orig_rvh->SendBeforeUnloadACK(true);
722 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
724 // DidNavigate from the pending page.
725 contents()->TestDidNavigate(
726 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
727 SiteInstance* new_instance = contents()->GetSiteInstance();
729 EXPECT_FALSE(contents()->cross_navigation_pending());
730 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
731 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
732 EXPECT_EQ(url2, contents()->GetVisibleURL());
733 EXPECT_NE(new_instance, orig_instance);
734 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
735 // We keep the original RFH around, swapped out.
736 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
738 EXPECT_EQ(orig_rvh_delete_count, 0);
739 orig_rvh->OnSwappedOut(false);
741 // Close contents and ensure RVHs are deleted.
743 EXPECT_EQ(orig_rvh_delete_count, 1);
744 EXPECT_EQ(pending_rvh_delete_count, 1);
747 // Test that we can find an opener RVH even if it's pending.
748 // http://crbug.com/176252.
749 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
750 contents()->transition_cross_site = true;
751 TestRenderViewHost* orig_rvh = test_rvh();
753 // Navigate to a URL.
754 const GURL url("http://www.google.com");
755 controller().LoadURL(
756 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
757 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
759 // Start to navigate first tab to a new site, so that it has a pending RVH.
760 const GURL url2("http://www.yahoo.com");
761 controller().LoadURL(
762 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
763 orig_rvh->SendBeforeUnloadACK(true);
764 TestRenderViewHost* pending_rvh =
765 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
767 // While it is still pending, simulate opening a new tab with the first tab
768 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
769 // on the opener to ensure that an RVH exists.
770 int opener_routing_id = contents()->CreateOpenerRenderViews(
771 pending_rvh->GetSiteInstance());
773 // We should find the pending RVH and not create a new one.
774 EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
777 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
778 // to determine whether a navigation is cross-site.
779 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
780 contents()->transition_cross_site = true;
781 RenderViewHost* orig_rvh = rvh();
782 SiteInstance* instance1 = contents()->GetSiteInstance();
785 const GURL url("http://www.google.com");
786 controller().LoadURL(
787 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
788 contents()->TestDidNavigate(
789 orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
791 // Open a related contents to a second site.
792 scoped_ptr<TestWebContents> contents2(
793 TestWebContents::Create(browser_context(), instance1));
794 contents2->transition_cross_site = true;
795 const GURL url2("http://www.yahoo.com");
796 contents2->GetController().LoadURL(url2, Referrer(),
797 PAGE_TRANSITION_TYPED,
799 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
801 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
802 contents2->GetRenderViewHost());
803 EXPECT_FALSE(contents2->cross_navigation_pending());
804 contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
805 SiteInstance* instance2 = contents2->GetSiteInstance();
806 EXPECT_NE(instance1, instance2);
807 EXPECT_FALSE(contents2->cross_navigation_pending());
809 // Simulate a link click in first contents to second site. Doesn't switch
810 // SiteInstances, because we don't intercept WebKit navigations.
811 contents()->TestDidNavigate(
812 orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
813 SiteInstance* instance3 = contents()->GetSiteInstance();
814 EXPECT_EQ(instance1, instance3);
815 EXPECT_FALSE(contents()->cross_navigation_pending());
817 // Navigate to the new site. Doesn't switch SiteInstancees, because we
818 // compare against the current URL, not the SiteInstance's site.
819 const GURL url3("http://mail.yahoo.com");
820 controller().LoadURL(
821 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
822 EXPECT_FALSE(contents()->cross_navigation_pending());
823 contents()->TestDidNavigate(
824 orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
825 SiteInstance* instance4 = contents()->GetSiteInstance();
826 EXPECT_EQ(instance1, instance4);
829 // Test that the onbeforeunload and onunload handlers run when navigating
830 // across site boundaries.
831 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
832 contents()->transition_cross_site = true;
833 TestRenderViewHost* orig_rvh = test_rvh();
834 SiteInstance* instance1 = contents()->GetSiteInstance();
836 // Navigate to URL. First URL should use first RenderViewHost.
837 const GURL url("http://www.google.com");
838 controller().LoadURL(
839 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
840 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
841 EXPECT_FALSE(contents()->cross_navigation_pending());
842 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
844 // Navigate to new site, but simulate an onbeforeunload denial.
845 const GURL url2("http://www.yahoo.com");
846 controller().LoadURL(
847 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
848 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
849 base::TimeTicks now = base::TimeTicks::Now();
850 orig_rvh->GetMainFrame()->OnMessageReceived(
851 FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
852 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
853 EXPECT_FALSE(contents()->cross_navigation_pending());
854 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
856 // Navigate again, but simulate an onbeforeunload approval.
857 controller().LoadURL(
858 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
859 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
860 now = base::TimeTicks::Now();
861 orig_rvh->GetMainFrame()->OnMessageReceived(
862 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
863 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
864 EXPECT_TRUE(contents()->cross_navigation_pending());
865 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
866 contents()->GetPendingRenderViewHost());
868 // We won't hear DidNavigate until the onunload handler has finished running.
870 // DidNavigate from the pending page.
871 contents()->TestDidNavigate(
872 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
873 SiteInstance* instance2 = contents()->GetSiteInstance();
874 EXPECT_FALSE(contents()->cross_navigation_pending());
875 EXPECT_EQ(pending_rvh, rvh());
876 EXPECT_NE(instance1, instance2);
877 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
880 // Test that during a slow cross-site navigation, the original renderer can
881 // navigate to a different URL and have it displayed, canceling the slow
883 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
884 contents()->transition_cross_site = true;
885 TestRenderViewHost* orig_rvh = test_rvh();
886 SiteInstance* instance1 = contents()->GetSiteInstance();
888 // Navigate to URL. First URL should use first RenderViewHost.
889 const GURL url("http://www.google.com");
890 controller().LoadURL(
891 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
892 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
893 EXPECT_FALSE(contents()->cross_navigation_pending());
894 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
896 // Navigate to new site, simulating an onbeforeunload approval.
897 const GURL url2("http://www.yahoo.com");
898 controller().LoadURL(
899 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
900 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
901 base::TimeTicks now = base::TimeTicks::Now();
902 orig_rvh->GetMainFrame()->OnMessageReceived(
903 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
904 EXPECT_TRUE(contents()->cross_navigation_pending());
906 // Suppose the original renderer navigates before the new one is ready.
907 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
909 // Verify that the pending navigation is cancelled.
910 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
911 SiteInstance* instance2 = contents()->GetSiteInstance();
912 EXPECT_FALSE(contents()->cross_navigation_pending());
913 EXPECT_EQ(orig_rvh, rvh());
914 EXPECT_EQ(instance1, instance2);
915 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
918 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
919 contents()->transition_cross_site = true;
921 // Start with a web ui page, which gets a new RVH with WebUI bindings.
922 const GURL url1("chrome://blah");
923 controller().LoadURL(
924 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
925 TestRenderViewHost* ntp_rvh = test_rvh();
926 contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
927 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
928 SiteInstance* instance1 = contents()->GetSiteInstance();
930 EXPECT_FALSE(contents()->cross_navigation_pending());
931 EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
932 EXPECT_EQ(url1, entry1->GetURL());
934 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
935 EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
937 // Navigate to new site.
938 const GURL url2("http://www.google.com");
939 controller().LoadURL(
940 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
941 EXPECT_TRUE(contents()->cross_navigation_pending());
942 TestRenderViewHost* google_rvh =
943 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
945 // Simulate beforeunload approval.
946 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
947 base::TimeTicks now = base::TimeTicks::Now();
948 ntp_rvh->GetMainFrame()->OnMessageReceived(
949 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
951 // DidNavigate from the pending page.
952 contents()->TestDidNavigate(
953 google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
954 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
955 SiteInstance* instance2 = contents()->GetSiteInstance();
957 EXPECT_FALSE(contents()->cross_navigation_pending());
958 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
959 EXPECT_NE(instance1, instance2);
960 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
961 EXPECT_EQ(url2, entry2->GetURL());
963 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
964 EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
966 // Navigate to third page on same site.
967 const GURL url3("http://news.google.com");
968 controller().LoadURL(
969 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
970 EXPECT_FALSE(contents()->cross_navigation_pending());
971 contents()->TestDidNavigate(
972 google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
973 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
974 SiteInstance* instance3 = contents()->GetSiteInstance();
976 EXPECT_FALSE(contents()->cross_navigation_pending());
977 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
978 EXPECT_EQ(instance2, instance3);
979 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
980 EXPECT_EQ(url3, entry3->GetURL());
982 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
984 // Go back within the site.
985 controller().GoBack();
986 EXPECT_FALSE(contents()->cross_navigation_pending());
987 EXPECT_EQ(entry2, controller().GetPendingEntry());
989 // Before that commits, go back again.
990 controller().GoBack();
991 EXPECT_TRUE(contents()->cross_navigation_pending());
992 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
993 EXPECT_EQ(entry1, controller().GetPendingEntry());
995 // Simulate beforeunload approval.
996 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
997 now = base::TimeTicks::Now();
998 google_rvh->GetMainFrame()->OnMessageReceived(
999 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1001 // DidNavigate from the first back. This aborts the second back's pending RVH.
1002 contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1004 // We should commit this page and forget about the second back.
1005 EXPECT_FALSE(contents()->cross_navigation_pending());
1006 EXPECT_FALSE(controller().GetPendingEntry());
1007 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
1008 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
1010 // We should not have corrupted the NTP entry.
1011 EXPECT_EQ(instance3,
1012 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1013 EXPECT_EQ(instance2,
1014 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1015 EXPECT_EQ(instance1,
1016 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1017 EXPECT_EQ(url1, entry1->GetURL());
1020 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1021 // original renderer will not cancel the slow navigation (bug 42029).
1022 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
1023 contents()->transition_cross_site = true;
1024 TestRenderViewHost* orig_rvh = test_rvh();
1026 // Navigate to URL. First URL should use first RenderViewHost.
1027 const GURL url("http://www.google.com");
1028 controller().LoadURL(
1029 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1030 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1031 EXPECT_FALSE(contents()->cross_navigation_pending());
1032 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1034 // Start navigating to new site.
1035 const GURL url2("http://www.yahoo.com");
1036 controller().LoadURL(
1037 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1039 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1040 // waiting for a before unload response.
1041 orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
1042 PAGE_TRANSITION_AUTO_SUBFRAME);
1043 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1045 // Now simulate the onbeforeunload approval and verify the navigation is
1047 base::TimeTicks now = base::TimeTicks::Now();
1048 orig_rvh->GetMainFrame()->OnMessageReceived(
1049 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1050 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1051 EXPECT_TRUE(contents()->cross_navigation_pending());
1054 // Test that a cross-site navigation is not preempted if the previous
1055 // renderer sends a FrameNavigate message just before being told to stop.
1056 // We should only preempt the cross-site navigation if the previous renderer
1057 // has started a new navigation. See http://crbug.com/79176.
1058 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1059 contents()->transition_cross_site = true;
1061 // Navigate to NTP URL.
1062 const GURL url("chrome://blah");
1063 controller().LoadURL(
1064 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1065 TestRenderViewHost* orig_rvh = test_rvh();
1066 EXPECT_FALSE(contents()->cross_navigation_pending());
1068 // Navigate to new site, with the beforeunload request in flight.
1069 const GURL url2("http://www.yahoo.com");
1070 controller().LoadURL(
1071 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1072 TestRenderViewHost* pending_rvh =
1073 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1074 EXPECT_TRUE(contents()->cross_navigation_pending());
1075 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1077 // Suppose the first navigation tries to commit now, with a
1078 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1079 // but it should act as if the beforeunload ack arrived.
1080 orig_rvh->SendNavigate(1, GURL("chrome://blah"));
1081 EXPECT_TRUE(contents()->cross_navigation_pending());
1082 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1083 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1085 // The pending navigation should be able to commit successfully.
1086 contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1087 EXPECT_FALSE(contents()->cross_navigation_pending());
1088 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
1091 // Test that the original renderer cannot preempt a cross-site navigation once
1092 // the unload request has been made. At this point, the cross-site navigation
1093 // is almost ready to be displayed, and the original renderer is only given a
1094 // short chance to run an unload handler. Prevents regression of bug 23942.
1095 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
1096 contents()->transition_cross_site = true;
1097 TestRenderViewHost* orig_rvh = test_rvh();
1098 SiteInstance* instance1 = contents()->GetSiteInstance();
1100 // Navigate to URL. First URL should use first RenderViewHost.
1101 const GURL url("http://www.google.com");
1102 controller().LoadURL(
1103 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1104 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1105 EXPECT_FALSE(contents()->cross_navigation_pending());
1106 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1108 // Navigate to new site, simulating an onbeforeunload approval.
1109 const GURL url2("http://www.yahoo.com");
1110 controller().LoadURL(
1111 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1112 base::TimeTicks now = base::TimeTicks::Now();
1113 orig_rvh->GetMainFrame()->OnMessageReceived(
1114 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1115 EXPECT_TRUE(contents()->cross_navigation_pending());
1116 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
1117 contents()->GetPendingRenderViewHost());
1119 // Simulate the pending renderer's response, which leads to an unload request
1120 // being sent to orig_rvh.
1121 std::vector<GURL> url_chain;
1122 url_chain.push_back(GURL());
1123 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1124 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1125 GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
1126 url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
1128 // Suppose the original renderer navigates now, while the unload request is in
1129 // flight. We should ignore it, wait for the unload ack, and let the pending
1130 // request continue. Otherwise, the contents may close spontaneously or stop
1131 // responding to navigation requests. (See bug 23942.)
1132 FrameHostMsg_DidCommitProvisionalLoad_Params params1a;
1133 InitNavigateParams(¶ms1a, 2, GURL("http://www.google.com/foo"),
1134 PAGE_TRANSITION_TYPED);
1135 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1137 // Verify that the pending navigation is still in progress.
1138 EXPECT_TRUE(contents()->cross_navigation_pending());
1139 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
1141 // DidNavigate from the pending page should commit it.
1142 contents()->TestDidNavigate(
1143 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1144 SiteInstance* instance2 = contents()->GetSiteInstance();
1145 EXPECT_FALSE(contents()->cross_navigation_pending());
1146 EXPECT_EQ(pending_rvh, rvh());
1147 EXPECT_NE(instance1, instance2);
1148 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1151 // Test that a cross-site navigation that doesn't commit after the unload
1152 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1153 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1154 contents()->transition_cross_site = true;
1155 TestRenderViewHost* orig_rvh = test_rvh();
1156 SiteInstance* instance1 = contents()->GetSiteInstance();
1158 // Navigate to URL. First URL should use first RenderViewHost.
1159 const GURL url("http://www.google.com");
1160 controller().LoadURL(
1161 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1162 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1163 EXPECT_FALSE(contents()->cross_navigation_pending());
1164 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1166 // Navigate to new site, simulating an onbeforeunload approval.
1167 const GURL url2("http://www.yahoo.com");
1168 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1169 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1170 base::TimeTicks now = base::TimeTicks::Now();
1171 orig_rvh->GetMainFrame()->OnMessageReceived(
1172 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1173 EXPECT_TRUE(contents()->cross_navigation_pending());
1175 // Simulate swap out message when the response arrives.
1176 orig_rvh->OnSwappedOut(false);
1178 // Suppose the navigation doesn't get a chance to commit, and the user
1179 // navigates in the current RVH's SiteInstance.
1180 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1182 // Verify that the pending navigation is cancelled and the renderer is no
1183 // longer swapped out.
1184 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1185 SiteInstance* instance2 = contents()->GetSiteInstance();
1186 EXPECT_FALSE(contents()->cross_navigation_pending());
1187 EXPECT_EQ(orig_rvh, rvh());
1188 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, orig_rvh->rvh_state());
1189 EXPECT_EQ(instance1, instance2);
1190 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1193 // Test that NavigationEntries have the correct page state after going
1194 // forward and back. Prevents regression for bug 1116137.
1195 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1196 TestRenderViewHost* orig_rvh = test_rvh();
1198 // Navigate to URL. There should be no committed entry yet.
1199 const GURL url("http://www.google.com");
1200 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1201 NavigationEntry* entry = controller().GetLastCommittedEntry();
1202 EXPECT_TRUE(entry == NULL);
1204 // Committed entry should have page state after DidNavigate.
1205 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1206 entry = controller().GetLastCommittedEntry();
1207 EXPECT_TRUE(entry->GetPageState().IsValid());
1209 // Navigate to same site.
1210 const GURL url2("http://images.google.com");
1211 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1212 entry = controller().GetLastCommittedEntry();
1213 EXPECT_TRUE(entry->GetPageState().IsValid());
1215 // Committed entry should have page state after DidNavigate.
1216 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1217 entry = controller().GetLastCommittedEntry();
1218 EXPECT_TRUE(entry->GetPageState().IsValid());
1220 // Now go back. Committed entry should still have page state.
1221 controller().GoBack();
1222 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1223 entry = controller().GetLastCommittedEntry();
1224 EXPECT_TRUE(entry->GetPageState().IsValid());
1227 // Test that NavigationEntries have the correct page state and SiteInstance
1228 // state after opening a new window to about:blank. Prevents regression for
1229 // bugs b/1116137 and http://crbug.com/111975.
1230 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1231 TestRenderViewHost* orig_rvh = test_rvh();
1233 // When opening a new window, it is navigated to about:blank internally.
1234 // Currently, this results in two DidNavigate events.
1235 const GURL url(kAboutBlankURL);
1236 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1237 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1239 // Should have a page state here.
1240 NavigationEntry* entry = controller().GetLastCommittedEntry();
1241 EXPECT_TRUE(entry->GetPageState().IsValid());
1243 // The SiteInstance should be available for other navigations to use.
1244 NavigationEntryImpl* entry_impl =
1245 NavigationEntryImpl::FromNavigationEntry(entry);
1246 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1247 int32 site_instance_id = entry_impl->site_instance()->GetId();
1249 // Navigating to a normal page should not cause a process swap.
1250 const GURL new_url("http://www.google.com");
1251 controller().LoadURL(new_url, Referrer(),
1252 PAGE_TRANSITION_TYPED, std::string());
1253 EXPECT_FALSE(contents()->cross_navigation_pending());
1254 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1255 contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1256 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1257 controller().GetLastCommittedEntry());
1258 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1259 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1262 // Tests that fullscreen is exited throughout the object hierarchy when
1263 // navigating to a new page.
1264 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
1265 FakeFullscreenDelegate fake_delegate;
1266 contents()->SetDelegate(&fake_delegate);
1267 TestRenderViewHost* orig_rvh = test_rvh();
1269 // Navigate to a site.
1270 const GURL url("http://www.google.com");
1271 controller().LoadURL(
1272 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1273 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1274 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1276 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1277 EXPECT_FALSE(orig_rvh->IsFullscreen());
1278 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1279 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1280 orig_rvh->OnMessageReceived(
1281 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1282 EXPECT_TRUE(orig_rvh->IsFullscreen());
1283 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1284 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1286 // Navigate to a new site.
1287 const GURL url2("http://www.yahoo.com");
1288 controller().LoadURL(
1289 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1290 RenderViewHost* const pending_rvh = contents()->GetPendingRenderViewHost();
1291 contents()->TestDidNavigate(
1292 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1294 // Confirm fullscreen has exited.
1295 EXPECT_FALSE(orig_rvh->IsFullscreen());
1296 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1297 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1299 contents()->SetDelegate(NULL);
1302 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1304 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
1305 FakeFullscreenDelegate fake_delegate;
1306 contents()->SetDelegate(&fake_delegate);
1308 // Navigate to a site.
1309 const GURL url("http://www.google.com");
1310 controller().LoadURL(
1311 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1312 contents()->TestDidNavigate(test_rvh(), 1, url, PAGE_TRANSITION_TYPED);
1313 EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
1315 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1316 EXPECT_FALSE(test_rvh()->IsFullscreen());
1317 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1318 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1319 test_rvh()->OnMessageReceived(
1320 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1321 EXPECT_TRUE(test_rvh()->IsFullscreen());
1322 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1323 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1325 // Crash the renderer.
1326 test_rvh()->OnMessageReceived(
1327 ViewHostMsg_RenderProcessGone(
1328 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1330 // Confirm fullscreen has exited.
1331 EXPECT_FALSE(test_rvh()->IsFullscreen());
1332 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1333 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1335 contents()->SetDelegate(NULL);
1338 ////////////////////////////////////////////////////////////////////////////////
1339 // Interstitial Tests
1340 ////////////////////////////////////////////////////////////////////////////////
1342 // Test navigating to a page (with the navigation initiated from the browser,
1343 // as when a URL is typed in the location bar) that shows an interstitial and
1344 // creates a new navigation entry, then hiding it without proceeding.
1345 TEST_F(WebContentsImplTest,
1346 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1347 // Navigate to a page.
1348 GURL url1("http://www.google.com");
1349 test_rvh()->SendNavigate(1, url1);
1350 EXPECT_EQ(1, controller().GetEntryCount());
1352 // Initiate a browser navigation that will trigger the interstitial
1353 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1354 PAGE_TRANSITION_TYPED, std::string());
1356 // Show an interstitial.
1357 TestInterstitialPage::InterstitialState state =
1358 TestInterstitialPage::INVALID;
1359 bool deleted = false;
1360 GURL url2("http://interstitial");
1361 TestInterstitialPage* interstitial =
1362 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1363 TestInterstitialPageStateGuard state_guard(interstitial);
1364 interstitial->Show();
1365 // The interstitial should not show until its navigation has committed.
1366 EXPECT_FALSE(interstitial->is_showing());
1367 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1368 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1369 // Let's commit the interstitial navigation.
1370 interstitial->TestDidNavigate(1, url2);
1371 EXPECT_TRUE(interstitial->is_showing());
1372 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1373 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1374 NavigationEntry* entry = controller().GetVisibleEntry();
1375 ASSERT_TRUE(entry != NULL);
1376 EXPECT_TRUE(entry->GetURL() == url2);
1378 // Now don't proceed.
1379 interstitial->DontProceed();
1380 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1381 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1382 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1383 entry = controller().GetVisibleEntry();
1384 ASSERT_TRUE(entry != NULL);
1385 EXPECT_TRUE(entry->GetURL() == url1);
1386 EXPECT_EQ(1, controller().GetEntryCount());
1388 RunAllPendingInMessageLoop();
1389 EXPECT_TRUE(deleted);
1392 // Test navigating to a page (with the navigation initiated from the renderer,
1393 // as when clicking on a link in the page) that shows an interstitial and
1394 // creates a new navigation entry, then hiding it without proceeding.
1395 TEST_F(WebContentsImplTest,
1396 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1397 // Navigate to a page.
1398 GURL url1("http://www.google.com");
1399 test_rvh()->SendNavigate(1, url1);
1400 EXPECT_EQ(1, controller().GetEntryCount());
1402 // Show an interstitial (no pending entry, the interstitial would have been
1403 // triggered by clicking on a link).
1404 TestInterstitialPage::InterstitialState state =
1405 TestInterstitialPage::INVALID;
1406 bool deleted = false;
1407 GURL url2("http://interstitial");
1408 TestInterstitialPage* interstitial =
1409 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1410 TestInterstitialPageStateGuard state_guard(interstitial);
1411 interstitial->Show();
1412 // The interstitial should not show until its navigation has committed.
1413 EXPECT_FALSE(interstitial->is_showing());
1414 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1415 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1416 // Let's commit the interstitial navigation.
1417 interstitial->TestDidNavigate(1, url2);
1418 EXPECT_TRUE(interstitial->is_showing());
1419 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1420 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1421 NavigationEntry* entry = controller().GetVisibleEntry();
1422 ASSERT_TRUE(entry != NULL);
1423 EXPECT_TRUE(entry->GetURL() == url2);
1425 // Now don't proceed.
1426 interstitial->DontProceed();
1427 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1428 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1429 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1430 entry = controller().GetVisibleEntry();
1431 ASSERT_TRUE(entry != NULL);
1432 EXPECT_TRUE(entry->GetURL() == url1);
1433 EXPECT_EQ(1, controller().GetEntryCount());
1435 RunAllPendingInMessageLoop();
1436 EXPECT_TRUE(deleted);
1439 // Test navigating to a page that shows an interstitial without creating a new
1440 // navigation entry (this happens when the interstitial is triggered by a
1441 // sub-resource in the page), then hiding it without proceeding.
1442 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1443 // Navigate to a page.
1444 GURL url1("http://www.google.com");
1445 test_rvh()->SendNavigate(1, url1);
1446 EXPECT_EQ(1, controller().GetEntryCount());
1448 // Show an interstitial.
1449 TestInterstitialPage::InterstitialState state =
1450 TestInterstitialPage::INVALID;
1451 bool deleted = false;
1452 GURL url2("http://interstitial");
1453 TestInterstitialPage* interstitial =
1454 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1455 TestInterstitialPageStateGuard state_guard(interstitial);
1456 interstitial->Show();
1457 // The interstitial should not show until its navigation has committed.
1458 EXPECT_FALSE(interstitial->is_showing());
1459 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1460 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1461 // Let's commit the interstitial navigation.
1462 interstitial->TestDidNavigate(1, url2);
1463 EXPECT_TRUE(interstitial->is_showing());
1464 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1465 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1466 NavigationEntry* entry = controller().GetVisibleEntry();
1467 ASSERT_TRUE(entry != NULL);
1468 // The URL specified to the interstitial should have been ignored.
1469 EXPECT_TRUE(entry->GetURL() == url1);
1471 // Now don't proceed.
1472 interstitial->DontProceed();
1473 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1474 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1475 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1476 entry = controller().GetVisibleEntry();
1477 ASSERT_TRUE(entry != NULL);
1478 EXPECT_TRUE(entry->GetURL() == url1);
1479 EXPECT_EQ(1, controller().GetEntryCount());
1481 RunAllPendingInMessageLoop();
1482 EXPECT_TRUE(deleted);
1485 // Test navigating to a page (with the navigation initiated from the browser,
1486 // as when a URL is typed in the location bar) that shows an interstitial and
1487 // creates a new navigation entry, then proceeding.
1488 TEST_F(WebContentsImplTest,
1489 ShowInterstitialFromBrowserNewNavigationProceed) {
1490 // Navigate to a page.
1491 GURL url1("http://www.google.com");
1492 test_rvh()->SendNavigate(1, url1);
1493 EXPECT_EQ(1, controller().GetEntryCount());
1495 // Initiate a browser navigation that will trigger the interstitial
1496 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1497 PAGE_TRANSITION_TYPED, std::string());
1499 // Show an interstitial.
1500 TestInterstitialPage::InterstitialState state =
1501 TestInterstitialPage::INVALID;
1502 bool deleted = false;
1503 GURL url2("http://interstitial");
1504 TestInterstitialPage* interstitial =
1505 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1506 TestInterstitialPageStateGuard state_guard(interstitial);
1507 interstitial->Show();
1508 // The interstitial should not show until its navigation has committed.
1509 EXPECT_FALSE(interstitial->is_showing());
1510 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1511 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1512 // Let's commit the interstitial navigation.
1513 interstitial->TestDidNavigate(1, url2);
1514 EXPECT_TRUE(interstitial->is_showing());
1515 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1516 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1517 NavigationEntry* entry = controller().GetVisibleEntry();
1518 ASSERT_TRUE(entry != NULL);
1519 EXPECT_TRUE(entry->GetURL() == url2);
1522 interstitial->Proceed();
1523 // The interstitial should show until the new navigation commits.
1524 RunAllPendingInMessageLoop();
1525 ASSERT_FALSE(deleted);
1526 EXPECT_EQ(TestInterstitialPage::OKED, state);
1527 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1528 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1530 // Simulate the navigation to the page, that's when the interstitial gets
1532 GURL url3("http://www.thepage.com");
1533 test_rvh()->SendNavigate(2, url3);
1535 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1536 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1537 entry = controller().GetVisibleEntry();
1538 ASSERT_TRUE(entry != NULL);
1539 EXPECT_TRUE(entry->GetURL() == url3);
1541 EXPECT_EQ(2, controller().GetEntryCount());
1543 RunAllPendingInMessageLoop();
1544 EXPECT_TRUE(deleted);
1547 // Test navigating to a page (with the navigation initiated from the renderer,
1548 // as when clicking on a link in the page) that shows an interstitial and
1549 // creates a new navigation entry, then proceeding.
1550 TEST_F(WebContentsImplTest,
1551 ShowInterstitialFromRendererNewNavigationProceed) {
1552 // Navigate to a page.
1553 GURL url1("http://www.google.com");
1554 test_rvh()->SendNavigate(1, url1);
1555 EXPECT_EQ(1, controller().GetEntryCount());
1557 // Show an interstitial.
1558 TestInterstitialPage::InterstitialState state =
1559 TestInterstitialPage::INVALID;
1560 bool deleted = false;
1561 GURL url2("http://interstitial");
1562 TestInterstitialPage* interstitial =
1563 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1564 TestInterstitialPageStateGuard state_guard(interstitial);
1565 interstitial->Show();
1566 // The interstitial should not show until its navigation has committed.
1567 EXPECT_FALSE(interstitial->is_showing());
1568 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1569 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1570 // Let's commit the interstitial navigation.
1571 interstitial->TestDidNavigate(1, url2);
1572 EXPECT_TRUE(interstitial->is_showing());
1573 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1574 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1575 NavigationEntry* entry = controller().GetVisibleEntry();
1576 ASSERT_TRUE(entry != NULL);
1577 EXPECT_TRUE(entry->GetURL() == url2);
1580 interstitial->Proceed();
1581 // The interstitial should show until the new navigation commits.
1582 RunAllPendingInMessageLoop();
1583 ASSERT_FALSE(deleted);
1584 EXPECT_EQ(TestInterstitialPage::OKED, state);
1585 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1586 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1588 // Simulate the navigation to the page, that's when the interstitial gets
1590 GURL url3("http://www.thepage.com");
1591 test_rvh()->SendNavigate(2, url3);
1593 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1594 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1595 entry = controller().GetVisibleEntry();
1596 ASSERT_TRUE(entry != NULL);
1597 EXPECT_TRUE(entry->GetURL() == url3);
1599 EXPECT_EQ(2, controller().GetEntryCount());
1601 RunAllPendingInMessageLoop();
1602 EXPECT_TRUE(deleted);
1605 // Test navigating to a page that shows an interstitial without creating a new
1606 // navigation entry (this happens when the interstitial is triggered by a
1607 // sub-resource in the page), then proceeding.
1608 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1609 // Navigate to a page so we have a navigation entry in the controller.
1610 GURL url1("http://www.google.com");
1611 test_rvh()->SendNavigate(1, url1);
1612 EXPECT_EQ(1, controller().GetEntryCount());
1614 // Show an interstitial.
1615 TestInterstitialPage::InterstitialState state =
1616 TestInterstitialPage::INVALID;
1617 bool deleted = false;
1618 GURL url2("http://interstitial");
1619 TestInterstitialPage* interstitial =
1620 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1621 TestInterstitialPageStateGuard state_guard(interstitial);
1622 interstitial->Show();
1623 // The interstitial should not show until its navigation has committed.
1624 EXPECT_FALSE(interstitial->is_showing());
1625 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1626 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1627 // Let's commit the interstitial navigation.
1628 interstitial->TestDidNavigate(1, url2);
1629 EXPECT_TRUE(interstitial->is_showing());
1630 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1631 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1632 NavigationEntry* entry = controller().GetVisibleEntry();
1633 ASSERT_TRUE(entry != NULL);
1634 // The URL specified to the interstitial should have been ignored.
1635 EXPECT_TRUE(entry->GetURL() == url1);
1638 interstitial->Proceed();
1639 // Since this is not a new navigation, the previous page is dismissed right
1640 // away and shows the original page.
1641 EXPECT_EQ(TestInterstitialPage::OKED, state);
1642 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1643 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1644 entry = controller().GetVisibleEntry();
1645 ASSERT_TRUE(entry != NULL);
1646 EXPECT_TRUE(entry->GetURL() == url1);
1648 EXPECT_EQ(1, controller().GetEntryCount());
1650 RunAllPendingInMessageLoop();
1651 EXPECT_TRUE(deleted);
1654 // Test navigating to a page that shows an interstitial, then navigating away.
1655 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1656 // Show interstitial.
1657 TestInterstitialPage::InterstitialState state =
1658 TestInterstitialPage::INVALID;
1659 bool deleted = false;
1660 GURL url("http://interstitial");
1661 TestInterstitialPage* interstitial =
1662 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1663 TestInterstitialPageStateGuard state_guard(interstitial);
1664 interstitial->Show();
1665 interstitial->TestDidNavigate(1, url);
1667 // While interstitial showing, navigate to a new URL.
1668 const GURL url2("http://www.yahoo.com");
1669 test_rvh()->SendNavigate(1, url2);
1671 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1673 RunAllPendingInMessageLoop();
1674 EXPECT_TRUE(deleted);
1677 // Test navigating to a page that shows an interstitial, then going back.
1678 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1679 // Navigate to a page so we have a navigation entry in the controller.
1680 GURL url1("http://www.google.com");
1681 test_rvh()->SendNavigate(1, url1);
1682 EXPECT_EQ(1, controller().GetEntryCount());
1684 // Show interstitial.
1685 TestInterstitialPage::InterstitialState state =
1686 TestInterstitialPage::INVALID;
1687 bool deleted = false;
1688 GURL interstitial_url("http://interstitial");
1689 TestInterstitialPage* interstitial =
1690 new TestInterstitialPage(contents(), true, interstitial_url,
1692 TestInterstitialPageStateGuard state_guard(interstitial);
1693 interstitial->Show();
1694 interstitial->TestDidNavigate(2, interstitial_url);
1696 // While the interstitial is showing, go back.
1697 controller().GoBack();
1698 test_rvh()->SendNavigate(1, url1);
1700 // Make sure we are back to the original page and that the interstitial is
1702 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1703 NavigationEntry* entry = controller().GetVisibleEntry();
1705 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1707 RunAllPendingInMessageLoop();
1708 EXPECT_TRUE(deleted);
1711 // Test navigating to a page that shows an interstitial, has a renderer crash,
1712 // and then goes back.
1713 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1714 // Navigate to a page so we have a navigation entry in the controller.
1715 GURL url1("http://www.google.com");
1716 test_rvh()->SendNavigate(1, url1);
1717 EXPECT_EQ(1, controller().GetEntryCount());
1719 // Show interstitial.
1720 TestInterstitialPage::InterstitialState state =
1721 TestInterstitialPage::INVALID;
1722 bool deleted = false;
1723 GURL interstitial_url("http://interstitial");
1724 TestInterstitialPage* interstitial =
1725 new TestInterstitialPage(contents(), true, interstitial_url,
1727 TestInterstitialPageStateGuard state_guard(interstitial);
1728 interstitial->Show();
1729 interstitial->TestDidNavigate(2, interstitial_url);
1731 // Crash the renderer
1732 test_rvh()->OnMessageReceived(
1733 ViewHostMsg_RenderProcessGone(
1734 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1736 // While the interstitial is showing, go back.
1737 controller().GoBack();
1738 test_rvh()->SendNavigate(1, url1);
1740 // Make sure we are back to the original page and that the interstitial is
1742 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1743 NavigationEntry* entry = controller().GetVisibleEntry();
1745 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1747 RunAllPendingInMessageLoop();
1748 EXPECT_TRUE(deleted);
1751 // Test navigating to a page that shows an interstitial, has the renderer crash,
1752 // and then navigates to the interstitial.
1753 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1754 // Navigate to a page so we have a navigation entry in the controller.
1755 GURL url1("http://www.google.com");
1756 test_rvh()->SendNavigate(1, url1);
1757 EXPECT_EQ(1, controller().GetEntryCount());
1759 // Show interstitial.
1760 TestInterstitialPage::InterstitialState state =
1761 TestInterstitialPage::INVALID;
1762 bool deleted = false;
1763 GURL interstitial_url("http://interstitial");
1764 TestInterstitialPage* interstitial =
1765 new TestInterstitialPage(contents(), true, interstitial_url,
1767 TestInterstitialPageStateGuard state_guard(interstitial);
1768 interstitial->Show();
1770 // Crash the renderer
1771 test_rvh()->OnMessageReceived(
1772 ViewHostMsg_RenderProcessGone(
1773 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1775 interstitial->TestDidNavigate(2, interstitial_url);
1778 // Test navigating to a page that shows an interstitial, then close the
1780 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1781 // Show interstitial.
1782 TestInterstitialPage::InterstitialState state =
1783 TestInterstitialPage::INVALID;
1784 bool deleted = false;
1785 GURL url("http://interstitial");
1786 TestInterstitialPage* interstitial =
1787 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1788 TestInterstitialPageStateGuard state_guard(interstitial);
1789 interstitial->Show();
1790 interstitial->TestDidNavigate(1, url);
1792 // Now close the contents.
1794 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1796 RunAllPendingInMessageLoop();
1797 EXPECT_TRUE(deleted);
1800 // Test navigating to a page that shows an interstitial, then close the
1802 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1803 // Show interstitial.
1804 TestInterstitialPage::InterstitialState state =
1805 TestInterstitialPage::INVALID;
1806 bool deleted = false;
1807 GURL url("http://interstitial");
1808 TestInterstitialPage* interstitial =
1809 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1810 TestInterstitialPageStateGuard state_guard(interstitial);
1811 interstitial->Show();
1812 interstitial->TestDidNavigate(1, url);
1813 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1814 interstitial->GetRenderViewHostForTesting());
1816 // Now close the contents.
1818 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1820 // Before the interstitial has a chance to process its shutdown task,
1821 // simulate quitting the browser. This goes through all processes and
1822 // tells them to destruct.
1823 rvh->OnMessageReceived(
1824 ViewHostMsg_RenderProcessGone(0, 0, 0));
1826 RunAllPendingInMessageLoop();
1827 EXPECT_TRUE(deleted);
1830 // Test that after Proceed is called and an interstitial is still shown, no more
1831 // commands get executed.
1832 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1833 // Navigate to a page so we have a navigation entry in the controller.
1834 GURL url1("http://www.google.com");
1835 test_rvh()->SendNavigate(1, url1);
1836 EXPECT_EQ(1, controller().GetEntryCount());
1838 // Show an interstitial.
1839 TestInterstitialPage::InterstitialState state =
1840 TestInterstitialPage::INVALID;
1841 bool deleted = false;
1842 GURL url2("http://interstitial");
1843 TestInterstitialPage* interstitial =
1844 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1845 TestInterstitialPageStateGuard state_guard(interstitial);
1846 interstitial->Show();
1847 interstitial->TestDidNavigate(1, url2);
1850 EXPECT_EQ(0, interstitial->command_received_count());
1851 interstitial->TestDomOperationResponse("toto");
1852 EXPECT_EQ(1, interstitial->command_received_count());
1855 interstitial->Proceed();
1856 RunAllPendingInMessageLoop();
1857 ASSERT_FALSE(deleted);
1859 // While the navigation to the new page is pending, send other commands, they
1860 // should be ignored.
1861 interstitial->TestDomOperationResponse("hello");
1862 interstitial->TestDomOperationResponse("hi");
1863 EXPECT_EQ(1, interstitial->command_received_count());
1866 // Test showing an interstitial while another interstitial is already showing.
1867 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1868 // Navigate to a page so we have a navigation entry in the controller.
1869 GURL start_url("http://www.google.com");
1870 test_rvh()->SendNavigate(1, start_url);
1871 EXPECT_EQ(1, controller().GetEntryCount());
1873 // Show an interstitial.
1874 TestInterstitialPage::InterstitialState state1 =
1875 TestInterstitialPage::INVALID;
1876 bool deleted1 = false;
1877 GURL url1("http://interstitial1");
1878 TestInterstitialPage* interstitial1 =
1879 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1880 TestInterstitialPageStateGuard state_guard1(interstitial1);
1881 interstitial1->Show();
1882 interstitial1->TestDidNavigate(1, url1);
1884 // Now show another interstitial.
1885 TestInterstitialPage::InterstitialState state2 =
1886 TestInterstitialPage::INVALID;
1887 bool deleted2 = false;
1888 GURL url2("http://interstitial2");
1889 TestInterstitialPage* interstitial2 =
1890 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1891 TestInterstitialPageStateGuard state_guard2(interstitial2);
1892 interstitial2->Show();
1893 interstitial2->TestDidNavigate(1, url2);
1895 // Showing interstitial2 should have caused interstitial1 to go away.
1896 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1897 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1899 RunAllPendingInMessageLoop();
1900 EXPECT_TRUE(deleted1);
1901 ASSERT_FALSE(deleted2);
1903 // Let's make sure interstitial2 is working as intended.
1904 interstitial2->Proceed();
1905 GURL landing_url("http://www.thepage.com");
1906 test_rvh()->SendNavigate(2, landing_url);
1908 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1909 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1910 NavigationEntry* entry = controller().GetVisibleEntry();
1911 ASSERT_TRUE(entry != NULL);
1912 EXPECT_TRUE(entry->GetURL() == landing_url);
1913 EXPECT_EQ(2, controller().GetEntryCount());
1914 RunAllPendingInMessageLoop();
1915 EXPECT_TRUE(deleted2);
1918 // Test showing an interstitial, proceeding and then navigating to another
1920 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
1921 // Navigate to a page so we have a navigation entry in the controller.
1922 GURL start_url("http://www.google.com");
1923 test_rvh()->SendNavigate(1, start_url);
1924 EXPECT_EQ(1, controller().GetEntryCount());
1926 // Show an interstitial.
1927 TestInterstitialPage::InterstitialState state1 =
1928 TestInterstitialPage::INVALID;
1929 bool deleted1 = false;
1930 GURL url1("http://interstitial1");
1931 TestInterstitialPage* interstitial1 =
1932 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1933 TestInterstitialPageStateGuard state_guard1(interstitial1);
1934 interstitial1->Show();
1935 interstitial1->TestDidNavigate(1, url1);
1937 // Take action. The interstitial won't be hidden until the navigation is
1939 interstitial1->Proceed();
1940 EXPECT_EQ(TestInterstitialPage::OKED, state1);
1942 // Now show another interstitial (simulating the navigation causing another
1944 TestInterstitialPage::InterstitialState state2 =
1945 TestInterstitialPage::INVALID;
1946 bool deleted2 = false;
1947 GURL url2("http://interstitial2");
1948 TestInterstitialPage* interstitial2 =
1949 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1950 TestInterstitialPageStateGuard state_guard2(interstitial2);
1951 interstitial2->Show();
1952 interstitial2->TestDidNavigate(1, url2);
1954 // Showing interstitial2 should have caused interstitial1 to go away.
1955 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1956 RunAllPendingInMessageLoop();
1957 EXPECT_TRUE(deleted1);
1958 ASSERT_FALSE(deleted2);
1960 // Let's make sure interstitial2 is working as intended.
1961 interstitial2->Proceed();
1962 GURL landing_url("http://www.thepage.com");
1963 test_rvh()->SendNavigate(2, landing_url);
1965 RunAllPendingInMessageLoop();
1966 EXPECT_TRUE(deleted2);
1967 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1968 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1969 NavigationEntry* entry = controller().GetVisibleEntry();
1970 ASSERT_TRUE(entry != NULL);
1971 EXPECT_TRUE(entry->GetURL() == landing_url);
1972 EXPECT_EQ(2, controller().GetEntryCount());
1975 // Test that navigating away from an interstitial while it's loading cause it
1977 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
1978 // Show an interstitial.
1979 TestInterstitialPage::InterstitialState state =
1980 TestInterstitialPage::INVALID;
1981 bool deleted = false;
1982 GURL interstitial_url("http://interstitial");
1983 TestInterstitialPage* interstitial =
1984 new TestInterstitialPage(contents(), true, interstitial_url,
1986 TestInterstitialPageStateGuard state_guard(interstitial);
1987 interstitial->Show();
1989 // Let's simulate a navigation initiated from the browser before the
1990 // interstitial finishes loading.
1991 const GURL url("http://www.google.com");
1992 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1993 EXPECT_FALSE(interstitial->is_showing());
1994 RunAllPendingInMessageLoop();
1995 ASSERT_FALSE(deleted);
1997 // Now let's make the interstitial navigation commit.
1998 interstitial->TestDidNavigate(1, interstitial_url);
2000 // After it loaded the interstitial should be gone.
2001 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2003 RunAllPendingInMessageLoop();
2004 EXPECT_TRUE(deleted);
2007 // Test that a new request to show an interstitial while an interstitial is
2008 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2009 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
2010 GURL interstitial_url("http://interstitial");
2012 // Show a first interstitial.
2013 TestInterstitialPage::InterstitialState state1 =
2014 TestInterstitialPage::INVALID;
2015 bool deleted1 = false;
2016 TestInterstitialPage* interstitial1 =
2017 new TestInterstitialPage(contents(), true, interstitial_url,
2018 &state1, &deleted1);
2019 TestInterstitialPageStateGuard state_guard1(interstitial1);
2020 interstitial1->Show();
2022 // Show another interstitial on that same contents before the first one had
2024 TestInterstitialPage::InterstitialState state2 =
2025 TestInterstitialPage::INVALID;
2026 bool deleted2 = false;
2027 TestInterstitialPage* interstitial2 =
2028 new TestInterstitialPage(contents(), true, interstitial_url,
2029 &state2, &deleted2);
2030 TestInterstitialPageStateGuard state_guard2(interstitial2);
2031 interstitial2->Show();
2033 // The first interstitial should have been closed and deleted.
2034 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2035 // The 2nd one should still be OK.
2036 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2038 RunAllPendingInMessageLoop();
2039 EXPECT_TRUE(deleted1);
2040 ASSERT_FALSE(deleted2);
2042 // Make the interstitial navigation commit it should be showing.
2043 interstitial2->TestDidNavigate(1, interstitial_url);
2044 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
2047 // Test showing an interstitial and have its renderer crash.
2048 TEST_F(WebContentsImplTest, InterstitialCrasher) {
2049 // Show an interstitial.
2050 TestInterstitialPage::InterstitialState state =
2051 TestInterstitialPage::INVALID;
2052 bool deleted = false;
2053 GURL url("http://interstitial");
2054 TestInterstitialPage* interstitial =
2055 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2056 TestInterstitialPageStateGuard state_guard(interstitial);
2057 interstitial->Show();
2058 // Simulate a renderer crash before the interstitial is shown.
2059 interstitial->TestRenderViewTerminated(
2060 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2061 // The interstitial should have been dismissed.
2062 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2063 RunAllPendingInMessageLoop();
2064 EXPECT_TRUE(deleted);
2066 // Now try again but this time crash the intersitial after it was shown.
2068 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2069 interstitial->Show();
2070 interstitial->TestDidNavigate(1, url);
2071 // Simulate a renderer crash.
2072 interstitial->TestRenderViewTerminated(
2073 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2074 // The interstitial should have been dismissed.
2075 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2076 RunAllPendingInMessageLoop();
2077 EXPECT_TRUE(deleted);
2080 // Tests that showing an interstitial as a result of a browser initiated
2081 // navigation while an interstitial is showing does not remove the pending
2082 // entry (see http://crbug.com/9791).
2083 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
2084 const char kUrl[] = "http://www.badguys.com/";
2085 const GURL kGURL(kUrl);
2087 // Start a navigation to a page
2088 contents()->GetController().LoadURL(
2089 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2091 // Simulate that navigation triggering an interstitial.
2092 TestInterstitialPage::InterstitialState state =
2093 TestInterstitialPage::INVALID;
2094 bool deleted = false;
2095 TestInterstitialPage* interstitial =
2096 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2097 TestInterstitialPageStateGuard state_guard(interstitial);
2098 interstitial->Show();
2099 interstitial->TestDidNavigate(1, kGURL);
2101 // Initiate a new navigation from the browser that also triggers an
2103 contents()->GetController().LoadURL(
2104 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2105 TestInterstitialPage::InterstitialState state2 =
2106 TestInterstitialPage::INVALID;
2107 bool deleted2 = false;
2108 TestInterstitialPage* interstitial2 =
2109 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
2110 TestInterstitialPageStateGuard state_guard2(interstitial2);
2111 interstitial2->Show();
2112 interstitial2->TestDidNavigate(1, kGURL);
2114 // Make sure we still have an entry.
2115 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2117 EXPECT_EQ(kUrl, entry->GetURL().spec());
2119 // And that the first interstitial is gone, but not the second.
2120 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2121 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2122 RunAllPendingInMessageLoop();
2123 EXPECT_TRUE(deleted);
2124 EXPECT_FALSE(deleted2);
2127 // Tests that Javascript messages are not shown while an interstitial is
2129 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2130 const char kUrl[] = "http://www.badguys.com/";
2131 const GURL kGURL(kUrl);
2133 // Start a navigation to a page
2134 contents()->GetController().LoadURL(
2135 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2136 // DidNavigate from the page
2137 contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
2139 // Simulate showing an interstitial while the page is showing.
2140 TestInterstitialPage::InterstitialState state =
2141 TestInterstitialPage::INVALID;
2142 bool deleted = false;
2143 TestInterstitialPage* interstitial =
2144 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2145 TestInterstitialPageStateGuard state_guard(interstitial);
2146 interstitial->Show();
2147 interstitial->TestDidNavigate(1, kGURL);
2149 // While the interstitial is showing, let's simulate the hidden page
2150 // attempting to show a JS message.
2151 IPC::Message* dummy_message = new IPC::Message;
2152 bool did_suppress_message = false;
2153 contents()->RunJavaScriptMessage(contents()->GetRenderViewHost(),
2154 base::ASCIIToUTF16("This is an informative message"),
2155 base::ASCIIToUTF16("OK"),
2156 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message,
2157 &did_suppress_message);
2158 EXPECT_TRUE(did_suppress_message);
2161 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2162 // interstitial it isn't copied over to the destination.
2163 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2164 // Navigate to a page.
2165 GURL url1("http://www.google.com");
2166 test_rvh()->SendNavigate(1, url1);
2167 EXPECT_EQ(1, controller().GetEntryCount());
2169 // Initiate a browser navigation that will trigger the interstitial
2170 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2171 PAGE_TRANSITION_TYPED, std::string());
2173 // Show an interstitial.
2174 TestInterstitialPage::InterstitialState state =
2175 TestInterstitialPage::INVALID;
2176 bool deleted = false;
2177 GURL url2("http://interstitial");
2178 TestInterstitialPage* interstitial =
2179 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2180 TestInterstitialPageStateGuard state_guard(interstitial);
2181 interstitial->Show();
2182 interstitial->TestDidNavigate(1, url2);
2183 EXPECT_TRUE(interstitial->is_showing());
2184 EXPECT_EQ(2, controller().GetEntryCount());
2186 // Create another NavigationController.
2187 GURL url3("http://foo2");
2188 scoped_ptr<TestWebContents> other_contents(
2189 static_cast<TestWebContents*>(CreateTestWebContents()));
2190 NavigationControllerImpl& other_controller = other_contents->GetController();
2191 other_contents->NavigateAndCommit(url3);
2192 other_contents->ExpectSetHistoryLengthAndPrune(
2193 NavigationEntryImpl::FromNavigationEntry(
2194 other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2195 other_controller.GetEntryAtIndex(0)->GetPageID());
2196 other_controller.CopyStateFromAndPrune(&controller(), false);
2198 // The merged controller should only have two entries: url1 and url2.
2199 ASSERT_EQ(2, other_controller.GetEntryCount());
2200 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2201 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2202 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2204 // And the merged controller shouldn't be showing an interstitial.
2205 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2208 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2209 // showing an interstitial.
2210 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2211 // Navigate to a page.
2212 GURL url1("http://www.google.com");
2213 contents()->NavigateAndCommit(url1);
2215 // Create another NavigationController.
2216 scoped_ptr<TestWebContents> other_contents(
2217 static_cast<TestWebContents*>(CreateTestWebContents()));
2218 NavigationControllerImpl& other_controller = other_contents->GetController();
2220 // Navigate it to url2.
2221 GURL url2("http://foo2");
2222 other_contents->NavigateAndCommit(url2);
2224 // Show an interstitial.
2225 TestInterstitialPage::InterstitialState state =
2226 TestInterstitialPage::INVALID;
2227 bool deleted = false;
2228 GURL url3("http://interstitial");
2229 TestInterstitialPage* interstitial =
2230 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2232 TestInterstitialPageStateGuard state_guard(interstitial);
2233 interstitial->Show();
2234 interstitial->TestDidNavigate(1, url3);
2235 EXPECT_TRUE(interstitial->is_showing());
2236 EXPECT_EQ(2, other_controller.GetEntryCount());
2238 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2239 // interstitial is showing in the target.
2240 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2243 // Regression test for http://crbug.com/168611 - the URLs passed by the
2244 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2245 TEST_F(WebContentsImplTest, FilterURLs) {
2246 TestWebContentsObserver observer(contents());
2248 // A navigation to about:whatever should always look like a navigation to
2250 GURL url_normalized(kAboutBlankURL);
2251 GURL url_from_ipc("about:whatever");
2253 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2254 // will use the given URL to create the NavigationEntry as well, and that
2255 // entry should contain the filtered URL.
2256 contents()->NavigateAndCommit(url_normalized);
2258 // Check that an IPC with about:whatever is correctly normalized.
2259 contents()->TestDidFinishLoad(url_from_ipc);
2261 EXPECT_EQ(url_normalized, observer.last_url());
2263 // Create and navigate another WebContents.
2264 scoped_ptr<TestWebContents> other_contents(
2265 static_cast<TestWebContents*>(CreateTestWebContents()));
2266 TestWebContentsObserver other_observer(other_contents.get());
2267 other_contents->NavigateAndCommit(url_normalized);
2269 // Check that an IPC with about:whatever is correctly normalized.
2270 other_contents->TestDidFailLoadWithError(
2271 url_from_ipc, 1, base::string16());
2272 EXPECT_EQ(url_normalized, other_observer.last_url());
2275 // Test that if a pending contents is deleted before it is shown, we don't
2277 TEST_F(WebContentsImplTest, PendingContents) {
2278 scoped_ptr<TestWebContents> other_contents(
2279 static_cast<TestWebContents*>(CreateTestWebContents()));
2280 contents()->AddPendingContents(other_contents.get());
2281 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2282 other_contents.reset();
2283 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2286 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
2287 const gfx::Size original_preferred_size(1024, 768);
2288 contents()->UpdatePreferredSize(original_preferred_size);
2290 // With no capturers, expect the preferred size to be the one propagated into
2291 // WebContentsImpl via the RenderViewHostDelegate interface.
2292 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2293 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2295 // Increment capturer count, but without specifying a capture size. Expect
2296 // a "not set" preferred size.
2297 contents()->IncrementCapturerCount(gfx::Size());
2298 EXPECT_EQ(1, contents()->GetCapturerCount());
2299 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2301 // Increment capturer count again, but with an overriding capture size.
2302 // Expect preferred size to now be overridden to the capture size.
2303 const gfx::Size capture_size(1280, 720);
2304 contents()->IncrementCapturerCount(capture_size);
2305 EXPECT_EQ(2, contents()->GetCapturerCount());
2306 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2308 // Increment capturer count a third time, but the expect that the preferred
2309 // size is still the first capture size.
2310 const gfx::Size another_capture_size(720, 480);
2311 contents()->IncrementCapturerCount(another_capture_size);
2312 EXPECT_EQ(3, contents()->GetCapturerCount());
2313 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2315 // Decrement capturer count twice, but expect the preferred size to still be
2317 contents()->DecrementCapturerCount();
2318 contents()->DecrementCapturerCount();
2319 EXPECT_EQ(1, contents()->GetCapturerCount());
2320 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2322 // Decrement capturer count, and since the count has dropped to zero, the
2323 // original preferred size should be restored.
2324 contents()->DecrementCapturerCount();
2325 EXPECT_EQ(0, contents()->GetCapturerCount());
2326 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2329 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2331 TEST_F(WebContentsImplTest, GetLastActiveTime) {
2332 // The WebContents starts with a valid creation time.
2333 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2335 // Reset the last active time to a known-bad value.
2336 contents()->last_active_time_ = base::TimeTicks();
2337 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2339 // Simulate activating the WebContents. The active time should update.
2340 contents()->WasShown();
2341 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2344 class ContentsZoomChangedDelegate : public WebContentsDelegate {
2346 ContentsZoomChangedDelegate() :
2347 contents_zoom_changed_call_count_(0),
2348 last_zoom_in_(false) {
2351 int GetAndResetContentsZoomChangedCallCount() {
2352 int count = contents_zoom_changed_call_count_;
2353 contents_zoom_changed_call_count_ = 0;
2357 bool last_zoom_in() const {
2358 return last_zoom_in_;
2361 // WebContentsDelegate:
2362 virtual void ContentsZoomChange(bool zoom_in) OVERRIDE {
2363 contents_zoom_changed_call_count_++;
2364 last_zoom_in_ = zoom_in;
2368 int contents_zoom_changed_call_count_;
2371 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
2374 // Tests that some mouseehweel events get turned into browser zoom requests.
2375 TEST_F(WebContentsImplTest, HandleWheelEvent) {
2376 using blink::WebInputEvent;
2378 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2379 new ContentsZoomChangedDelegate());
2380 contents()->SetDelegate(delegate.get());
2384 // Verify that normal mouse wheel events do nothing to change the zoom level.
2385 blink::WebMouseWheelEvent event =
2386 SyntheticWebMouseWheelEventBuilder::Build(0, dy, modifiers, false);
2387 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2388 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2390 modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey;
2391 event = SyntheticWebMouseWheelEventBuilder::Build(0, dy, modifiers, false);
2392 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2393 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2395 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2396 // Except on MacOS where we never want to adjust zoom with mousewheel.
2397 modifiers = WebInputEvent::ControlKey;
2398 event = SyntheticWebMouseWheelEventBuilder::Build(0, dy, modifiers, false);
2399 bool handled = contents()->HandleWheelEvent(event);
2400 #if defined(OS_MACOSX)
2401 EXPECT_FALSE(handled);
2402 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2404 EXPECT_TRUE(handled);
2405 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2406 EXPECT_TRUE(delegate->last_zoom_in());
2409 modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
2410 WebInputEvent::AltKey;
2412 event = SyntheticWebMouseWheelEventBuilder::Build(2, dy, modifiers, false);
2413 handled = contents()->HandleWheelEvent(event);
2414 #if defined(OS_MACOSX)
2415 EXPECT_FALSE(handled);
2416 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2418 EXPECT_TRUE(handled);
2419 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2420 EXPECT_FALSE(delegate->last_zoom_in());
2423 // Unless there is no vertical movement.
2425 event = SyntheticWebMouseWheelEventBuilder::Build(2, dy, modifiers, false);
2426 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2427 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2429 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2430 contents()->SetDelegate(NULL);
2433 } // namespace content