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
;
329 ¶ms
, 0, GURL(url::kAboutBlankURL
), PAGE_TRANSITION_TYPED
);
331 LoadCommittedDetails details
;
332 cont
.RendererDidNavigate(main_test_rfh(), params
, &details
);
334 contents()->UpdateTitle(main_test_rfh(), 0,
335 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
336 base::i18n::LEFT_TO_RIGHT
);
337 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
340 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
341 const GURL
kGURL("chrome://blah");
342 controller().LoadURL(
343 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
344 EXPECT_EQ(base::string16(), contents()->GetTitle());
347 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
348 const GURL
kGURL("chrome://blah");
349 const base::string16 title
= base::ASCIIToUTF16("My Title");
350 controller().LoadURL(
351 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
353 NavigationEntry
* entry
= controller().GetVisibleEntry();
354 ASSERT_EQ(kGURL
, entry
->GetURL());
355 entry
->SetTitle(title
);
357 EXPECT_EQ(title
, contents()->GetTitle());
360 // Test view source mode for a webui page.
361 TEST_F(WebContentsImplTest
, NTPViewSource
) {
362 NavigationControllerImpl
& cont
=
363 static_cast<NavigationControllerImpl
&>(controller());
364 const char kUrl
[] = "view-source:chrome://blah";
365 const GURL
kGURL(kUrl
);
367 process()->sink().ClearMessages();
370 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
371 rvh()->GetDelegate()->RenderViewCreated(rvh());
372 // Did we get the expected message?
373 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
374 ViewMsg_EnableViewSourceMode::ID
));
376 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
377 InitNavigateParams(¶ms
, 0, kGURL
, PAGE_TRANSITION_TYPED
);
378 LoadCommittedDetails details
;
379 cont
.RendererDidNavigate(main_test_rfh(), params
, &details
);
380 // Also check title and url.
381 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
384 // Test to ensure UpdateMaxPageID is working properly.
385 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
386 SiteInstance
* instance1
= contents()->GetSiteInstance();
387 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(NULL
));
390 EXPECT_EQ(-1, contents()->GetMaxPageID());
391 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
392 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
394 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
395 contents()->UpdateMaxPageID(3);
396 contents()->UpdateMaxPageID(1);
397 EXPECT_EQ(3, contents()->GetMaxPageID());
398 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
399 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
401 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
402 EXPECT_EQ(3, contents()->GetMaxPageID());
403 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
404 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
407 // Test simple same-SiteInstance navigation.
408 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
409 TestRenderViewHost
* orig_rvh
= test_rvh();
410 SiteInstance
* instance1
= contents()->GetSiteInstance();
411 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
414 const GURL
url("http://www.google.com");
415 controller().LoadURL(
416 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
417 EXPECT_FALSE(contents()->cross_navigation_pending());
418 EXPECT_EQ(instance1
, orig_rvh
->GetSiteInstance());
419 // Controller's pending entry will have a NULL site instance until we assign
420 // it in DidNavigate.
422 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
423 site_instance() == NULL
);
425 // DidNavigate from the page
426 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
427 EXPECT_FALSE(contents()->cross_navigation_pending());
428 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
429 EXPECT_EQ(instance1
, orig_rvh
->GetSiteInstance());
430 // Controller's entry should now have the SiteInstance, or else we won't be
431 // able to find it later.
434 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
438 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
439 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
440 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
441 const GURL
url(std::string("http://example.org/").append(
442 GetMaxURLChars() + 1, 'a'));
444 controller().LoadURL(
445 url
, Referrer(), PAGE_TRANSITION_GENERATED
, std::string());
446 EXPECT_TRUE(controller().GetVisibleEntry() == NULL
);
449 // Test that navigating across a site boundary creates a new RenderViewHost
450 // with a new SiteInstance. Going back should do the same.
451 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
452 contents()->transition_cross_site
= true;
453 TestRenderViewHost
* orig_rvh
= test_rvh();
454 RenderFrameHostImpl
* orig_rfh
=
455 contents()->GetFrameTree()->root()->current_frame_host();
456 int orig_rvh_delete_count
= 0;
457 orig_rvh
->set_delete_counter(&orig_rvh_delete_count
);
458 SiteInstance
* instance1
= contents()->GetSiteInstance();
460 // Navigate to URL. First URL should use first RenderViewHost.
461 const GURL
url("http://www.google.com");
462 controller().LoadURL(
463 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
464 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
466 // Keep the number of active views in orig_rvh's SiteInstance
467 // non-zero so that orig_rvh doesn't get deleted when it gets
469 static_cast<SiteInstanceImpl
*>(orig_rvh
->GetSiteInstance())->
470 increment_active_view_count();
472 EXPECT_FALSE(contents()->cross_navigation_pending());
473 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
474 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
475 EXPECT_EQ(url
, contents()->GetVisibleURL());
477 // Navigate to new site
478 const GURL
url2("http://www.yahoo.com");
479 controller().LoadURL(
480 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
481 EXPECT_TRUE(contents()->cross_navigation_pending());
482 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
483 EXPECT_EQ(url2
, contents()->GetVisibleURL());
484 TestRenderViewHost
* pending_rvh
=
485 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
486 int pending_rvh_delete_count
= 0;
487 pending_rvh
->set_delete_counter(&pending_rvh_delete_count
);
488 RenderFrameHostImpl
* pending_rfh
= contents()->GetFrameTree()->root()->
489 render_manager()->pending_frame_host();
491 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
492 EXPECT_TRUE(pending_rvh
->are_navigations_suspended());
493 orig_rvh
->SendBeforeUnloadACK(true);
494 EXPECT_FALSE(pending_rvh
->are_navigations_suspended());
496 // DidNavigate from the pending page
497 contents()->TestDidNavigate(
498 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
499 SiteInstance
* instance2
= contents()->GetSiteInstance();
501 // Keep the number of active views in pending_rvh's SiteInstance
502 // non-zero so that orig_rvh doesn't get deleted when it gets
504 static_cast<SiteInstanceImpl
*>(pending_rvh
->GetSiteInstance())->
505 increment_active_view_count();
507 EXPECT_FALSE(contents()->cross_navigation_pending());
508 EXPECT_EQ(pending_rvh
, contents()->GetRenderViewHost());
509 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
510 EXPECT_EQ(url2
, contents()->GetVisibleURL());
511 EXPECT_NE(instance1
, instance2
);
512 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
513 // We keep the original RFH around, swapped out.
514 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
516 EXPECT_EQ(orig_rvh_delete_count
, 0);
518 // Going back should switch SiteInstances again. The first SiteInstance is
519 // stored in the NavigationEntry, so it should be the same as at the start.
520 // We should use the same RVH as before, swapping it back in.
521 controller().GoBack();
522 TestRenderViewHost
* goback_rvh
=
523 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
524 EXPECT_EQ(orig_rvh
, goback_rvh
);
525 EXPECT_TRUE(contents()->cross_navigation_pending());
527 // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
528 EXPECT_TRUE(goback_rvh
->are_navigations_suspended());
529 pending_rvh
->SendBeforeUnloadACK(true);
530 EXPECT_FALSE(goback_rvh
->are_navigations_suspended());
532 // DidNavigate from the back action
533 contents()->TestDidNavigate(
534 goback_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
535 EXPECT_FALSE(contents()->cross_navigation_pending());
536 EXPECT_EQ(goback_rvh
, contents()->GetRenderViewHost());
537 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
538 // The pending RFH should now be swapped out, not deleted.
539 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
540 IsOnSwappedOutList(pending_rfh
));
541 EXPECT_EQ(pending_rvh_delete_count
, 0);
542 pending_rvh
->OnSwappedOut(false);
544 // Close contents and ensure RVHs are deleted.
546 EXPECT_EQ(orig_rvh_delete_count
, 1);
547 EXPECT_EQ(pending_rvh_delete_count
, 1);
550 // Test that navigating across a site boundary after a crash creates a new
551 // RVH without requiring a cross-site transition (i.e., PENDING state).
552 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
553 contents()->transition_cross_site
= true;
554 TestRenderViewHost
* orig_rvh
= test_rvh();
555 int orig_rvh_delete_count
= 0;
556 orig_rvh
->set_delete_counter(&orig_rvh_delete_count
);
557 SiteInstance
* instance1
= contents()->GetSiteInstance();
559 // Navigate to URL. First URL should use first RenderViewHost.
560 const GURL
url("http://www.google.com");
561 controller().LoadURL(
562 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
563 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
565 EXPECT_FALSE(contents()->cross_navigation_pending());
566 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
568 // Crash the renderer.
569 orig_rvh
->set_render_view_created(false);
571 // Navigate to new site. We should not go into PENDING.
572 const GURL
url2("http://www.yahoo.com");
573 controller().LoadURL(
574 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
575 RenderViewHost
* new_rvh
= rvh();
576 EXPECT_FALSE(contents()->cross_navigation_pending());
577 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
578 EXPECT_NE(orig_rvh
, new_rvh
);
579 EXPECT_EQ(orig_rvh_delete_count
, 1);
581 // DidNavigate from the new page
582 contents()->TestDidNavigate(new_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
583 SiteInstance
* instance2
= contents()->GetSiteInstance();
585 EXPECT_FALSE(contents()->cross_navigation_pending());
586 EXPECT_EQ(new_rvh
, rvh());
587 EXPECT_NE(instance1
, instance2
);
588 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
590 // Close contents and ensure RVHs are deleted.
592 EXPECT_EQ(orig_rvh_delete_count
, 1);
595 // Test that opening a new contents in the same SiteInstance and then navigating
596 // both contentses to a new site will place both contentses in a single
598 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
599 contents()->transition_cross_site
= true;
600 TestRenderViewHost
* orig_rvh
= test_rvh();
601 SiteInstance
* instance1
= contents()->GetSiteInstance();
603 // Navigate to URL. First URL should use first RenderViewHost.
604 const GURL
url("http://www.google.com");
605 controller().LoadURL(
606 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
607 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
609 // Open a new contents with the same SiteInstance, navigated to the same site.
610 scoped_ptr
<TestWebContents
> contents2(
611 TestWebContents::Create(browser_context(), instance1
));
612 contents2
->transition_cross_site
= true;
613 contents2
->GetController().LoadURL(url
, Referrer(),
614 PAGE_TRANSITION_TYPED
,
616 // Need this page id to be 2 since the site instance is the same (which is the
617 // scope of page IDs) and we want to consider this a new page.
618 contents2
->TestDidNavigate(
619 contents2
->GetRenderViewHost(), 2, url
, PAGE_TRANSITION_TYPED
);
621 // Navigate first contents to a new site.
622 const GURL
url2a("http://www.yahoo.com");
623 controller().LoadURL(
624 url2a
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
625 orig_rvh
->SendBeforeUnloadACK(true);
626 TestRenderViewHost
* pending_rvh_a
=
627 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
628 contents()->TestDidNavigate(
629 pending_rvh_a
, 1, url2a
, PAGE_TRANSITION_TYPED
);
630 SiteInstance
* instance2a
= contents()->GetSiteInstance();
631 EXPECT_NE(instance1
, instance2a
);
633 // Navigate second contents to the same site as the first tab.
634 const GURL
url2b("http://mail.yahoo.com");
635 contents2
->GetController().LoadURL(url2b
, Referrer(),
636 PAGE_TRANSITION_TYPED
,
638 TestRenderViewHost
* rvh2
=
639 static_cast<TestRenderViewHost
*>(contents2
->GetRenderViewHost());
640 rvh2
->SendBeforeUnloadACK(true);
641 TestRenderViewHost
* pending_rvh_b
=
642 static_cast<TestRenderViewHost
*>(contents2
->GetPendingRenderViewHost());
643 EXPECT_TRUE(pending_rvh_b
!= NULL
);
644 EXPECT_TRUE(contents2
->cross_navigation_pending());
646 // NOTE(creis): We used to be in danger of showing a crash page here if the
647 // second contents hadn't navigated somewhere first (bug 1145430). That case
648 // is now covered by the CrossSiteBoundariesAfterCrash test.
649 contents2
->TestDidNavigate(
650 pending_rvh_b
, 2, url2b
, PAGE_TRANSITION_TYPED
);
651 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
652 EXPECT_NE(instance1
, instance2b
);
654 // Both contentses should now be in the same SiteInstance.
655 EXPECT_EQ(instance2a
, instance2b
);
658 TEST_F(WebContentsImplTest
, NavigateDoesNotUseUpSiteInstance
) {
659 WebContentsImplTestBrowserClient browser_client
;
660 SetBrowserClientForTesting(&browser_client
);
662 contents()->transition_cross_site
= true;
663 TestRenderViewHost
* orig_rvh
= test_rvh();
664 RenderFrameHostImpl
* orig_rfh
=
665 contents()->GetFrameTree()->root()->current_frame_host();
666 int orig_rvh_delete_count
= 0;
667 orig_rvh
->set_delete_counter(&orig_rvh_delete_count
);
668 SiteInstanceImpl
* orig_instance
=
669 static_cast<SiteInstanceImpl
*>(contents()->GetSiteInstance());
671 browser_client
.set_assign_site_for_url(false);
672 // Navigate to an URL that will not assign a new SiteInstance.
673 const GURL
native_url("non-site-url://stuffandthings");
674 controller().LoadURL(
675 native_url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
676 contents()->TestDidNavigate(orig_rvh
, 1, native_url
, PAGE_TRANSITION_TYPED
);
678 EXPECT_FALSE(contents()->cross_navigation_pending());
679 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
680 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
681 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
682 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
683 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
684 EXPECT_FALSE(orig_instance
->HasSite());
686 browser_client
.set_assign_site_for_url(true);
687 // Navigate to new site (should keep same site instance).
688 const GURL
url("http://www.google.com");
689 controller().LoadURL(
690 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
691 EXPECT_FALSE(contents()->cross_navigation_pending());
692 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
693 EXPECT_EQ(url
, contents()->GetVisibleURL());
694 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
695 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
697 // Keep the number of active views in orig_rvh's SiteInstance
698 // non-zero so that orig_rvh doesn't get deleted when it gets
700 static_cast<SiteInstanceImpl
*>(orig_rvh
->GetSiteInstance())->
701 increment_active_view_count();
703 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
705 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
706 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
708 // Navigate to another new site (should create a new site instance).
709 const GURL
url2("http://www.yahoo.com");
710 controller().LoadURL(
711 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
712 EXPECT_TRUE(contents()->cross_navigation_pending());
713 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
714 EXPECT_EQ(url2
, contents()->GetVisibleURL());
715 TestRenderViewHost
* pending_rvh
=
716 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
717 int pending_rvh_delete_count
= 0;
718 pending_rvh
->set_delete_counter(&pending_rvh_delete_count
);
720 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
721 EXPECT_TRUE(pending_rvh
->are_navigations_suspended());
722 orig_rvh
->SendBeforeUnloadACK(true);
723 EXPECT_FALSE(pending_rvh
->are_navigations_suspended());
725 // DidNavigate from the pending page.
726 contents()->TestDidNavigate(
727 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
728 SiteInstance
* new_instance
= contents()->GetSiteInstance();
730 EXPECT_FALSE(contents()->cross_navigation_pending());
731 EXPECT_EQ(pending_rvh
, contents()->GetRenderViewHost());
732 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
733 EXPECT_EQ(url2
, contents()->GetVisibleURL());
734 EXPECT_NE(new_instance
, orig_instance
);
735 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
736 // We keep the original RFH around, swapped out.
737 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
739 EXPECT_EQ(orig_rvh_delete_count
, 0);
740 orig_rvh
->OnSwappedOut(false);
742 // Close contents and ensure RVHs are deleted.
744 EXPECT_EQ(orig_rvh_delete_count
, 1);
745 EXPECT_EQ(pending_rvh_delete_count
, 1);
748 // Test that we can find an opener RVH even if it's pending.
749 // http://crbug.com/176252.
750 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
751 contents()->transition_cross_site
= true;
752 TestRenderViewHost
* orig_rvh
= test_rvh();
754 // Navigate to a URL.
755 const GURL
url("http://www.google.com");
756 controller().LoadURL(
757 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
758 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
760 // Start to navigate first tab to a new site, so that it has a pending RVH.
761 const GURL
url2("http://www.yahoo.com");
762 controller().LoadURL(
763 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
764 orig_rvh
->SendBeforeUnloadACK(true);
765 TestRenderViewHost
* pending_rvh
=
766 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
768 // While it is still pending, simulate opening a new tab with the first tab
769 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
770 // on the opener to ensure that an RVH exists.
771 int opener_routing_id
= contents()->CreateOpenerRenderViews(
772 pending_rvh
->GetSiteInstance());
774 // We should find the pending RVH and not create a new one.
775 EXPECT_EQ(pending_rvh
->GetRoutingID(), opener_routing_id
);
778 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
779 // to determine whether a navigation is cross-site.
780 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
781 contents()->transition_cross_site
= true;
782 RenderViewHost
* orig_rvh
= rvh();
783 SiteInstance
* instance1
= contents()->GetSiteInstance();
786 const GURL
url("http://www.google.com");
787 controller().LoadURL(
788 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
789 contents()->TestDidNavigate(
790 orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
792 // Open a related contents to a second site.
793 scoped_ptr
<TestWebContents
> contents2(
794 TestWebContents::Create(browser_context(), instance1
));
795 contents2
->transition_cross_site
= true;
796 const GURL
url2("http://www.yahoo.com");
797 contents2
->GetController().LoadURL(url2
, Referrer(),
798 PAGE_TRANSITION_TYPED
,
800 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
802 TestRenderViewHost
* rvh2
= static_cast<TestRenderViewHost
*>(
803 contents2
->GetRenderViewHost());
804 EXPECT_FALSE(contents2
->cross_navigation_pending());
805 contents2
->TestDidNavigate(rvh2
, 2, url2
, PAGE_TRANSITION_TYPED
);
806 SiteInstance
* instance2
= contents2
->GetSiteInstance();
807 EXPECT_NE(instance1
, instance2
);
808 EXPECT_FALSE(contents2
->cross_navigation_pending());
810 // Simulate a link click in first contents to second site. Doesn't switch
811 // SiteInstances, because we don't intercept WebKit navigations.
812 contents()->TestDidNavigate(
813 orig_rvh
, 2, url2
, PAGE_TRANSITION_TYPED
);
814 SiteInstance
* instance3
= contents()->GetSiteInstance();
815 EXPECT_EQ(instance1
, instance3
);
816 EXPECT_FALSE(contents()->cross_navigation_pending());
818 // Navigate to the new site. Doesn't switch SiteInstancees, because we
819 // compare against the current URL, not the SiteInstance's site.
820 const GURL
url3("http://mail.yahoo.com");
821 controller().LoadURL(
822 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
823 EXPECT_FALSE(contents()->cross_navigation_pending());
824 contents()->TestDidNavigate(
825 orig_rvh
, 3, url3
, PAGE_TRANSITION_TYPED
);
826 SiteInstance
* instance4
= contents()->GetSiteInstance();
827 EXPECT_EQ(instance1
, instance4
);
830 // Test that the onbeforeunload and onunload handlers run when navigating
831 // across site boundaries.
832 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
833 contents()->transition_cross_site
= true;
834 TestRenderViewHost
* orig_rvh
= test_rvh();
835 SiteInstance
* instance1
= contents()->GetSiteInstance();
837 // Navigate to URL. First URL should use first RenderViewHost.
838 const GURL
url("http://www.google.com");
839 controller().LoadURL(
840 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
841 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
842 EXPECT_FALSE(contents()->cross_navigation_pending());
843 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
845 // Navigate to new site, but simulate an onbeforeunload denial.
846 const GURL
url2("http://www.yahoo.com");
847 controller().LoadURL(
848 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
849 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
850 base::TimeTicks now
= base::TimeTicks::Now();
851 orig_rvh
->GetMainFrame()->OnMessageReceived(
852 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
853 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
854 EXPECT_FALSE(contents()->cross_navigation_pending());
855 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
857 // Navigate again, but simulate an onbeforeunload approval.
858 controller().LoadURL(
859 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
860 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
861 now
= base::TimeTicks::Now();
862 orig_rvh
->GetMainFrame()->OnMessageReceived(
863 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
864 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
865 EXPECT_TRUE(contents()->cross_navigation_pending());
866 TestRenderViewHost
* pending_rvh
= static_cast<TestRenderViewHost
*>(
867 contents()->GetPendingRenderViewHost());
869 // We won't hear DidNavigate until the onunload handler has finished running.
871 // DidNavigate from the pending page.
872 contents()->TestDidNavigate(
873 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
874 SiteInstance
* instance2
= contents()->GetSiteInstance();
875 EXPECT_FALSE(contents()->cross_navigation_pending());
876 EXPECT_EQ(pending_rvh
, rvh());
877 EXPECT_NE(instance1
, instance2
);
878 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
881 // Test that during a slow cross-site navigation, the original renderer can
882 // navigate to a different URL and have it displayed, canceling the slow
884 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
885 contents()->transition_cross_site
= true;
886 TestRenderViewHost
* orig_rvh
= test_rvh();
887 SiteInstance
* instance1
= contents()->GetSiteInstance();
889 // Navigate to URL. First URL should use first RenderViewHost.
890 const GURL
url("http://www.google.com");
891 controller().LoadURL(
892 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
893 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
894 EXPECT_FALSE(contents()->cross_navigation_pending());
895 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
897 // Navigate to new site, simulating an onbeforeunload approval.
898 const GURL
url2("http://www.yahoo.com");
899 controller().LoadURL(
900 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
901 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
902 base::TimeTicks now
= base::TimeTicks::Now();
903 orig_rvh
->GetMainFrame()->OnMessageReceived(
904 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
905 EXPECT_TRUE(contents()->cross_navigation_pending());
907 // Suppose the original renderer navigates before the new one is ready.
908 orig_rvh
->SendNavigate(2, GURL("http://www.google.com/foo"));
910 // Verify that the pending navigation is cancelled.
911 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
912 SiteInstance
* instance2
= contents()->GetSiteInstance();
913 EXPECT_FALSE(contents()->cross_navigation_pending());
914 EXPECT_EQ(orig_rvh
, rvh());
915 EXPECT_EQ(instance1
, instance2
);
916 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
919 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
920 contents()->transition_cross_site
= true;
922 // Start with a web ui page, which gets a new RVH with WebUI bindings.
923 const GURL
url1("chrome://blah");
924 controller().LoadURL(
925 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
926 TestRenderViewHost
* ntp_rvh
= test_rvh();
927 contents()->TestDidNavigate(ntp_rvh
, 1, url1
, PAGE_TRANSITION_TYPED
);
928 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
929 SiteInstance
* instance1
= contents()->GetSiteInstance();
931 EXPECT_FALSE(contents()->cross_navigation_pending());
932 EXPECT_EQ(ntp_rvh
, contents()->GetRenderViewHost());
933 EXPECT_EQ(url1
, entry1
->GetURL());
935 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
936 EXPECT_TRUE(ntp_rvh
->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
938 // Navigate to new site.
939 const GURL
url2("http://www.google.com");
940 controller().LoadURL(
941 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
942 EXPECT_TRUE(contents()->cross_navigation_pending());
943 TestRenderViewHost
* google_rvh
=
944 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
946 // Simulate beforeunload approval.
947 EXPECT_TRUE(ntp_rvh
->is_waiting_for_beforeunload_ack());
948 base::TimeTicks now
= base::TimeTicks::Now();
949 ntp_rvh
->GetMainFrame()->OnMessageReceived(
950 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
952 // DidNavigate from the pending page.
953 contents()->TestDidNavigate(
954 google_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
955 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
956 SiteInstance
* instance2
= contents()->GetSiteInstance();
958 EXPECT_FALSE(contents()->cross_navigation_pending());
959 EXPECT_EQ(google_rvh
, contents()->GetRenderViewHost());
960 EXPECT_NE(instance1
, instance2
);
961 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
962 EXPECT_EQ(url2
, entry2
->GetURL());
964 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
965 EXPECT_FALSE(google_rvh
->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
967 // Navigate to third page on same site.
968 const GURL
url3("http://news.google.com");
969 controller().LoadURL(
970 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
971 EXPECT_FALSE(contents()->cross_navigation_pending());
972 contents()->TestDidNavigate(
973 google_rvh
, 2, url3
, PAGE_TRANSITION_TYPED
);
974 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
975 SiteInstance
* instance3
= contents()->GetSiteInstance();
977 EXPECT_FALSE(contents()->cross_navigation_pending());
978 EXPECT_EQ(google_rvh
, contents()->GetRenderViewHost());
979 EXPECT_EQ(instance2
, instance3
);
980 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
981 EXPECT_EQ(url3
, entry3
->GetURL());
983 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
985 // Go back within the site.
986 controller().GoBack();
987 EXPECT_FALSE(contents()->cross_navigation_pending());
988 EXPECT_EQ(entry2
, controller().GetPendingEntry());
990 // Before that commits, go back again.
991 controller().GoBack();
992 EXPECT_TRUE(contents()->cross_navigation_pending());
993 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
994 EXPECT_EQ(entry1
, controller().GetPendingEntry());
996 // Simulate beforeunload approval.
997 EXPECT_TRUE(google_rvh
->is_waiting_for_beforeunload_ack());
998 now
= base::TimeTicks::Now();
999 google_rvh
->GetMainFrame()->OnMessageReceived(
1000 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1002 // DidNavigate from the first back. This aborts the second back's pending RVH.
1003 contents()->TestDidNavigate(google_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1005 // We should commit this page and forget about the second back.
1006 EXPECT_FALSE(contents()->cross_navigation_pending());
1007 EXPECT_FALSE(controller().GetPendingEntry());
1008 EXPECT_EQ(google_rvh
, contents()->GetRenderViewHost());
1009 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1011 // We should not have corrupted the NTP entry.
1012 EXPECT_EQ(instance3
,
1013 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1014 EXPECT_EQ(instance2
,
1015 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1016 EXPECT_EQ(instance1
,
1017 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1018 EXPECT_EQ(url1
, entry1
->GetURL());
1021 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1022 // original renderer will not cancel the slow navigation (bug 42029).
1023 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1024 contents()->transition_cross_site
= true;
1025 TestRenderViewHost
* orig_rvh
= test_rvh();
1027 // Navigate to URL. First URL should use first RenderViewHost.
1028 const GURL
url("http://www.google.com");
1029 controller().LoadURL(
1030 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1031 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1032 EXPECT_FALSE(contents()->cross_navigation_pending());
1033 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1035 // Start navigating to new site.
1036 const GURL
url2("http://www.yahoo.com");
1037 controller().LoadURL(
1038 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1040 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1041 // waiting for a before unload response.
1042 orig_rvh
->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
1043 PAGE_TRANSITION_AUTO_SUBFRAME
);
1044 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
1046 // Now simulate the onbeforeunload approval and verify the navigation is
1048 base::TimeTicks now
= base::TimeTicks::Now();
1049 orig_rvh
->GetMainFrame()->OnMessageReceived(
1050 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1051 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1052 EXPECT_TRUE(contents()->cross_navigation_pending());
1055 // Test that a cross-site navigation is not preempted if the previous
1056 // renderer sends a FrameNavigate message just before being told to stop.
1057 // We should only preempt the cross-site navigation if the previous renderer
1058 // has started a new navigation. See http://crbug.com/79176.
1059 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1060 contents()->transition_cross_site
= true;
1062 // Navigate to NTP URL.
1063 const GURL
url("chrome://blah");
1064 controller().LoadURL(
1065 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1066 TestRenderViewHost
* orig_rvh
= test_rvh();
1067 EXPECT_FALSE(contents()->cross_navigation_pending());
1069 // Navigate to new site, with the beforeunload request in flight.
1070 const GURL
url2("http://www.yahoo.com");
1071 controller().LoadURL(
1072 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1073 TestRenderViewHost
* pending_rvh
=
1074 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
1075 EXPECT_TRUE(contents()->cross_navigation_pending());
1076 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
1078 // Suppose the first navigation tries to commit now, with a
1079 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1080 // but it should act as if the beforeunload ack arrived.
1081 orig_rvh
->SendNavigate(1, GURL("chrome://blah"));
1082 EXPECT_TRUE(contents()->cross_navigation_pending());
1083 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1084 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1086 // The pending navigation should be able to commit successfully.
1087 contents()->TestDidNavigate(pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1088 EXPECT_FALSE(contents()->cross_navigation_pending());
1089 EXPECT_EQ(pending_rvh
, contents()->GetRenderViewHost());
1092 // Test that the original renderer cannot preempt a cross-site navigation once
1093 // the unload request has been made. At this point, the cross-site navigation
1094 // is almost ready to be displayed, and the original renderer is only given a
1095 // short chance to run an unload handler. Prevents regression of bug 23942.
1096 TEST_F(WebContentsImplTest
, CrossSiteCantPreemptAfterUnload
) {
1097 contents()->transition_cross_site
= true;
1098 TestRenderViewHost
* orig_rvh
= test_rvh();
1099 SiteInstance
* instance1
= contents()->GetSiteInstance();
1101 // Navigate to URL. First URL should use first RenderViewHost.
1102 const GURL
url("http://www.google.com");
1103 controller().LoadURL(
1104 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1105 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1106 EXPECT_FALSE(contents()->cross_navigation_pending());
1107 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1109 // Navigate to new site, simulating an onbeforeunload approval.
1110 const GURL
url2("http://www.yahoo.com");
1111 controller().LoadURL(
1112 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1113 base::TimeTicks now
= base::TimeTicks::Now();
1114 orig_rvh
->GetMainFrame()->OnMessageReceived(
1115 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1116 EXPECT_TRUE(contents()->cross_navigation_pending());
1117 TestRenderViewHost
* pending_rvh
= static_cast<TestRenderViewHost
*>(
1118 contents()->GetPendingRenderViewHost());
1120 // Simulate the pending renderer's response, which leads to an unload request
1121 // being sent to orig_rvh.
1122 std::vector
<GURL
> url_chain
;
1123 url_chain
.push_back(GURL());
1124 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1125 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1126 GlobalRequestID(0, 0), scoped_ptr
<CrossSiteTransferringRequest
>(),
1127 url_chain
, Referrer(), PAGE_TRANSITION_TYPED
, false);
1129 // Suppose the original renderer navigates now, while the unload request is in
1130 // flight. We should ignore it, wait for the unload ack, and let the pending
1131 // request continue. Otherwise, the contents may close spontaneously or stop
1132 // responding to navigation requests. (See bug 23942.)
1133 FrameHostMsg_DidCommitProvisionalLoad_Params params1a
;
1134 InitNavigateParams(¶ms1a
, 2, GURL("http://www.google.com/foo"),
1135 PAGE_TRANSITION_TYPED
);
1136 orig_rvh
->SendNavigate(2, GURL("http://www.google.com/foo"));
1138 // Verify that the pending navigation is still in progress.
1139 EXPECT_TRUE(contents()->cross_navigation_pending());
1140 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL
);
1142 // DidNavigate from the pending page should commit it.
1143 contents()->TestDidNavigate(
1144 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1145 SiteInstance
* instance2
= contents()->GetSiteInstance();
1146 EXPECT_FALSE(contents()->cross_navigation_pending());
1147 EXPECT_EQ(pending_rvh
, rvh());
1148 EXPECT_NE(instance1
, instance2
);
1149 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
1152 // Test that a cross-site navigation that doesn't commit after the unload
1153 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1154 TEST_F(WebContentsImplTest
, CrossSiteNavigationCanceled
) {
1155 contents()->transition_cross_site
= true;
1156 TestRenderViewHost
* orig_rvh
= test_rvh();
1157 SiteInstance
* instance1
= contents()->GetSiteInstance();
1159 // Navigate to URL. First URL should use first RenderViewHost.
1160 const GURL
url("http://www.google.com");
1161 controller().LoadURL(
1162 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1163 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1164 EXPECT_FALSE(contents()->cross_navigation_pending());
1165 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1167 // Navigate to new site, simulating an onbeforeunload approval.
1168 const GURL
url2("http://www.yahoo.com");
1169 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1170 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
1171 base::TimeTicks now
= base::TimeTicks::Now();
1172 orig_rvh
->GetMainFrame()->OnMessageReceived(
1173 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1174 EXPECT_TRUE(contents()->cross_navigation_pending());
1176 // Simulate swap out message when the response arrives.
1177 orig_rvh
->OnSwappedOut(false);
1179 // Suppose the navigation doesn't get a chance to commit, and the user
1180 // navigates in the current RVH's SiteInstance.
1181 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1183 // Verify that the pending navigation is cancelled and the renderer is no
1184 // longer swapped out.
1185 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1186 SiteInstance
* instance2
= contents()->GetSiteInstance();
1187 EXPECT_FALSE(contents()->cross_navigation_pending());
1188 EXPECT_EQ(orig_rvh
, rvh());
1189 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT
, orig_rvh
->rvh_state());
1190 EXPECT_EQ(instance1
, instance2
);
1191 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
1194 // Test that NavigationEntries have the correct page state after going
1195 // forward and back. Prevents regression for bug 1116137.
1196 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1197 TestRenderViewHost
* orig_rvh
= test_rvh();
1199 // Navigate to URL. There should be no committed entry yet.
1200 const GURL
url("http://www.google.com");
1201 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1202 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1203 EXPECT_TRUE(entry
== NULL
);
1205 // Committed entry should have page state after DidNavigate.
1206 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1207 entry
= controller().GetLastCommittedEntry();
1208 EXPECT_TRUE(entry
->GetPageState().IsValid());
1210 // Navigate to same site.
1211 const GURL
url2("http://images.google.com");
1212 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1213 entry
= controller().GetLastCommittedEntry();
1214 EXPECT_TRUE(entry
->GetPageState().IsValid());
1216 // Committed entry should have page state after DidNavigate.
1217 contents()->TestDidNavigate(orig_rvh
, 2, url2
, PAGE_TRANSITION_TYPED
);
1218 entry
= controller().GetLastCommittedEntry();
1219 EXPECT_TRUE(entry
->GetPageState().IsValid());
1221 // Now go back. Committed entry should still have page state.
1222 controller().GoBack();
1223 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1224 entry
= controller().GetLastCommittedEntry();
1225 EXPECT_TRUE(entry
->GetPageState().IsValid());
1228 // Test that NavigationEntries have the correct page state and SiteInstance
1229 // state after opening a new window to about:blank. Prevents regression for
1230 // bugs b/1116137 and http://crbug.com/111975.
1231 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1232 TestRenderViewHost
* orig_rvh
= test_rvh();
1234 // When opening a new window, it is navigated to about:blank internally.
1235 // Currently, this results in two DidNavigate events.
1236 const GURL
url(url::kAboutBlankURL
);
1237 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1238 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1240 // Should have a page state here.
1241 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1242 EXPECT_TRUE(entry
->GetPageState().IsValid());
1244 // The SiteInstance should be available for other navigations to use.
1245 NavigationEntryImpl
* entry_impl
=
1246 NavigationEntryImpl::FromNavigationEntry(entry
);
1247 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1248 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1250 // Navigating to a normal page should not cause a process swap.
1251 const GURL
new_url("http://www.google.com");
1252 controller().LoadURL(new_url
, Referrer(),
1253 PAGE_TRANSITION_TYPED
, std::string());
1254 EXPECT_FALSE(contents()->cross_navigation_pending());
1255 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1256 contents()->TestDidNavigate(orig_rvh
, 1, new_url
, PAGE_TRANSITION_TYPED
);
1257 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1258 controller().GetLastCommittedEntry());
1259 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1260 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1263 // Tests that fullscreen is exited throughout the object hierarchy when
1264 // navigating to a new page.
1265 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1266 FakeFullscreenDelegate fake_delegate
;
1267 contents()->SetDelegate(&fake_delegate
);
1268 TestRenderViewHost
* orig_rvh
= test_rvh();
1270 // Navigate to a site.
1271 const GURL
url("http://www.google.com");
1272 controller().LoadURL(
1273 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1274 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1275 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1277 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1278 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1279 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1280 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1281 orig_rvh
->OnMessageReceived(
1282 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1283 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1284 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1285 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1287 // Navigate to a new site.
1288 const GURL
url2("http://www.yahoo.com");
1289 controller().LoadURL(
1290 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1291 RenderViewHost
* const pending_rvh
= contents()->GetPendingRenderViewHost();
1292 contents()->TestDidNavigate(
1293 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1295 // Confirm fullscreen has exited.
1296 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1297 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1298 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1300 contents()->SetDelegate(NULL
);
1303 // Tests that fullscreen is exited throughout the object hierarchy when
1304 // instructing NavigationController to GoBack() or GoForward().
1305 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1306 FakeFullscreenDelegate fake_delegate
;
1307 contents()->SetDelegate(&fake_delegate
);
1308 TestRenderViewHost
* const orig_rvh
= test_rvh();
1310 // Navigate to a site.
1311 const GURL
url("http://www.google.com");
1312 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1313 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1314 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1316 // Now, navigate to another page on the same site.
1317 const GURL
url2("http://www.google.com/search?q=kittens");
1318 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1319 EXPECT_FALSE(contents()->cross_navigation_pending());
1320 contents()->TestDidNavigate(orig_rvh
, 2, url2
, PAGE_TRANSITION_TYPED
);
1321 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1323 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1324 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1325 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1326 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1328 for (int i
= 0; i
< 2; ++i
) {
1329 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1330 orig_rvh
->OnMessageReceived(
1331 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1332 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1333 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1334 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1336 // Navigate backward (or forward).
1338 controller().GoBack();
1340 controller().GoForward();
1341 EXPECT_FALSE(contents()->cross_navigation_pending());
1342 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1343 contents()->TestDidNavigate(
1344 orig_rvh
, i
+ 1, url
, PAGE_TRANSITION_FORWARD_BACK
);
1346 // Confirm fullscreen has exited.
1347 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1348 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1349 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1352 contents()->SetDelegate(NULL
);
1355 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1357 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1358 FakeFullscreenDelegate fake_delegate
;
1359 contents()->SetDelegate(&fake_delegate
);
1361 // Navigate to a site.
1362 const GURL
url("http://www.google.com");
1363 controller().LoadURL(
1364 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1365 contents()->TestDidNavigate(test_rvh(), 1, url
, PAGE_TRANSITION_TYPED
);
1366 EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
1368 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1369 EXPECT_FALSE(test_rvh()->IsFullscreen());
1370 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1371 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1372 test_rvh()->OnMessageReceived(
1373 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1374 EXPECT_TRUE(test_rvh()->IsFullscreen());
1375 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1376 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1378 // Crash the renderer.
1379 test_rvh()->OnMessageReceived(
1380 ViewHostMsg_RenderProcessGone(
1381 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1383 // Confirm fullscreen has exited.
1384 EXPECT_FALSE(test_rvh()->IsFullscreen());
1385 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1386 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1388 contents()->SetDelegate(NULL
);
1391 ////////////////////////////////////////////////////////////////////////////////
1392 // Interstitial Tests
1393 ////////////////////////////////////////////////////////////////////////////////
1395 // Test navigating to a page (with the navigation initiated from the browser,
1396 // as when a URL is typed in the location bar) that shows an interstitial and
1397 // creates a new navigation entry, then hiding it without proceeding.
1398 TEST_F(WebContentsImplTest
,
1399 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1400 // Navigate to a page.
1401 GURL
url1("http://www.google.com");
1402 test_rvh()->SendNavigate(1, url1
);
1403 EXPECT_EQ(1, controller().GetEntryCount());
1405 // Initiate a browser navigation that will trigger the interstitial
1406 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1407 PAGE_TRANSITION_TYPED
, std::string());
1409 // Show an interstitial.
1410 TestInterstitialPage::InterstitialState state
=
1411 TestInterstitialPage::INVALID
;
1412 bool deleted
= false;
1413 GURL
url2("http://interstitial");
1414 TestInterstitialPage
* interstitial
=
1415 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1416 TestInterstitialPageStateGuard
state_guard(interstitial
);
1417 interstitial
->Show();
1418 // The interstitial should not show until its navigation has committed.
1419 EXPECT_FALSE(interstitial
->is_showing());
1420 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1421 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1422 // Let's commit the interstitial navigation.
1423 interstitial
->TestDidNavigate(1, url2
);
1424 EXPECT_TRUE(interstitial
->is_showing());
1425 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1426 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1427 NavigationEntry
* entry
= controller().GetVisibleEntry();
1428 ASSERT_TRUE(entry
!= NULL
);
1429 EXPECT_TRUE(entry
->GetURL() == url2
);
1431 // Now don't proceed.
1432 interstitial
->DontProceed();
1433 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1434 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1435 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1436 entry
= controller().GetVisibleEntry();
1437 ASSERT_TRUE(entry
!= NULL
);
1438 EXPECT_TRUE(entry
->GetURL() == url1
);
1439 EXPECT_EQ(1, controller().GetEntryCount());
1441 RunAllPendingInMessageLoop();
1442 EXPECT_TRUE(deleted
);
1445 // Test navigating to a page (with the navigation initiated from the renderer,
1446 // as when clicking on a link in the page) that shows an interstitial and
1447 // creates a new navigation entry, then hiding it without proceeding.
1448 TEST_F(WebContentsImplTest
,
1449 ShowInterstitiaFromRendererlWithNewNavigationDontProceed
) {
1450 // Navigate to a page.
1451 GURL
url1("http://www.google.com");
1452 test_rvh()->SendNavigate(1, url1
);
1453 EXPECT_EQ(1, controller().GetEntryCount());
1455 // Show an interstitial (no pending entry, the interstitial would have been
1456 // triggered by clicking on a link).
1457 TestInterstitialPage::InterstitialState state
=
1458 TestInterstitialPage::INVALID
;
1459 bool deleted
= false;
1460 GURL
url2("http://interstitial");
1461 TestInterstitialPage
* interstitial
=
1462 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1463 TestInterstitialPageStateGuard
state_guard(interstitial
);
1464 interstitial
->Show();
1465 // The interstitial should not show until its navigation has committed.
1466 EXPECT_FALSE(interstitial
->is_showing());
1467 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1468 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1469 // Let's commit the interstitial navigation.
1470 interstitial
->TestDidNavigate(1, url2
);
1471 EXPECT_TRUE(interstitial
->is_showing());
1472 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1473 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1474 NavigationEntry
* entry
= controller().GetVisibleEntry();
1475 ASSERT_TRUE(entry
!= NULL
);
1476 EXPECT_TRUE(entry
->GetURL() == url2
);
1478 // Now don't proceed.
1479 interstitial
->DontProceed();
1480 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1481 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1482 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1483 entry
= controller().GetVisibleEntry();
1484 ASSERT_TRUE(entry
!= NULL
);
1485 EXPECT_TRUE(entry
->GetURL() == url1
);
1486 EXPECT_EQ(1, controller().GetEntryCount());
1488 RunAllPendingInMessageLoop();
1489 EXPECT_TRUE(deleted
);
1492 // Test navigating to a page that shows an interstitial without creating a new
1493 // navigation entry (this happens when the interstitial is triggered by a
1494 // sub-resource in the page), then hiding it without proceeding.
1495 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1496 // Navigate to a page.
1497 GURL
url1("http://www.google.com");
1498 test_rvh()->SendNavigate(1, url1
);
1499 EXPECT_EQ(1, controller().GetEntryCount());
1501 // Show an interstitial.
1502 TestInterstitialPage::InterstitialState state
=
1503 TestInterstitialPage::INVALID
;
1504 bool deleted
= false;
1505 GURL
url2("http://interstitial");
1506 TestInterstitialPage
* interstitial
=
1507 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1508 TestInterstitialPageStateGuard
state_guard(interstitial
);
1509 interstitial
->Show();
1510 // The interstitial should not show until its navigation has committed.
1511 EXPECT_FALSE(interstitial
->is_showing());
1512 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1513 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1514 // Let's commit the interstitial navigation.
1515 interstitial
->TestDidNavigate(1, url2
);
1516 EXPECT_TRUE(interstitial
->is_showing());
1517 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1518 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1519 NavigationEntry
* entry
= controller().GetVisibleEntry();
1520 ASSERT_TRUE(entry
!= NULL
);
1521 // The URL specified to the interstitial should have been ignored.
1522 EXPECT_TRUE(entry
->GetURL() == url1
);
1524 // Now don't proceed.
1525 interstitial
->DontProceed();
1526 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1527 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1528 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1529 entry
= controller().GetVisibleEntry();
1530 ASSERT_TRUE(entry
!= NULL
);
1531 EXPECT_TRUE(entry
->GetURL() == url1
);
1532 EXPECT_EQ(1, controller().GetEntryCount());
1534 RunAllPendingInMessageLoop();
1535 EXPECT_TRUE(deleted
);
1538 // Test navigating to a page (with the navigation initiated from the browser,
1539 // as when a URL is typed in the location bar) that shows an interstitial and
1540 // creates a new navigation entry, then proceeding.
1541 TEST_F(WebContentsImplTest
,
1542 ShowInterstitialFromBrowserNewNavigationProceed
) {
1543 // Navigate to a page.
1544 GURL
url1("http://www.google.com");
1545 test_rvh()->SendNavigate(1, url1
);
1546 EXPECT_EQ(1, controller().GetEntryCount());
1548 // Initiate a browser navigation that will trigger the interstitial
1549 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1550 PAGE_TRANSITION_TYPED
, std::string());
1552 // Show an interstitial.
1553 TestInterstitialPage::InterstitialState state
=
1554 TestInterstitialPage::INVALID
;
1555 bool deleted
= false;
1556 GURL
url2("http://interstitial");
1557 TestInterstitialPage
* interstitial
=
1558 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1559 TestInterstitialPageStateGuard
state_guard(interstitial
);
1560 interstitial
->Show();
1561 // The interstitial should not show until its navigation has committed.
1562 EXPECT_FALSE(interstitial
->is_showing());
1563 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1564 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1565 // Let's commit the interstitial navigation.
1566 interstitial
->TestDidNavigate(1, url2
);
1567 EXPECT_TRUE(interstitial
->is_showing());
1568 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1569 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1570 NavigationEntry
* entry
= controller().GetVisibleEntry();
1571 ASSERT_TRUE(entry
!= NULL
);
1572 EXPECT_TRUE(entry
->GetURL() == url2
);
1575 interstitial
->Proceed();
1576 // The interstitial should show until the new navigation commits.
1577 RunAllPendingInMessageLoop();
1578 ASSERT_FALSE(deleted
);
1579 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1580 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1581 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1583 // Simulate the navigation to the page, that's when the interstitial gets
1585 GURL
url3("http://www.thepage.com");
1586 test_rvh()->SendNavigate(2, url3
);
1588 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1589 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1590 entry
= controller().GetVisibleEntry();
1591 ASSERT_TRUE(entry
!= NULL
);
1592 EXPECT_TRUE(entry
->GetURL() == url3
);
1594 EXPECT_EQ(2, controller().GetEntryCount());
1596 RunAllPendingInMessageLoop();
1597 EXPECT_TRUE(deleted
);
1600 // Test navigating to a page (with the navigation initiated from the renderer,
1601 // as when clicking on a link in the page) that shows an interstitial and
1602 // creates a new navigation entry, then proceeding.
1603 TEST_F(WebContentsImplTest
,
1604 ShowInterstitialFromRendererNewNavigationProceed
) {
1605 // Navigate to a page.
1606 GURL
url1("http://www.google.com");
1607 test_rvh()->SendNavigate(1, url1
);
1608 EXPECT_EQ(1, controller().GetEntryCount());
1610 // Show an interstitial.
1611 TestInterstitialPage::InterstitialState state
=
1612 TestInterstitialPage::INVALID
;
1613 bool deleted
= false;
1614 GURL
url2("http://interstitial");
1615 TestInterstitialPage
* interstitial
=
1616 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1617 TestInterstitialPageStateGuard
state_guard(interstitial
);
1618 interstitial
->Show();
1619 // The interstitial should not show until its navigation has committed.
1620 EXPECT_FALSE(interstitial
->is_showing());
1621 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1622 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1623 // Let's commit the interstitial navigation.
1624 interstitial
->TestDidNavigate(1, url2
);
1625 EXPECT_TRUE(interstitial
->is_showing());
1626 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1627 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1628 NavigationEntry
* entry
= controller().GetVisibleEntry();
1629 ASSERT_TRUE(entry
!= NULL
);
1630 EXPECT_TRUE(entry
->GetURL() == url2
);
1633 interstitial
->Proceed();
1634 // The interstitial should show until the new navigation commits.
1635 RunAllPendingInMessageLoop();
1636 ASSERT_FALSE(deleted
);
1637 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1638 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1639 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1641 // Simulate the navigation to the page, that's when the interstitial gets
1643 GURL
url3("http://www.thepage.com");
1644 test_rvh()->SendNavigate(2, url3
);
1646 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1647 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1648 entry
= controller().GetVisibleEntry();
1649 ASSERT_TRUE(entry
!= NULL
);
1650 EXPECT_TRUE(entry
->GetURL() == url3
);
1652 EXPECT_EQ(2, controller().GetEntryCount());
1654 RunAllPendingInMessageLoop();
1655 EXPECT_TRUE(deleted
);
1658 // Test navigating to a page that shows an interstitial without creating a new
1659 // navigation entry (this happens when the interstitial is triggered by a
1660 // sub-resource in the page), then proceeding.
1661 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1662 // Navigate to a page so we have a navigation entry in the controller.
1663 GURL
url1("http://www.google.com");
1664 test_rvh()->SendNavigate(1, url1
);
1665 EXPECT_EQ(1, controller().GetEntryCount());
1667 // Show an interstitial.
1668 TestInterstitialPage::InterstitialState state
=
1669 TestInterstitialPage::INVALID
;
1670 bool deleted
= false;
1671 GURL
url2("http://interstitial");
1672 TestInterstitialPage
* interstitial
=
1673 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1674 TestInterstitialPageStateGuard
state_guard(interstitial
);
1675 interstitial
->Show();
1676 // The interstitial should not show until its navigation has committed.
1677 EXPECT_FALSE(interstitial
->is_showing());
1678 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1679 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1680 // Let's commit the interstitial navigation.
1681 interstitial
->TestDidNavigate(1, url2
);
1682 EXPECT_TRUE(interstitial
->is_showing());
1683 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1684 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1685 NavigationEntry
* entry
= controller().GetVisibleEntry();
1686 ASSERT_TRUE(entry
!= NULL
);
1687 // The URL specified to the interstitial should have been ignored.
1688 EXPECT_TRUE(entry
->GetURL() == url1
);
1691 interstitial
->Proceed();
1692 // Since this is not a new navigation, the previous page is dismissed right
1693 // away and shows the original page.
1694 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1695 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1696 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1697 entry
= controller().GetVisibleEntry();
1698 ASSERT_TRUE(entry
!= NULL
);
1699 EXPECT_TRUE(entry
->GetURL() == url1
);
1701 EXPECT_EQ(1, controller().GetEntryCount());
1703 RunAllPendingInMessageLoop();
1704 EXPECT_TRUE(deleted
);
1707 // Test navigating to a page that shows an interstitial, then navigating away.
1708 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1709 // Show interstitial.
1710 TestInterstitialPage::InterstitialState state
=
1711 TestInterstitialPage::INVALID
;
1712 bool deleted
= false;
1713 GURL
url("http://interstitial");
1714 TestInterstitialPage
* interstitial
=
1715 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1716 TestInterstitialPageStateGuard
state_guard(interstitial
);
1717 interstitial
->Show();
1718 interstitial
->TestDidNavigate(1, url
);
1720 // While interstitial showing, navigate to a new URL.
1721 const GURL
url2("http://www.yahoo.com");
1722 test_rvh()->SendNavigate(1, url2
);
1724 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1726 RunAllPendingInMessageLoop();
1727 EXPECT_TRUE(deleted
);
1730 // Test navigating to a page that shows an interstitial, then going back.
1731 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1732 // Navigate to a page so we have a navigation entry in the controller.
1733 GURL
url1("http://www.google.com");
1734 test_rvh()->SendNavigate(1, url1
);
1735 EXPECT_EQ(1, controller().GetEntryCount());
1737 // Show interstitial.
1738 TestInterstitialPage::InterstitialState state
=
1739 TestInterstitialPage::INVALID
;
1740 bool deleted
= false;
1741 GURL
interstitial_url("http://interstitial");
1742 TestInterstitialPage
* interstitial
=
1743 new TestInterstitialPage(contents(), true, interstitial_url
,
1745 TestInterstitialPageStateGuard
state_guard(interstitial
);
1746 interstitial
->Show();
1747 interstitial
->TestDidNavigate(2, interstitial_url
);
1749 // While the interstitial is showing, go back.
1750 controller().GoBack();
1751 test_rvh()->SendNavigate(1, url1
);
1753 // Make sure we are back to the original page and that the interstitial is
1755 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1756 NavigationEntry
* entry
= controller().GetVisibleEntry();
1758 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1760 RunAllPendingInMessageLoop();
1761 EXPECT_TRUE(deleted
);
1764 // Test navigating to a page that shows an interstitial, has a renderer crash,
1765 // and then goes back.
1766 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1767 // Navigate to a page so we have a navigation entry in the controller.
1768 GURL
url1("http://www.google.com");
1769 test_rvh()->SendNavigate(1, url1
);
1770 EXPECT_EQ(1, controller().GetEntryCount());
1772 // Show interstitial.
1773 TestInterstitialPage::InterstitialState state
=
1774 TestInterstitialPage::INVALID
;
1775 bool deleted
= false;
1776 GURL
interstitial_url("http://interstitial");
1777 TestInterstitialPage
* interstitial
=
1778 new TestInterstitialPage(contents(), true, interstitial_url
,
1780 TestInterstitialPageStateGuard
state_guard(interstitial
);
1781 interstitial
->Show();
1782 interstitial
->TestDidNavigate(2, interstitial_url
);
1784 // Crash the renderer
1785 test_rvh()->OnMessageReceived(
1786 ViewHostMsg_RenderProcessGone(
1787 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1789 // While the interstitial is showing, go back.
1790 controller().GoBack();
1791 test_rvh()->SendNavigate(1, url1
);
1793 // Make sure we are back to the original page and that the interstitial is
1795 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1796 NavigationEntry
* entry
= controller().GetVisibleEntry();
1798 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1800 RunAllPendingInMessageLoop();
1801 EXPECT_TRUE(deleted
);
1804 // Test navigating to a page that shows an interstitial, has the renderer crash,
1805 // and then navigates to the interstitial.
1806 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1807 // Navigate to a page so we have a navigation entry in the controller.
1808 GURL
url1("http://www.google.com");
1809 test_rvh()->SendNavigate(1, url1
);
1810 EXPECT_EQ(1, controller().GetEntryCount());
1812 // Show interstitial.
1813 TestInterstitialPage::InterstitialState state
=
1814 TestInterstitialPage::INVALID
;
1815 bool deleted
= false;
1816 GURL
interstitial_url("http://interstitial");
1817 TestInterstitialPage
* interstitial
=
1818 new TestInterstitialPage(contents(), true, interstitial_url
,
1820 TestInterstitialPageStateGuard
state_guard(interstitial
);
1821 interstitial
->Show();
1823 // Crash the renderer
1824 test_rvh()->OnMessageReceived(
1825 ViewHostMsg_RenderProcessGone(
1826 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1828 interstitial
->TestDidNavigate(2, interstitial_url
);
1831 // Test navigating to a page that shows an interstitial, then close the
1833 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1834 // Show interstitial.
1835 TestInterstitialPage::InterstitialState state
=
1836 TestInterstitialPage::INVALID
;
1837 bool deleted
= false;
1838 GURL
url("http://interstitial");
1839 TestInterstitialPage
* interstitial
=
1840 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1841 TestInterstitialPageStateGuard
state_guard(interstitial
);
1842 interstitial
->Show();
1843 interstitial
->TestDidNavigate(1, url
);
1845 // Now close the contents.
1847 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1849 RunAllPendingInMessageLoop();
1850 EXPECT_TRUE(deleted
);
1853 // Test navigating to a page that shows an interstitial, then close the
1855 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
1856 // Show interstitial.
1857 TestInterstitialPage::InterstitialState state
=
1858 TestInterstitialPage::INVALID
;
1859 bool deleted
= false;
1860 GURL
url("http://interstitial");
1861 TestInterstitialPage
* interstitial
=
1862 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1863 TestInterstitialPageStateGuard
state_guard(interstitial
);
1864 interstitial
->Show();
1865 interstitial
->TestDidNavigate(1, url
);
1866 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
1867 interstitial
->GetRenderViewHostForTesting());
1869 // Now close the contents.
1871 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1873 // Before the interstitial has a chance to process its shutdown task,
1874 // simulate quitting the browser. This goes through all processes and
1875 // tells them to destruct.
1876 rvh
->OnMessageReceived(
1877 ViewHostMsg_RenderProcessGone(0, 0, 0));
1879 RunAllPendingInMessageLoop();
1880 EXPECT_TRUE(deleted
);
1883 // Test that after Proceed is called and an interstitial is still shown, no more
1884 // commands get executed.
1885 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
1886 // Navigate to a page so we have a navigation entry in the controller.
1887 GURL
url1("http://www.google.com");
1888 test_rvh()->SendNavigate(1, url1
);
1889 EXPECT_EQ(1, controller().GetEntryCount());
1891 // Show an interstitial.
1892 TestInterstitialPage::InterstitialState state
=
1893 TestInterstitialPage::INVALID
;
1894 bool deleted
= false;
1895 GURL
url2("http://interstitial");
1896 TestInterstitialPage
* interstitial
=
1897 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1898 TestInterstitialPageStateGuard
state_guard(interstitial
);
1899 interstitial
->Show();
1900 interstitial
->TestDidNavigate(1, url2
);
1903 EXPECT_EQ(0, interstitial
->command_received_count());
1904 interstitial
->TestDomOperationResponse("toto");
1905 EXPECT_EQ(1, interstitial
->command_received_count());
1908 interstitial
->Proceed();
1909 RunAllPendingInMessageLoop();
1910 ASSERT_FALSE(deleted
);
1912 // While the navigation to the new page is pending, send other commands, they
1913 // should be ignored.
1914 interstitial
->TestDomOperationResponse("hello");
1915 interstitial
->TestDomOperationResponse("hi");
1916 EXPECT_EQ(1, interstitial
->command_received_count());
1919 // Test showing an interstitial while another interstitial is already showing.
1920 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
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 // Now show another interstitial.
1938 TestInterstitialPage::InterstitialState state2
=
1939 TestInterstitialPage::INVALID
;
1940 bool deleted2
= false;
1941 GURL
url2("http://interstitial2");
1942 TestInterstitialPage
* interstitial2
=
1943 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
1944 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
1945 interstitial2
->Show();
1946 interstitial2
->TestDidNavigate(1, url2
);
1948 // Showing interstitial2 should have caused interstitial1 to go away.
1949 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
1950 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
1952 RunAllPendingInMessageLoop();
1953 EXPECT_TRUE(deleted1
);
1954 ASSERT_FALSE(deleted2
);
1956 // Let's make sure interstitial2 is working as intended.
1957 interstitial2
->Proceed();
1958 GURL
landing_url("http://www.thepage.com");
1959 test_rvh()->SendNavigate(2, landing_url
);
1961 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1962 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1963 NavigationEntry
* entry
= controller().GetVisibleEntry();
1964 ASSERT_TRUE(entry
!= NULL
);
1965 EXPECT_TRUE(entry
->GetURL() == landing_url
);
1966 EXPECT_EQ(2, controller().GetEntryCount());
1967 RunAllPendingInMessageLoop();
1968 EXPECT_TRUE(deleted2
);
1971 // Test showing an interstitial, proceeding and then navigating to another
1973 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
1974 // Navigate to a page so we have a navigation entry in the controller.
1975 GURL
start_url("http://www.google.com");
1976 test_rvh()->SendNavigate(1, start_url
);
1977 EXPECT_EQ(1, controller().GetEntryCount());
1979 // Show an interstitial.
1980 TestInterstitialPage::InterstitialState state1
=
1981 TestInterstitialPage::INVALID
;
1982 bool deleted1
= false;
1983 GURL
url1("http://interstitial1");
1984 TestInterstitialPage
* interstitial1
=
1985 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
1986 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
1987 interstitial1
->Show();
1988 interstitial1
->TestDidNavigate(1, url1
);
1990 // Take action. The interstitial won't be hidden until the navigation is
1992 interstitial1
->Proceed();
1993 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
1995 // Now show another interstitial (simulating the navigation causing another
1997 TestInterstitialPage::InterstitialState state2
=
1998 TestInterstitialPage::INVALID
;
1999 bool deleted2
= false;
2000 GURL
url2("http://interstitial2");
2001 TestInterstitialPage
* interstitial2
=
2002 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2003 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2004 interstitial2
->Show();
2005 interstitial2
->TestDidNavigate(1, url2
);
2007 // Showing interstitial2 should have caused interstitial1 to go away.
2008 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2009 RunAllPendingInMessageLoop();
2010 EXPECT_TRUE(deleted1
);
2011 ASSERT_FALSE(deleted2
);
2013 // Let's make sure interstitial2 is working as intended.
2014 interstitial2
->Proceed();
2015 GURL
landing_url("http://www.thepage.com");
2016 test_rvh()->SendNavigate(2, landing_url
);
2018 RunAllPendingInMessageLoop();
2019 EXPECT_TRUE(deleted2
);
2020 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2021 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2022 NavigationEntry
* entry
= controller().GetVisibleEntry();
2023 ASSERT_TRUE(entry
!= NULL
);
2024 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2025 EXPECT_EQ(2, controller().GetEntryCount());
2028 // Test that navigating away from an interstitial while it's loading cause it
2030 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2031 // Show an interstitial.
2032 TestInterstitialPage::InterstitialState state
=
2033 TestInterstitialPage::INVALID
;
2034 bool deleted
= false;
2035 GURL
interstitial_url("http://interstitial");
2036 TestInterstitialPage
* interstitial
=
2037 new TestInterstitialPage(contents(), true, interstitial_url
,
2039 TestInterstitialPageStateGuard
state_guard(interstitial
);
2040 interstitial
->Show();
2042 // Let's simulate a navigation initiated from the browser before the
2043 // interstitial finishes loading.
2044 const GURL
url("http://www.google.com");
2045 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2046 EXPECT_FALSE(interstitial
->is_showing());
2047 RunAllPendingInMessageLoop();
2048 ASSERT_FALSE(deleted
);
2050 // Now let's make the interstitial navigation commit.
2051 interstitial
->TestDidNavigate(1, interstitial_url
);
2053 // After it loaded the interstitial should be gone.
2054 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2056 RunAllPendingInMessageLoop();
2057 EXPECT_TRUE(deleted
);
2060 // Test that a new request to show an interstitial while an interstitial is
2061 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2062 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2063 GURL
interstitial_url("http://interstitial");
2065 // Show a first interstitial.
2066 TestInterstitialPage::InterstitialState state1
=
2067 TestInterstitialPage::INVALID
;
2068 bool deleted1
= false;
2069 TestInterstitialPage
* interstitial1
=
2070 new TestInterstitialPage(contents(), true, interstitial_url
,
2071 &state1
, &deleted1
);
2072 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2073 interstitial1
->Show();
2075 // Show another interstitial on that same contents before the first one had
2077 TestInterstitialPage::InterstitialState state2
=
2078 TestInterstitialPage::INVALID
;
2079 bool deleted2
= false;
2080 TestInterstitialPage
* interstitial2
=
2081 new TestInterstitialPage(contents(), true, interstitial_url
,
2082 &state2
, &deleted2
);
2083 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2084 interstitial2
->Show();
2086 // The first interstitial should have been closed and deleted.
2087 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2088 // The 2nd one should still be OK.
2089 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2091 RunAllPendingInMessageLoop();
2092 EXPECT_TRUE(deleted1
);
2093 ASSERT_FALSE(deleted2
);
2095 // Make the interstitial navigation commit it should be showing.
2096 interstitial2
->TestDidNavigate(1, interstitial_url
);
2097 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2100 // Test showing an interstitial and have its renderer crash.
2101 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2102 // Show an interstitial.
2103 TestInterstitialPage::InterstitialState state
=
2104 TestInterstitialPage::INVALID
;
2105 bool deleted
= false;
2106 GURL
url("http://interstitial");
2107 TestInterstitialPage
* interstitial
=
2108 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2109 TestInterstitialPageStateGuard
state_guard(interstitial
);
2110 interstitial
->Show();
2111 // Simulate a renderer crash before the interstitial is shown.
2112 interstitial
->TestRenderViewTerminated(
2113 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2114 // The interstitial should have been dismissed.
2115 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2116 RunAllPendingInMessageLoop();
2117 EXPECT_TRUE(deleted
);
2119 // Now try again but this time crash the intersitial after it was shown.
2121 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2122 interstitial
->Show();
2123 interstitial
->TestDidNavigate(1, url
);
2124 // Simulate a renderer crash.
2125 interstitial
->TestRenderViewTerminated(
2126 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2127 // The interstitial should have been dismissed.
2128 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2129 RunAllPendingInMessageLoop();
2130 EXPECT_TRUE(deleted
);
2133 // Tests that showing an interstitial as a result of a browser initiated
2134 // navigation while an interstitial is showing does not remove the pending
2135 // entry (see http://crbug.com/9791).
2136 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2137 const char kUrl
[] = "http://www.badguys.com/";
2138 const GURL
kGURL(kUrl
);
2140 // Start a navigation to a page
2141 contents()->GetController().LoadURL(
2142 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2144 // Simulate that navigation triggering an interstitial.
2145 TestInterstitialPage::InterstitialState state
=
2146 TestInterstitialPage::INVALID
;
2147 bool deleted
= false;
2148 TestInterstitialPage
* interstitial
=
2149 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2150 TestInterstitialPageStateGuard
state_guard(interstitial
);
2151 interstitial
->Show();
2152 interstitial
->TestDidNavigate(1, kGURL
);
2154 // Initiate a new navigation from the browser that also triggers an
2156 contents()->GetController().LoadURL(
2157 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2158 TestInterstitialPage::InterstitialState state2
=
2159 TestInterstitialPage::INVALID
;
2160 bool deleted2
= false;
2161 TestInterstitialPage
* interstitial2
=
2162 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2163 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2164 interstitial2
->Show();
2165 interstitial2
->TestDidNavigate(1, kGURL
);
2167 // Make sure we still have an entry.
2168 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2170 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2172 // And that the first interstitial is gone, but not the second.
2173 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2174 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2175 RunAllPendingInMessageLoop();
2176 EXPECT_TRUE(deleted
);
2177 EXPECT_FALSE(deleted2
);
2180 // Tests that Javascript messages are not shown while an interstitial is
2182 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2183 const char kUrl
[] = "http://www.badguys.com/";
2184 const GURL
kGURL(kUrl
);
2186 // Start a navigation to a page
2187 contents()->GetController().LoadURL(
2188 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2189 // DidNavigate from the page
2190 contents()->TestDidNavigate(rvh(), 1, kGURL
, PAGE_TRANSITION_TYPED
);
2192 // Simulate showing an interstitial while the page is showing.
2193 TestInterstitialPage::InterstitialState state
=
2194 TestInterstitialPage::INVALID
;
2195 bool deleted
= false;
2196 TestInterstitialPage
* interstitial
=
2197 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2198 TestInterstitialPageStateGuard
state_guard(interstitial
);
2199 interstitial
->Show();
2200 interstitial
->TestDidNavigate(1, kGURL
);
2202 // While the interstitial is showing, let's simulate the hidden page
2203 // attempting to show a JS message.
2204 IPC::Message
* dummy_message
= new IPC::Message
;
2205 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2206 base::ASCIIToUTF16("This is an informative message"),
2207 base::ASCIIToUTF16("OK"),
2208 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2209 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2212 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2213 // interstitial it isn't copied over to the destination.
2214 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2215 // Navigate to a page.
2216 GURL
url1("http://www.google.com");
2217 test_rvh()->SendNavigate(1, url1
);
2218 EXPECT_EQ(1, controller().GetEntryCount());
2220 // Initiate a browser navigation that will trigger the interstitial
2221 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2222 PAGE_TRANSITION_TYPED
, std::string());
2224 // Show an interstitial.
2225 TestInterstitialPage::InterstitialState state
=
2226 TestInterstitialPage::INVALID
;
2227 bool deleted
= false;
2228 GURL
url2("http://interstitial");
2229 TestInterstitialPage
* interstitial
=
2230 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2231 TestInterstitialPageStateGuard
state_guard(interstitial
);
2232 interstitial
->Show();
2233 interstitial
->TestDidNavigate(1, url2
);
2234 EXPECT_TRUE(interstitial
->is_showing());
2235 EXPECT_EQ(2, controller().GetEntryCount());
2237 // Create another NavigationController.
2238 GURL
url3("http://foo2");
2239 scoped_ptr
<TestWebContents
> other_contents(
2240 static_cast<TestWebContents
*>(CreateTestWebContents()));
2241 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2242 other_contents
->NavigateAndCommit(url3
);
2243 other_contents
->ExpectSetHistoryLengthAndPrune(
2244 NavigationEntryImpl::FromNavigationEntry(
2245 other_controller
.GetEntryAtIndex(0))->site_instance(), 1,
2246 other_controller
.GetEntryAtIndex(0)->GetPageID());
2247 other_controller
.CopyStateFromAndPrune(&controller(), false);
2249 // The merged controller should only have two entries: url1 and url2.
2250 ASSERT_EQ(2, other_controller
.GetEntryCount());
2251 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2252 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2253 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2255 // And the merged controller shouldn't be showing an interstitial.
2256 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2259 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2260 // showing an interstitial.
2261 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2262 // Navigate to a page.
2263 GURL
url1("http://www.google.com");
2264 contents()->NavigateAndCommit(url1
);
2266 // Create another NavigationController.
2267 scoped_ptr
<TestWebContents
> other_contents(
2268 static_cast<TestWebContents
*>(CreateTestWebContents()));
2269 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2271 // Navigate it to url2.
2272 GURL
url2("http://foo2");
2273 other_contents
->NavigateAndCommit(url2
);
2275 // Show an interstitial.
2276 TestInterstitialPage::InterstitialState state
=
2277 TestInterstitialPage::INVALID
;
2278 bool deleted
= false;
2279 GURL
url3("http://interstitial");
2280 TestInterstitialPage
* interstitial
=
2281 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2283 TestInterstitialPageStateGuard
state_guard(interstitial
);
2284 interstitial
->Show();
2285 interstitial
->TestDidNavigate(1, url3
);
2286 EXPECT_TRUE(interstitial
->is_showing());
2287 EXPECT_EQ(2, other_controller
.GetEntryCount());
2289 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2290 // interstitial is showing in the target.
2291 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2294 // Regression test for http://crbug.com/168611 - the URLs passed by the
2295 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2296 TEST_F(WebContentsImplTest
, FilterURLs
) {
2297 TestWebContentsObserver
observer(contents());
2299 // A navigation to about:whatever should always look like a navigation to
2301 GURL
url_normalized(url::kAboutBlankURL
);
2302 GURL
url_from_ipc("about:whatever");
2304 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2305 // will use the given URL to create the NavigationEntry as well, and that
2306 // entry should contain the filtered URL.
2307 contents()->NavigateAndCommit(url_normalized
);
2309 // Check that an IPC with about:whatever is correctly normalized.
2310 contents()->TestDidFinishLoad(url_from_ipc
);
2312 EXPECT_EQ(url_normalized
, observer
.last_url());
2314 // Create and navigate another WebContents.
2315 scoped_ptr
<TestWebContents
> other_contents(
2316 static_cast<TestWebContents
*>(CreateTestWebContents()));
2317 TestWebContentsObserver
other_observer(other_contents
.get());
2318 other_contents
->NavigateAndCommit(url_normalized
);
2320 // Check that an IPC with about:whatever is correctly normalized.
2321 other_contents
->TestDidFailLoadWithError(
2322 url_from_ipc
, 1, base::string16());
2323 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2326 // Test that if a pending contents is deleted before it is shown, we don't
2328 TEST_F(WebContentsImplTest
, PendingContents
) {
2329 scoped_ptr
<TestWebContents
> other_contents(
2330 static_cast<TestWebContents
*>(CreateTestWebContents()));
2331 contents()->AddPendingContents(other_contents
.get());
2332 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2333 other_contents
.reset();
2334 EXPECT_EQ(NULL
, contents()->GetCreatedWindow(route_id
));
2337 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2338 const gfx::Size
original_preferred_size(1024, 768);
2339 contents()->UpdatePreferredSize(original_preferred_size
);
2341 // With no capturers, expect the preferred size to be the one propagated into
2342 // WebContentsImpl via the RenderViewHostDelegate interface.
2343 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2344 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2346 // Increment capturer count, but without specifying a capture size. Expect
2347 // a "not set" preferred size.
2348 contents()->IncrementCapturerCount(gfx::Size());
2349 EXPECT_EQ(1, contents()->GetCapturerCount());
2350 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2352 // Increment capturer count again, but with an overriding capture size.
2353 // Expect preferred size to now be overridden to the capture size.
2354 const gfx::Size
capture_size(1280, 720);
2355 contents()->IncrementCapturerCount(capture_size
);
2356 EXPECT_EQ(2, contents()->GetCapturerCount());
2357 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2359 // Increment capturer count a third time, but the expect that the preferred
2360 // size is still the first capture size.
2361 const gfx::Size
another_capture_size(720, 480);
2362 contents()->IncrementCapturerCount(another_capture_size
);
2363 EXPECT_EQ(3, contents()->GetCapturerCount());
2364 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2366 // Decrement capturer count twice, but expect the preferred size to still be
2368 contents()->DecrementCapturerCount();
2369 contents()->DecrementCapturerCount();
2370 EXPECT_EQ(1, contents()->GetCapturerCount());
2371 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2373 // Decrement capturer count, and since the count has dropped to zero, the
2374 // original preferred size should be restored.
2375 contents()->DecrementCapturerCount();
2376 EXPECT_EQ(0, contents()->GetCapturerCount());
2377 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2380 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2382 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2383 // The WebContents starts with a valid creation time.
2384 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2386 // Reset the last active time to a known-bad value.
2387 contents()->last_active_time_
= base::TimeTicks();
2388 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2390 // Simulate activating the WebContents. The active time should update.
2391 contents()->WasShown();
2392 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2395 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2397 ContentsZoomChangedDelegate() :
2398 contents_zoom_changed_call_count_(0),
2399 last_zoom_in_(false) {
2402 int GetAndResetContentsZoomChangedCallCount() {
2403 int count
= contents_zoom_changed_call_count_
;
2404 contents_zoom_changed_call_count_
= 0;
2408 bool last_zoom_in() const {
2409 return last_zoom_in_
;
2412 // WebContentsDelegate:
2413 virtual void ContentsZoomChange(bool zoom_in
) OVERRIDE
{
2414 contents_zoom_changed_call_count_
++;
2415 last_zoom_in_
= zoom_in
;
2419 int contents_zoom_changed_call_count_
;
2422 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2425 // Tests that some mouseehweel events get turned into browser zoom requests.
2426 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2427 using blink::WebInputEvent
;
2429 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2430 new ContentsZoomChangedDelegate());
2431 contents()->SetDelegate(delegate
.get());
2434 // Verify that normal mouse wheel events do nothing to change the zoom level.
2435 blink::WebMouseWheelEvent event
=
2436 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2437 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2438 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2440 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
;
2441 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2442 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2443 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2445 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2446 // Except on MacOS where we never want to adjust zoom with mousewheel.
2447 modifiers
= WebInputEvent::ControlKey
;
2448 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2449 bool handled
= contents()->HandleWheelEvent(event
);
2450 #if defined(OS_MACOSX)
2451 EXPECT_FALSE(handled
);
2452 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2454 EXPECT_TRUE(handled
);
2455 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2456 EXPECT_TRUE(delegate
->last_zoom_in());
2459 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2460 WebInputEvent::AltKey
;
2461 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2462 handled
= contents()->HandleWheelEvent(event
);
2463 #if defined(OS_MACOSX)
2464 EXPECT_FALSE(handled
);
2465 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2467 EXPECT_TRUE(handled
);
2468 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2469 EXPECT_FALSE(delegate
->last_zoom_in());
2472 // Unless there is no vertical movement.
2473 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2474 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2475 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2477 // Events containing precise scrolling deltas also shouldn't result in the
2478 // zoom being adjusted, to avoid accidental adjustments caused by
2479 // two-finger-scrolling on a touchpad.
2480 modifiers
= WebInputEvent::ControlKey
;
2481 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2482 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2483 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2485 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2486 contents()->SetDelegate(NULL
);
2489 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2490 TEST_F(WebContentsImplTest
, HandleGestureEvent
) {
2491 using blink::WebGestureEvent
;
2492 using blink::WebInputEvent
;
2494 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2495 new ContentsZoomChangedDelegate());
2496 contents()->SetDelegate(delegate
.get());
2498 const float kZoomStepValue
= 0.6f
;
2499 blink::WebGestureEvent event
= SyntheticWebGestureEventBuilder::Build(
2500 WebInputEvent::GesturePinchUpdate
, blink::WebGestureDeviceTouchpad
);
2502 // A pinch less than the step value doesn't change the zoom level.
2503 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 0.8f
;
2504 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2505 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2507 // But repeating the event so the combined scale is greater does.
2508 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2509 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2510 EXPECT_TRUE(delegate
->last_zoom_in());
2512 // Pinching back out one step goes back to 100%.
2513 event
.data
.pinchUpdate
.scale
= 1.0f
- kZoomStepValue
;
2514 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2515 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2516 EXPECT_FALSE(delegate
->last_zoom_in());
2518 // Pinching out again doesn't zoom (step is twice as large around 100%).
2519 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2520 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2522 // And again now it zooms once per step.
2523 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2524 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2525 EXPECT_FALSE(delegate
->last_zoom_in());
2527 // No other type of gesture event is handled by WebContentsImpl (for example
2528 // a touchscreen pinch gesture).
2529 event
= SyntheticWebGestureEventBuilder::Build(
2530 WebInputEvent::GesturePinchUpdate
, blink::WebGestureDeviceTouchscreen
);
2531 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 3;
2532 EXPECT_FALSE(contents()->HandleGestureEvent(event
));
2533 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2535 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2536 contents()->SetDelegate(NULL
);
2539 // Tests that GetRelatedActiveContentsCount is shared between related
2540 // SiteInstances and includes WebContents that have not navigated yet.
2541 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2542 scoped_refptr
<SiteInstance
> instance1(
2543 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2544 scoped_refptr
<SiteInstance
> instance2(
2545 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2547 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2548 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2550 scoped_ptr
<TestWebContents
> contents1(
2551 TestWebContents::Create(browser_context(), instance1
));
2552 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2553 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2555 scoped_ptr
<TestWebContents
> contents2(
2556 TestWebContents::Create(browser_context(), instance1
));
2557 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2558 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2561 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2562 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2565 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2566 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2569 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2570 // same-site and cross-site navigations.
2571 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2572 scoped_refptr
<SiteInstance
> instance(
2573 SiteInstance::Create(browser_context()));
2575 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2577 scoped_ptr
<TestWebContents
> contents(
2578 TestWebContents::Create(browser_context(), instance
));
2579 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2581 // Navigate to a URL.
2582 contents
->GetController().LoadURL(
2583 GURL("http://a.com/1"), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2584 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2585 contents
->CommitPendingNavigation();
2586 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2588 // Navigate to a URL in the same site.
2589 contents
->GetController().LoadURL(
2590 GURL("http://a.com/2"), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2591 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2592 contents
->CommitPendingNavigation();
2593 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2595 // Navigate to a URL in a different site.
2596 contents
->GetController().LoadURL(
2597 GURL("http://b.com"), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2598 EXPECT_TRUE(contents
->cross_navigation_pending());
2599 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2600 contents
->CommitPendingNavigation();
2601 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2604 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2607 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2609 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2610 scoped_refptr
<SiteInstance
> instance(
2611 SiteInstance::Create(browser_context()));
2613 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2615 scoped_ptr
<TestWebContents
> contents(
2616 TestWebContents::Create(browser_context(), instance
));
2617 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2619 // Navigate to a URL.
2620 contents
->NavigateAndCommit(GURL("http://a.com"));
2621 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2623 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2624 contents
->GetController().LoadURL(
2625 GURL(kTestWebUIUrl
), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2626 EXPECT_TRUE(contents
->cross_navigation_pending());
2627 scoped_refptr
<SiteInstance
> instance_webui(
2628 contents
->GetPendingRenderViewHost()->GetSiteInstance());
2629 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2631 // At this point, contents still counts for the old BrowsingInstance.
2632 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2633 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2635 // Commit and contents counts for the new one.
2636 contents
->CommitPendingNavigation();
2637 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2638 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2641 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2642 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2645 } // namespace content