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