1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/logging.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "content/browser/frame_host/cross_site_transferring_request.h"
8 #include "content/browser/frame_host/interstitial_page_impl.h"
9 #include "content/browser/frame_host/navigation_entry_impl.h"
10 #include "content/browser/renderer_host/render_view_host_impl.h"
11 #include "content/browser/site_instance_impl.h"
12 #include "content/browser/webui/web_ui_controller_factory_registry.h"
13 #include "content/common/frame_messages.h"
14 #include "content/common/input/synthetic_web_input_event_builders.h"
15 #include "content/common/view_messages.h"
16 #include "content/public/browser/global_request_id.h"
17 #include "content/public/browser/interstitial_page_delegate.h"
18 #include "content/public/browser/navigation_details.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_source.h"
21 #include "content/public/browser/render_widget_host_view.h"
22 #include "content/public/browser/web_contents_delegate.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/browser/web_ui_controller.h"
25 #include "content/public/common/bindings_policy.h"
26 #include "content/public/common/content_constants.h"
27 #include "content/public/common/url_constants.h"
28 #include "content/public/common/url_utils.h"
29 #include "content/public/test/mock_render_process_host.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/test/test_content_browser_client.h"
32 #include "content/test/test_content_client.h"
33 #include "content/test/test_render_view_host.h"
34 #include "content/test/test_web_contents.h"
35 #include "testing/gtest/include/gtest/gtest.h"
40 const char kTestWebUIUrl
[] = "chrome://blah";
42 class WebContentsImplTestWebUIControllerFactory
43 : public WebUIControllerFactory
{
45 virtual WebUIController
* CreateWebUIControllerForURL(
46 WebUI
* web_ui
, const GURL
& url
) const OVERRIDE
{
49 return new WebUIController(web_ui
);
52 virtual WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
53 const GURL
& url
) const OVERRIDE
{
54 return WebUI::kNoWebUI
;
57 virtual bool UseWebUIForURL(BrowserContext
* browser_context
,
58 const GURL
& url
) const OVERRIDE
{
62 virtual bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
63 const GURL
& url
) const OVERRIDE
{
68 bool UseWebUI(const GURL
& url
) const {
69 return url
== GURL(kTestWebUIUrl
);
73 class TestInterstitialPage
;
75 class TestInterstitialPageDelegate
: public InterstitialPageDelegate
{
77 explicit TestInterstitialPageDelegate(TestInterstitialPage
* interstitial_page
)
78 : interstitial_page_(interstitial_page
) {}
79 virtual void CommandReceived(const std::string
& command
) OVERRIDE
;
80 virtual std::string
GetHTMLContents() OVERRIDE
{ return std::string(); }
81 virtual void OnDontProceed() OVERRIDE
;
82 virtual void OnProceed() OVERRIDE
;
84 TestInterstitialPage
* interstitial_page_
;
87 class TestInterstitialPage
: public InterstitialPageImpl
{
89 enum InterstitialState
{
90 INVALID
= 0, // Hasn't yet been initialized.
91 UNDECIDED
, // Initialized, but no decision taken yet.
92 OKED
, // Proceed was called.
93 CANCELED
// DontProceed was called.
98 virtual void TestInterstitialPageDeleted(
99 TestInterstitialPage
* interstitial
) = 0;
102 virtual ~Delegate() {}
105 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
106 // |deleted| (like all interstitial related tests do at this point), make sure
107 // to create an instance of the TestInterstitialPageStateGuard class on the
108 // stack in your test. This will ensure that the TestInterstitialPage states
109 // are cleared when the test finishes.
110 // Not doing so will cause stack trashing if your test does not hide the
111 // interstitial, as in such a case it will be destroyed in the test TearDown
112 // method and will dereference the |deleted| local variable which by then is
114 TestInterstitialPage(WebContentsImpl
* contents
,
117 InterstitialState
* state
,
119 : InterstitialPageImpl(
121 static_cast<RenderWidgetHostDelegate
*>(contents
),
122 new_navigation
, url
, new TestInterstitialPageDelegate(this)),
125 command_received_count_(0),
131 virtual ~TestInterstitialPage() {
135 delegate_
->TestInterstitialPageDeleted(this);
138 void OnDontProceed() {
147 int command_received_count() const {
148 return command_received_count_
;
151 void TestDomOperationResponse(const std::string
& json_string
) {
156 void TestDidNavigate(int page_id
, const GURL
& url
) {
157 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
158 InitNavigateParams(¶ms
, page_id
, url
, PAGE_TRANSITION_TYPED
);
159 DidNavigate(GetRenderViewHostForTesting(), params
);
162 void TestRenderViewTerminated(base::TerminationStatus status
,
164 RenderViewTerminated(GetRenderViewHostForTesting(), status
, error_code
);
167 bool is_showing() const {
168 return static_cast<TestRenderWidgetHostView
*>(
169 GetRenderViewHostForTesting()->GetView())->is_showing();
178 void CommandReceived() {
179 command_received_count_
++;
182 void set_delegate(Delegate
* delegate
) {
183 delegate_
= delegate
;
187 virtual WebContentsView
* CreateWebContentsView() OVERRIDE
{
192 InterstitialState
* state_
;
194 int command_received_count_
;
198 void TestInterstitialPageDelegate::CommandReceived(const std::string
& command
) {
199 interstitial_page_
->CommandReceived();
202 void TestInterstitialPageDelegate::OnDontProceed() {
203 interstitial_page_
->OnDontProceed();
206 void TestInterstitialPageDelegate::OnProceed() {
207 interstitial_page_
->OnProceed();
210 class TestInterstitialPageStateGuard
: public TestInterstitialPage::Delegate
{
212 explicit TestInterstitialPageStateGuard(
213 TestInterstitialPage
* interstitial_page
)
214 : interstitial_page_(interstitial_page
) {
215 DCHECK(interstitial_page_
);
216 interstitial_page_
->set_delegate(this);
218 virtual ~TestInterstitialPageStateGuard() {
219 if (interstitial_page_
)
220 interstitial_page_
->ClearStates();
223 virtual void TestInterstitialPageDeleted(
224 TestInterstitialPage
* interstitial
) OVERRIDE
{
225 DCHECK(interstitial_page_
== interstitial
);
226 interstitial_page_
= NULL
;
230 TestInterstitialPage
* interstitial_page_
;
233 class WebContentsImplTestBrowserClient
: public TestContentBrowserClient
{
235 WebContentsImplTestBrowserClient()
236 : assign_site_for_url_(false) {}
238 virtual ~WebContentsImplTestBrowserClient() {}
240 virtual bool ShouldAssignSiteForURL(const GURL
& url
) OVERRIDE
{
241 return assign_site_for_url_
;
244 void set_assign_site_for_url(bool assign
) {
245 assign_site_for_url_
= assign
;
249 bool assign_site_for_url_
;
252 class WebContentsImplTest
: public RenderViewHostImplTestHarness
{
254 virtual void SetUp() {
255 RenderViewHostImplTestHarness::SetUp();
256 WebUIControllerFactory::RegisterFactory(&factory_
);
259 virtual void TearDown() {
260 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_
);
261 RenderViewHostImplTestHarness::TearDown();
265 WebContentsImplTestWebUIControllerFactory factory_
;
268 class TestWebContentsObserver
: public WebContentsObserver
{
270 explicit TestWebContentsObserver(WebContents
* contents
)
271 : WebContentsObserver(contents
) {
273 virtual ~TestWebContentsObserver() {}
275 virtual void DidFinishLoad(int64 frame_id
,
276 const GURL
& validated_url
,
278 RenderViewHost
* render_view_host
) OVERRIDE
{
279 last_url_
= validated_url
;
281 virtual void DidFailLoad(int64 frame_id
,
282 const GURL
& validated_url
,
285 const base::string16
& error_description
,
286 RenderViewHost
* render_view_host
) OVERRIDE
{
287 last_url_
= validated_url
;
290 const GURL
& last_url() const { return last_url_
; }
295 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver
);
298 // Pretends to be a normal browser that receives toggles and transitions to/from
299 // a fullscreened state.
300 class FakeFullscreenDelegate
: public WebContentsDelegate
{
302 FakeFullscreenDelegate() : fullscreened_contents_(NULL
) {}
303 virtual ~FakeFullscreenDelegate() {}
305 virtual void ToggleFullscreenModeForTab(WebContents
* web_contents
,
306 bool enter_fullscreen
) OVERRIDE
{
307 fullscreened_contents_
= enter_fullscreen
? web_contents
: NULL
;
310 virtual bool IsFullscreenForTabOrPending(const WebContents
* web_contents
)
312 return fullscreened_contents_
&& web_contents
== fullscreened_contents_
;
316 WebContents
* fullscreened_contents_
;
318 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate
);
323 // Test to make sure that title updates get stripped of whitespace.
324 TEST_F(WebContentsImplTest
, UpdateTitle
) {
325 NavigationControllerImpl
& cont
=
326 static_cast<NavigationControllerImpl
&>(controller());
327 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
328 InitNavigateParams(¶ms
, 0, GURL(kAboutBlankURL
), PAGE_TRANSITION_TYPED
);
330 LoadCommittedDetails details
;
331 cont
.RendererDidNavigate(main_test_rfh(), params
, &details
);
333 contents()->UpdateTitle(rvh(), 0,
334 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
335 base::i18n::LEFT_TO_RIGHT
);
336 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
339 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
340 const GURL
kGURL("chrome://blah");
341 controller().LoadURL(
342 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
343 EXPECT_EQ(base::string16(), contents()->GetTitle());
346 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
347 const GURL
kGURL("chrome://blah");
348 const base::string16 title
= base::ASCIIToUTF16("My Title");
349 controller().LoadURL(
350 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
352 NavigationEntry
* entry
= controller().GetVisibleEntry();
353 ASSERT_EQ(kGURL
, entry
->GetURL());
354 entry
->SetTitle(title
);
356 EXPECT_EQ(title
, contents()->GetTitle());
359 // Test view source mode for a webui page.
360 TEST_F(WebContentsImplTest
, NTPViewSource
) {
361 NavigationControllerImpl
& cont
=
362 static_cast<NavigationControllerImpl
&>(controller());
363 const char kUrl
[] = "view-source:chrome://blah";
364 const GURL
kGURL(kUrl
);
366 process()->sink().ClearMessages();
369 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
370 rvh()->GetDelegate()->RenderViewCreated(rvh());
371 // Did we get the expected message?
372 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
373 ViewMsg_EnableViewSourceMode::ID
));
375 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
376 InitNavigateParams(¶ms
, 0, kGURL
, PAGE_TRANSITION_TYPED
);
377 LoadCommittedDetails details
;
378 cont
.RendererDidNavigate(main_test_rfh(), params
, &details
);
379 // Also check title and url.
380 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
383 // Test to ensure UpdateMaxPageID is working properly.
384 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
385 SiteInstance
* instance1
= contents()->GetSiteInstance();
386 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(NULL
));
389 EXPECT_EQ(-1, contents()->GetMaxPageID());
390 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
391 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
393 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
394 contents()->UpdateMaxPageID(3);
395 contents()->UpdateMaxPageID(1);
396 EXPECT_EQ(3, contents()->GetMaxPageID());
397 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
398 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
400 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
401 EXPECT_EQ(3, contents()->GetMaxPageID());
402 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
403 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
406 // Test simple same-SiteInstance navigation.
407 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
408 TestRenderViewHost
* orig_rvh
= test_rvh();
409 SiteInstance
* instance1
= contents()->GetSiteInstance();
410 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
413 const GURL
url("http://www.google.com");
414 controller().LoadURL(
415 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
416 EXPECT_FALSE(contents()->cross_navigation_pending());
417 EXPECT_EQ(instance1
, orig_rvh
->GetSiteInstance());
418 // Controller's pending entry will have a NULL site instance until we assign
419 // it in DidNavigate.
421 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
422 site_instance() == NULL
);
424 // DidNavigate from the page
425 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
426 EXPECT_FALSE(contents()->cross_navigation_pending());
427 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
428 EXPECT_EQ(instance1
, orig_rvh
->GetSiteInstance());
429 // Controller's entry should now have the SiteInstance, or else we won't be
430 // able to find it later.
433 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
437 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
438 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
439 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
440 const GURL
url(std::string("http://example.org/").append(
441 GetMaxURLChars() + 1, 'a'));
443 controller().LoadURL(
444 url
, Referrer(), PAGE_TRANSITION_GENERATED
, std::string());
445 EXPECT_TRUE(controller().GetVisibleEntry() == NULL
);
448 // Test that navigating across a site boundary creates a new RenderViewHost
449 // with a new SiteInstance. Going back should do the same.
450 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
451 contents()->transition_cross_site
= true;
452 TestRenderViewHost
* orig_rvh
= test_rvh();
453 RenderFrameHostImpl
* orig_rfh
=
454 contents()->GetFrameTree()->root()->current_frame_host();
455 int orig_rvh_delete_count
= 0;
456 orig_rvh
->set_delete_counter(&orig_rvh_delete_count
);
457 SiteInstance
* instance1
= contents()->GetSiteInstance();
459 // Navigate to URL. First URL should use first RenderViewHost.
460 const GURL
url("http://www.google.com");
461 controller().LoadURL(
462 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
463 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
465 // Keep the number of active views in orig_rvh's SiteInstance
466 // non-zero so that orig_rvh doesn't get deleted when it gets
468 static_cast<SiteInstanceImpl
*>(orig_rvh
->GetSiteInstance())->
469 increment_active_view_count();
471 EXPECT_FALSE(contents()->cross_navigation_pending());
472 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
473 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
474 EXPECT_EQ(url
, contents()->GetVisibleURL());
476 // Navigate to new site
477 const GURL
url2("http://www.yahoo.com");
478 controller().LoadURL(
479 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
480 EXPECT_TRUE(contents()->cross_navigation_pending());
481 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
482 EXPECT_EQ(url2
, contents()->GetVisibleURL());
483 TestRenderViewHost
* pending_rvh
=
484 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
485 int pending_rvh_delete_count
= 0;
486 pending_rvh
->set_delete_counter(&pending_rvh_delete_count
);
487 RenderFrameHostImpl
* pending_rfh
= contents()->GetFrameTree()->root()->
488 render_manager()->pending_frame_host();
490 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
491 EXPECT_TRUE(pending_rvh
->are_navigations_suspended());
492 orig_rvh
->SendBeforeUnloadACK(true);
493 EXPECT_FALSE(pending_rvh
->are_navigations_suspended());
495 // DidNavigate from the pending page
496 contents()->TestDidNavigate(
497 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
498 SiteInstance
* instance2
= contents()->GetSiteInstance();
500 // Keep the number of active views in pending_rvh's SiteInstance
501 // non-zero so that orig_rvh doesn't get deleted when it gets
503 static_cast<SiteInstanceImpl
*>(pending_rvh
->GetSiteInstance())->
504 increment_active_view_count();
506 EXPECT_FALSE(contents()->cross_navigation_pending());
507 EXPECT_EQ(pending_rvh
, contents()->GetRenderViewHost());
508 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
509 EXPECT_EQ(url2
, contents()->GetVisibleURL());
510 EXPECT_NE(instance1
, instance2
);
511 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
512 // We keep the original RFH around, swapped out.
513 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
515 EXPECT_EQ(orig_rvh_delete_count
, 0);
517 // Going back should switch SiteInstances again. The first SiteInstance is
518 // stored in the NavigationEntry, so it should be the same as at the start.
519 // We should use the same RVH as before, swapping it back in.
520 controller().GoBack();
521 TestRenderViewHost
* goback_rvh
=
522 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
523 EXPECT_EQ(orig_rvh
, goback_rvh
);
524 EXPECT_TRUE(contents()->cross_navigation_pending());
526 // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
527 EXPECT_TRUE(goback_rvh
->are_navigations_suspended());
528 pending_rvh
->SendBeforeUnloadACK(true);
529 EXPECT_FALSE(goback_rvh
->are_navigations_suspended());
531 // DidNavigate from the back action
532 contents()->TestDidNavigate(
533 goback_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
534 EXPECT_FALSE(contents()->cross_navigation_pending());
535 EXPECT_EQ(goback_rvh
, contents()->GetRenderViewHost());
536 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
537 // The pending RFH should now be swapped out, not deleted.
538 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
539 IsOnSwappedOutList(pending_rfh
));
540 EXPECT_EQ(pending_rvh_delete_count
, 0);
541 pending_rvh
->OnSwappedOut(false);
543 // Close contents and ensure RVHs are deleted.
545 EXPECT_EQ(orig_rvh_delete_count
, 1);
546 EXPECT_EQ(pending_rvh_delete_count
, 1);
549 // Test that navigating across a site boundary after a crash creates a new
550 // RVH without requiring a cross-site transition (i.e., PENDING state).
551 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
552 contents()->transition_cross_site
= true;
553 TestRenderViewHost
* orig_rvh
= test_rvh();
554 int orig_rvh_delete_count
= 0;
555 orig_rvh
->set_delete_counter(&orig_rvh_delete_count
);
556 SiteInstance
* instance1
= contents()->GetSiteInstance();
558 // Navigate to URL. First URL should use first RenderViewHost.
559 const GURL
url("http://www.google.com");
560 controller().LoadURL(
561 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
562 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
564 EXPECT_FALSE(contents()->cross_navigation_pending());
565 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
567 // Crash the renderer.
568 orig_rvh
->set_render_view_created(false);
570 // Navigate to new site. We should not go into PENDING.
571 const GURL
url2("http://www.yahoo.com");
572 controller().LoadURL(
573 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
574 RenderViewHost
* new_rvh
= rvh();
575 EXPECT_FALSE(contents()->cross_navigation_pending());
576 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
577 EXPECT_NE(orig_rvh
, new_rvh
);
578 EXPECT_EQ(orig_rvh_delete_count
, 1);
580 // DidNavigate from the new page
581 contents()->TestDidNavigate(new_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
582 SiteInstance
* instance2
= contents()->GetSiteInstance();
584 EXPECT_FALSE(contents()->cross_navigation_pending());
585 EXPECT_EQ(new_rvh
, rvh());
586 EXPECT_NE(instance1
, instance2
);
587 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
589 // Close contents and ensure RVHs are deleted.
591 EXPECT_EQ(orig_rvh_delete_count
, 1);
594 // Test that opening a new contents in the same SiteInstance and then navigating
595 // both contentses to a new site will place both contentses in a single
597 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
598 contents()->transition_cross_site
= true;
599 TestRenderViewHost
* orig_rvh
= test_rvh();
600 SiteInstance
* instance1
= contents()->GetSiteInstance();
602 // Navigate to URL. First URL should use first RenderViewHost.
603 const GURL
url("http://www.google.com");
604 controller().LoadURL(
605 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
606 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
608 // Open a new contents with the same SiteInstance, navigated to the same site.
609 scoped_ptr
<TestWebContents
> contents2(
610 TestWebContents::Create(browser_context(), instance1
));
611 contents2
->transition_cross_site
= true;
612 contents2
->GetController().LoadURL(url
, Referrer(),
613 PAGE_TRANSITION_TYPED
,
615 // Need this page id to be 2 since the site instance is the same (which is the
616 // scope of page IDs) and we want to consider this a new page.
617 contents2
->TestDidNavigate(
618 contents2
->GetRenderViewHost(), 2, url
, PAGE_TRANSITION_TYPED
);
620 // Navigate first contents to a new site.
621 const GURL
url2a("http://www.yahoo.com");
622 controller().LoadURL(
623 url2a
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
624 orig_rvh
->SendBeforeUnloadACK(true);
625 TestRenderViewHost
* pending_rvh_a
=
626 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
627 contents()->TestDidNavigate(
628 pending_rvh_a
, 1, url2a
, PAGE_TRANSITION_TYPED
);
629 SiteInstance
* instance2a
= contents()->GetSiteInstance();
630 EXPECT_NE(instance1
, instance2a
);
632 // Navigate second contents to the same site as the first tab.
633 const GURL
url2b("http://mail.yahoo.com");
634 contents2
->GetController().LoadURL(url2b
, Referrer(),
635 PAGE_TRANSITION_TYPED
,
637 TestRenderViewHost
* rvh2
=
638 static_cast<TestRenderViewHost
*>(contents2
->GetRenderViewHost());
639 rvh2
->SendBeforeUnloadACK(true);
640 TestRenderViewHost
* pending_rvh_b
=
641 static_cast<TestRenderViewHost
*>(contents2
->GetPendingRenderViewHost());
642 EXPECT_TRUE(pending_rvh_b
!= NULL
);
643 EXPECT_TRUE(contents2
->cross_navigation_pending());
645 // NOTE(creis): We used to be in danger of showing a crash page here if the
646 // second contents hadn't navigated somewhere first (bug 1145430). That case
647 // is now covered by the CrossSiteBoundariesAfterCrash test.
648 contents2
->TestDidNavigate(
649 pending_rvh_b
, 2, url2b
, PAGE_TRANSITION_TYPED
);
650 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
651 EXPECT_NE(instance1
, instance2b
);
653 // Both contentses should now be in the same SiteInstance.
654 EXPECT_EQ(instance2a
, instance2b
);
657 TEST_F(WebContentsImplTest
, NavigateDoesNotUseUpSiteInstance
) {
658 WebContentsImplTestBrowserClient browser_client
;
659 SetBrowserClientForTesting(&browser_client
);
661 contents()->transition_cross_site
= true;
662 TestRenderViewHost
* orig_rvh
= test_rvh();
663 RenderFrameHostImpl
* orig_rfh
=
664 contents()->GetFrameTree()->root()->current_frame_host();
665 int orig_rvh_delete_count
= 0;
666 orig_rvh
->set_delete_counter(&orig_rvh_delete_count
);
667 SiteInstanceImpl
* orig_instance
=
668 static_cast<SiteInstanceImpl
*>(contents()->GetSiteInstance());
670 browser_client
.set_assign_site_for_url(false);
671 // Navigate to an URL that will not assign a new SiteInstance.
672 const GURL
native_url("non-site-url://stuffandthings");
673 controller().LoadURL(
674 native_url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
675 contents()->TestDidNavigate(orig_rvh
, 1, native_url
, PAGE_TRANSITION_TYPED
);
677 EXPECT_FALSE(contents()->cross_navigation_pending());
678 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
679 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
680 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
681 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
682 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
683 EXPECT_FALSE(orig_instance
->HasSite());
685 browser_client
.set_assign_site_for_url(true);
686 // Navigate to new site (should keep same site instance).
687 const GURL
url("http://www.google.com");
688 controller().LoadURL(
689 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
690 EXPECT_FALSE(contents()->cross_navigation_pending());
691 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
692 EXPECT_EQ(url
, contents()->GetVisibleURL());
693 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
694 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
696 // Keep the number of active views in orig_rvh's SiteInstance
697 // non-zero so that orig_rvh doesn't get deleted when it gets
699 static_cast<SiteInstanceImpl
*>(orig_rvh
->GetSiteInstance())->
700 increment_active_view_count();
702 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
704 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
705 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
707 // Navigate to another new site (should create a new site instance).
708 const GURL
url2("http://www.yahoo.com");
709 controller().LoadURL(
710 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
711 EXPECT_TRUE(contents()->cross_navigation_pending());
712 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
713 EXPECT_EQ(url2
, contents()->GetVisibleURL());
714 TestRenderViewHost
* pending_rvh
=
715 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
716 int pending_rvh_delete_count
= 0;
717 pending_rvh
->set_delete_counter(&pending_rvh_delete_count
);
719 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
720 EXPECT_TRUE(pending_rvh
->are_navigations_suspended());
721 orig_rvh
->SendBeforeUnloadACK(true);
722 EXPECT_FALSE(pending_rvh
->are_navigations_suspended());
724 // DidNavigate from the pending page.
725 contents()->TestDidNavigate(
726 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
727 SiteInstance
* new_instance
= contents()->GetSiteInstance();
729 EXPECT_FALSE(contents()->cross_navigation_pending());
730 EXPECT_EQ(pending_rvh
, contents()->GetRenderViewHost());
731 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
732 EXPECT_EQ(url2
, contents()->GetVisibleURL());
733 EXPECT_NE(new_instance
, orig_instance
);
734 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
735 // We keep the original RFH around, swapped out.
736 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
738 EXPECT_EQ(orig_rvh_delete_count
, 0);
739 orig_rvh
->OnSwappedOut(false);
741 // Close contents and ensure RVHs are deleted.
743 EXPECT_EQ(orig_rvh_delete_count
, 1);
744 EXPECT_EQ(pending_rvh_delete_count
, 1);
747 // Test that we can find an opener RVH even if it's pending.
748 // http://crbug.com/176252.
749 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
750 contents()->transition_cross_site
= true;
751 TestRenderViewHost
* orig_rvh
= test_rvh();
753 // Navigate to a URL.
754 const GURL
url("http://www.google.com");
755 controller().LoadURL(
756 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
757 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
759 // Start to navigate first tab to a new site, so that it has a pending RVH.
760 const GURL
url2("http://www.yahoo.com");
761 controller().LoadURL(
762 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
763 orig_rvh
->SendBeforeUnloadACK(true);
764 TestRenderViewHost
* pending_rvh
=
765 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
767 // While it is still pending, simulate opening a new tab with the first tab
768 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
769 // on the opener to ensure that an RVH exists.
770 int opener_routing_id
= contents()->CreateOpenerRenderViews(
771 pending_rvh
->GetSiteInstance());
773 // We should find the pending RVH and not create a new one.
774 EXPECT_EQ(pending_rvh
->GetRoutingID(), opener_routing_id
);
777 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
778 // to determine whether a navigation is cross-site.
779 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
780 contents()->transition_cross_site
= true;
781 RenderViewHost
* orig_rvh
= rvh();
782 SiteInstance
* instance1
= contents()->GetSiteInstance();
785 const GURL
url("http://www.google.com");
786 controller().LoadURL(
787 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
788 contents()->TestDidNavigate(
789 orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
791 // Open a related contents to a second site.
792 scoped_ptr
<TestWebContents
> contents2(
793 TestWebContents::Create(browser_context(), instance1
));
794 contents2
->transition_cross_site
= true;
795 const GURL
url2("http://www.yahoo.com");
796 contents2
->GetController().LoadURL(url2
, Referrer(),
797 PAGE_TRANSITION_TYPED
,
799 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
801 TestRenderViewHost
* rvh2
= static_cast<TestRenderViewHost
*>(
802 contents2
->GetRenderViewHost());
803 EXPECT_FALSE(contents2
->cross_navigation_pending());
804 contents2
->TestDidNavigate(rvh2
, 2, url2
, PAGE_TRANSITION_TYPED
);
805 SiteInstance
* instance2
= contents2
->GetSiteInstance();
806 EXPECT_NE(instance1
, instance2
);
807 EXPECT_FALSE(contents2
->cross_navigation_pending());
809 // Simulate a link click in first contents to second site. Doesn't switch
810 // SiteInstances, because we don't intercept WebKit navigations.
811 contents()->TestDidNavigate(
812 orig_rvh
, 2, url2
, PAGE_TRANSITION_TYPED
);
813 SiteInstance
* instance3
= contents()->GetSiteInstance();
814 EXPECT_EQ(instance1
, instance3
);
815 EXPECT_FALSE(contents()->cross_navigation_pending());
817 // Navigate to the new site. Doesn't switch SiteInstancees, because we
818 // compare against the current URL, not the SiteInstance's site.
819 const GURL
url3("http://mail.yahoo.com");
820 controller().LoadURL(
821 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
822 EXPECT_FALSE(contents()->cross_navigation_pending());
823 contents()->TestDidNavigate(
824 orig_rvh
, 3, url3
, PAGE_TRANSITION_TYPED
);
825 SiteInstance
* instance4
= contents()->GetSiteInstance();
826 EXPECT_EQ(instance1
, instance4
);
829 // Test that the onbeforeunload and onunload handlers run when navigating
830 // across site boundaries.
831 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
832 contents()->transition_cross_site
= true;
833 TestRenderViewHost
* orig_rvh
= test_rvh();
834 SiteInstance
* instance1
= contents()->GetSiteInstance();
836 // Navigate to URL. First URL should use first RenderViewHost.
837 const GURL
url("http://www.google.com");
838 controller().LoadURL(
839 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
840 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
841 EXPECT_FALSE(contents()->cross_navigation_pending());
842 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
844 // Navigate to new site, but simulate an onbeforeunload denial.
845 const GURL
url2("http://www.yahoo.com");
846 controller().LoadURL(
847 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
848 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
849 base::TimeTicks now
= base::TimeTicks::Now();
850 orig_rvh
->GetMainFrame()->OnMessageReceived(
851 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
852 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
853 EXPECT_FALSE(contents()->cross_navigation_pending());
854 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
856 // Navigate again, but simulate an onbeforeunload approval.
857 controller().LoadURL(
858 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
859 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
860 now
= base::TimeTicks::Now();
861 orig_rvh
->GetMainFrame()->OnMessageReceived(
862 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
863 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
864 EXPECT_TRUE(contents()->cross_navigation_pending());
865 TestRenderViewHost
* pending_rvh
= static_cast<TestRenderViewHost
*>(
866 contents()->GetPendingRenderViewHost());
868 // We won't hear DidNavigate until the onunload handler has finished running.
870 // DidNavigate from the pending page.
871 contents()->TestDidNavigate(
872 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
873 SiteInstance
* instance2
= contents()->GetSiteInstance();
874 EXPECT_FALSE(contents()->cross_navigation_pending());
875 EXPECT_EQ(pending_rvh
, rvh());
876 EXPECT_NE(instance1
, instance2
);
877 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
880 // Test that during a slow cross-site navigation, the original renderer can
881 // navigate to a different URL and have it displayed, canceling the slow
883 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
884 contents()->transition_cross_site
= true;
885 TestRenderViewHost
* orig_rvh
= test_rvh();
886 SiteInstance
* instance1
= contents()->GetSiteInstance();
888 // Navigate to URL. First URL should use first RenderViewHost.
889 const GURL
url("http://www.google.com");
890 controller().LoadURL(
891 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
892 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
893 EXPECT_FALSE(contents()->cross_navigation_pending());
894 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
896 // Navigate to new site, simulating an onbeforeunload approval.
897 const GURL
url2("http://www.yahoo.com");
898 controller().LoadURL(
899 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
900 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
901 base::TimeTicks now
= base::TimeTicks::Now();
902 orig_rvh
->GetMainFrame()->OnMessageReceived(
903 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
904 EXPECT_TRUE(contents()->cross_navigation_pending());
906 // Suppose the original renderer navigates before the new one is ready.
907 orig_rvh
->SendNavigate(2, GURL("http://www.google.com/foo"));
909 // Verify that the pending navigation is cancelled.
910 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
911 SiteInstance
* instance2
= contents()->GetSiteInstance();
912 EXPECT_FALSE(contents()->cross_navigation_pending());
913 EXPECT_EQ(orig_rvh
, rvh());
914 EXPECT_EQ(instance1
, instance2
);
915 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
918 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
919 contents()->transition_cross_site
= true;
921 // Start with a web ui page, which gets a new RVH with WebUI bindings.
922 const GURL
url1("chrome://blah");
923 controller().LoadURL(
924 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
925 TestRenderViewHost
* ntp_rvh
= test_rvh();
926 contents()->TestDidNavigate(ntp_rvh
, 1, url1
, PAGE_TRANSITION_TYPED
);
927 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
928 SiteInstance
* instance1
= contents()->GetSiteInstance();
930 EXPECT_FALSE(contents()->cross_navigation_pending());
931 EXPECT_EQ(ntp_rvh
, contents()->GetRenderViewHost());
932 EXPECT_EQ(url1
, entry1
->GetURL());
934 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
935 EXPECT_TRUE(ntp_rvh
->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
937 // Navigate to new site.
938 const GURL
url2("http://www.google.com");
939 controller().LoadURL(
940 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
941 EXPECT_TRUE(contents()->cross_navigation_pending());
942 TestRenderViewHost
* google_rvh
=
943 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
945 // Simulate beforeunload approval.
946 EXPECT_TRUE(ntp_rvh
->is_waiting_for_beforeunload_ack());
947 base::TimeTicks now
= base::TimeTicks::Now();
948 ntp_rvh
->GetMainFrame()->OnMessageReceived(
949 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
951 // DidNavigate from the pending page.
952 contents()->TestDidNavigate(
953 google_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
954 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
955 SiteInstance
* instance2
= contents()->GetSiteInstance();
957 EXPECT_FALSE(contents()->cross_navigation_pending());
958 EXPECT_EQ(google_rvh
, contents()->GetRenderViewHost());
959 EXPECT_NE(instance1
, instance2
);
960 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
961 EXPECT_EQ(url2
, entry2
->GetURL());
963 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
964 EXPECT_FALSE(google_rvh
->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
966 // Navigate to third page on same site.
967 const GURL
url3("http://news.google.com");
968 controller().LoadURL(
969 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
970 EXPECT_FALSE(contents()->cross_navigation_pending());
971 contents()->TestDidNavigate(
972 google_rvh
, 2, url3
, PAGE_TRANSITION_TYPED
);
973 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
974 SiteInstance
* instance3
= contents()->GetSiteInstance();
976 EXPECT_FALSE(contents()->cross_navigation_pending());
977 EXPECT_EQ(google_rvh
, contents()->GetRenderViewHost());
978 EXPECT_EQ(instance2
, instance3
);
979 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
980 EXPECT_EQ(url3
, entry3
->GetURL());
982 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
984 // Go back within the site.
985 controller().GoBack();
986 EXPECT_FALSE(contents()->cross_navigation_pending());
987 EXPECT_EQ(entry2
, controller().GetPendingEntry());
989 // Before that commits, go back again.
990 controller().GoBack();
991 EXPECT_TRUE(contents()->cross_navigation_pending());
992 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
993 EXPECT_EQ(entry1
, controller().GetPendingEntry());
995 // Simulate beforeunload approval.
996 EXPECT_TRUE(google_rvh
->is_waiting_for_beforeunload_ack());
997 now
= base::TimeTicks::Now();
998 google_rvh
->GetMainFrame()->OnMessageReceived(
999 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1001 // DidNavigate from the first back. This aborts the second back's pending RVH.
1002 contents()->TestDidNavigate(google_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1004 // We should commit this page and forget about the second back.
1005 EXPECT_FALSE(contents()->cross_navigation_pending());
1006 EXPECT_FALSE(controller().GetPendingEntry());
1007 EXPECT_EQ(google_rvh
, contents()->GetRenderViewHost());
1008 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1010 // We should not have corrupted the NTP entry.
1011 EXPECT_EQ(instance3
,
1012 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1013 EXPECT_EQ(instance2
,
1014 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1015 EXPECT_EQ(instance1
,
1016 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1017 EXPECT_EQ(url1
, entry1
->GetURL());
1020 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1021 // original renderer will not cancel the slow navigation (bug 42029).
1022 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1023 contents()->transition_cross_site
= true;
1024 TestRenderViewHost
* orig_rvh
= test_rvh();
1026 // Navigate to URL. First URL should use first RenderViewHost.
1027 const GURL
url("http://www.google.com");
1028 controller().LoadURL(
1029 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1030 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1031 EXPECT_FALSE(contents()->cross_navigation_pending());
1032 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1034 // Start navigating to new site.
1035 const GURL
url2("http://www.yahoo.com");
1036 controller().LoadURL(
1037 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1039 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1040 // waiting for a before unload response.
1041 orig_rvh
->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
1042 PAGE_TRANSITION_AUTO_SUBFRAME
);
1043 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
1045 // Now simulate the onbeforeunload approval and verify the navigation is
1047 base::TimeTicks now
= base::TimeTicks::Now();
1048 orig_rvh
->GetMainFrame()->OnMessageReceived(
1049 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1050 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1051 EXPECT_TRUE(contents()->cross_navigation_pending());
1054 // Test that a cross-site navigation is not preempted if the previous
1055 // renderer sends a FrameNavigate message just before being told to stop.
1056 // We should only preempt the cross-site navigation if the previous renderer
1057 // has started a new navigation. See http://crbug.com/79176.
1058 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1059 contents()->transition_cross_site
= true;
1061 // Navigate to NTP URL.
1062 const GURL
url("chrome://blah");
1063 controller().LoadURL(
1064 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1065 TestRenderViewHost
* orig_rvh
= test_rvh();
1066 EXPECT_FALSE(contents()->cross_navigation_pending());
1068 // Navigate to new site, with the beforeunload request in flight.
1069 const GURL
url2("http://www.yahoo.com");
1070 controller().LoadURL(
1071 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1072 TestRenderViewHost
* pending_rvh
=
1073 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
1074 EXPECT_TRUE(contents()->cross_navigation_pending());
1075 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
1077 // Suppose the first navigation tries to commit now, with a
1078 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1079 // but it should act as if the beforeunload ack arrived.
1080 orig_rvh
->SendNavigate(1, GURL("chrome://blah"));
1081 EXPECT_TRUE(contents()->cross_navigation_pending());
1082 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1083 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1085 // The pending navigation should be able to commit successfully.
1086 contents()->TestDidNavigate(pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1087 EXPECT_FALSE(contents()->cross_navigation_pending());
1088 EXPECT_EQ(pending_rvh
, contents()->GetRenderViewHost());
1091 // Test that the original renderer cannot preempt a cross-site navigation once
1092 // the unload request has been made. At this point, the cross-site navigation
1093 // is almost ready to be displayed, and the original renderer is only given a
1094 // short chance to run an unload handler. Prevents regression of bug 23942.
1095 TEST_F(WebContentsImplTest
, CrossSiteCantPreemptAfterUnload
) {
1096 contents()->transition_cross_site
= true;
1097 TestRenderViewHost
* orig_rvh
= test_rvh();
1098 SiteInstance
* instance1
= contents()->GetSiteInstance();
1100 // Navigate to URL. First URL should use first RenderViewHost.
1101 const GURL
url("http://www.google.com");
1102 controller().LoadURL(
1103 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1104 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1105 EXPECT_FALSE(contents()->cross_navigation_pending());
1106 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1108 // Navigate to new site, simulating an onbeforeunload approval.
1109 const GURL
url2("http://www.yahoo.com");
1110 controller().LoadURL(
1111 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1112 base::TimeTicks now
= base::TimeTicks::Now();
1113 orig_rvh
->GetMainFrame()->OnMessageReceived(
1114 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1115 EXPECT_TRUE(contents()->cross_navigation_pending());
1116 TestRenderViewHost
* pending_rvh
= static_cast<TestRenderViewHost
*>(
1117 contents()->GetPendingRenderViewHost());
1119 // Simulate the pending renderer's response, which leads to an unload request
1120 // being sent to orig_rvh.
1121 std::vector
<GURL
> url_chain
;
1122 url_chain
.push_back(GURL());
1123 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1124 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1125 GlobalRequestID(0, 0), scoped_ptr
<CrossSiteTransferringRequest
>(),
1126 url_chain
, Referrer(), PAGE_TRANSITION_TYPED
, false);
1128 // Suppose the original renderer navigates now, while the unload request is in
1129 // flight. We should ignore it, wait for the unload ack, and let the pending
1130 // request continue. Otherwise, the contents may close spontaneously or stop
1131 // responding to navigation requests. (See bug 23942.)
1132 FrameHostMsg_DidCommitProvisionalLoad_Params params1a
;
1133 InitNavigateParams(¶ms1a
, 2, GURL("http://www.google.com/foo"),
1134 PAGE_TRANSITION_TYPED
);
1135 orig_rvh
->SendNavigate(2, GURL("http://www.google.com/foo"));
1137 // Verify that the pending navigation is still in progress.
1138 EXPECT_TRUE(contents()->cross_navigation_pending());
1139 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL
);
1141 // DidNavigate from the pending page should commit it.
1142 contents()->TestDidNavigate(
1143 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1144 SiteInstance
* instance2
= contents()->GetSiteInstance();
1145 EXPECT_FALSE(contents()->cross_navigation_pending());
1146 EXPECT_EQ(pending_rvh
, rvh());
1147 EXPECT_NE(instance1
, instance2
);
1148 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
1151 // Test that a cross-site navigation that doesn't commit after the unload
1152 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1153 TEST_F(WebContentsImplTest
, CrossSiteNavigationCanceled
) {
1154 contents()->transition_cross_site
= true;
1155 TestRenderViewHost
* orig_rvh
= test_rvh();
1156 SiteInstance
* instance1
= contents()->GetSiteInstance();
1158 // Navigate to URL. First URL should use first RenderViewHost.
1159 const GURL
url("http://www.google.com");
1160 controller().LoadURL(
1161 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1162 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1163 EXPECT_FALSE(contents()->cross_navigation_pending());
1164 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1166 // Navigate to new site, simulating an onbeforeunload approval.
1167 const GURL
url2("http://www.yahoo.com");
1168 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1169 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
1170 base::TimeTicks now
= base::TimeTicks::Now();
1171 orig_rvh
->GetMainFrame()->OnMessageReceived(
1172 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1173 EXPECT_TRUE(contents()->cross_navigation_pending());
1175 // Simulate swap out message when the response arrives.
1176 orig_rvh
->OnSwappedOut(false);
1178 // Suppose the navigation doesn't get a chance to commit, and the user
1179 // navigates in the current RVH's SiteInstance.
1180 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1182 // Verify that the pending navigation is cancelled and the renderer is no
1183 // longer swapped out.
1184 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1185 SiteInstance
* instance2
= contents()->GetSiteInstance();
1186 EXPECT_FALSE(contents()->cross_navigation_pending());
1187 EXPECT_EQ(orig_rvh
, rvh());
1188 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT
, orig_rvh
->rvh_state());
1189 EXPECT_EQ(instance1
, instance2
);
1190 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
1193 // Test that NavigationEntries have the correct page state after going
1194 // forward and back. Prevents regression for bug 1116137.
1195 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1196 TestRenderViewHost
* orig_rvh
= test_rvh();
1198 // Navigate to URL. There should be no committed entry yet.
1199 const GURL
url("http://www.google.com");
1200 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1201 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1202 EXPECT_TRUE(entry
== NULL
);
1204 // Committed entry should have page state after DidNavigate.
1205 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1206 entry
= controller().GetLastCommittedEntry();
1207 EXPECT_TRUE(entry
->GetPageState().IsValid());
1209 // Navigate to same site.
1210 const GURL
url2("http://images.google.com");
1211 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1212 entry
= controller().GetLastCommittedEntry();
1213 EXPECT_TRUE(entry
->GetPageState().IsValid());
1215 // Committed entry should have page state after DidNavigate.
1216 contents()->TestDidNavigate(orig_rvh
, 2, url2
, PAGE_TRANSITION_TYPED
);
1217 entry
= controller().GetLastCommittedEntry();
1218 EXPECT_TRUE(entry
->GetPageState().IsValid());
1220 // Now go back. Committed entry should still have page state.
1221 controller().GoBack();
1222 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1223 entry
= controller().GetLastCommittedEntry();
1224 EXPECT_TRUE(entry
->GetPageState().IsValid());
1227 // Test that NavigationEntries have the correct page state and SiteInstance
1228 // state after opening a new window to about:blank. Prevents regression for
1229 // bugs b/1116137 and http://crbug.com/111975.
1230 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1231 TestRenderViewHost
* orig_rvh
= test_rvh();
1233 // When opening a new window, it is navigated to about:blank internally.
1234 // Currently, this results in two DidNavigate events.
1235 const GURL
url(kAboutBlankURL
);
1236 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1237 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1239 // Should have a page state here.
1240 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1241 EXPECT_TRUE(entry
->GetPageState().IsValid());
1243 // The SiteInstance should be available for other navigations to use.
1244 NavigationEntryImpl
* entry_impl
=
1245 NavigationEntryImpl::FromNavigationEntry(entry
);
1246 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1247 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1249 // Navigating to a normal page should not cause a process swap.
1250 const GURL
new_url("http://www.google.com");
1251 controller().LoadURL(new_url
, Referrer(),
1252 PAGE_TRANSITION_TYPED
, std::string());
1253 EXPECT_FALSE(contents()->cross_navigation_pending());
1254 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1255 contents()->TestDidNavigate(orig_rvh
, 1, new_url
, PAGE_TRANSITION_TYPED
);
1256 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1257 controller().GetLastCommittedEntry());
1258 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1259 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1262 // Tests that fullscreen is exited throughout the object hierarchy when
1263 // navigating to a new page.
1264 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1265 FakeFullscreenDelegate fake_delegate
;
1266 contents()->SetDelegate(&fake_delegate
);
1267 TestRenderViewHost
* orig_rvh
= test_rvh();
1269 // Navigate to a site.
1270 const GURL
url("http://www.google.com");
1271 controller().LoadURL(
1272 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1273 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1274 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1276 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1277 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1278 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1279 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1280 orig_rvh
->OnMessageReceived(
1281 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1282 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1283 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1284 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1286 // Navigate to a new site.
1287 const GURL
url2("http://www.yahoo.com");
1288 controller().LoadURL(
1289 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1290 RenderViewHost
* const pending_rvh
= contents()->GetPendingRenderViewHost();
1291 contents()->TestDidNavigate(
1292 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1294 // Confirm fullscreen has exited.
1295 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1296 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1297 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1299 contents()->SetDelegate(NULL
);
1302 // Tests that fullscreen is exited throughout the object hierarchy when
1303 // instructing NavigationController to GoBack() or GoForward().
1304 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1305 FakeFullscreenDelegate fake_delegate
;
1306 contents()->SetDelegate(&fake_delegate
);
1307 TestRenderViewHost
* const orig_rvh
= test_rvh();
1309 // Navigate to a site.
1310 const GURL
url("http://www.google.com");
1311 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1312 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1313 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1315 // Now, navigate to another page on the same site.
1316 const GURL
url2("http://www.google.com/search?q=kittens");
1317 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1318 EXPECT_FALSE(contents()->cross_navigation_pending());
1319 contents()->TestDidNavigate(orig_rvh
, 2, url2
, PAGE_TRANSITION_TYPED
);
1320 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1322 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1323 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1324 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1325 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1327 for (int i
= 0; i
< 2; ++i
) {
1328 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1329 orig_rvh
->OnMessageReceived(
1330 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1331 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1332 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1333 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1335 // Navigate backward (or forward).
1337 controller().GoBack();
1339 controller().GoForward();
1340 EXPECT_FALSE(contents()->cross_navigation_pending());
1341 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1342 contents()->TestDidNavigate(
1343 orig_rvh
, i
+ 1, url
, PAGE_TRANSITION_FORWARD_BACK
);
1345 // Confirm fullscreen has exited.
1346 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1347 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1348 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1351 contents()->SetDelegate(NULL
);
1354 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1356 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1357 FakeFullscreenDelegate fake_delegate
;
1358 contents()->SetDelegate(&fake_delegate
);
1360 // Navigate to a site.
1361 const GURL
url("http://www.google.com");
1362 controller().LoadURL(
1363 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1364 contents()->TestDidNavigate(test_rvh(), 1, url
, PAGE_TRANSITION_TYPED
);
1365 EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
1367 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1368 EXPECT_FALSE(test_rvh()->IsFullscreen());
1369 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1370 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1371 test_rvh()->OnMessageReceived(
1372 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1373 EXPECT_TRUE(test_rvh()->IsFullscreen());
1374 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1375 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1377 // Crash the renderer.
1378 test_rvh()->OnMessageReceived(
1379 ViewHostMsg_RenderProcessGone(
1380 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1382 // Confirm fullscreen has exited.
1383 EXPECT_FALSE(test_rvh()->IsFullscreen());
1384 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1385 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1387 contents()->SetDelegate(NULL
);
1390 ////////////////////////////////////////////////////////////////////////////////
1391 // Interstitial Tests
1392 ////////////////////////////////////////////////////////////////////////////////
1394 // Test navigating to a page (with the navigation initiated from the browser,
1395 // as when a URL is typed in the location bar) that shows an interstitial and
1396 // creates a new navigation entry, then hiding it without proceeding.
1397 TEST_F(WebContentsImplTest
,
1398 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1399 // Navigate to a page.
1400 GURL
url1("http://www.google.com");
1401 test_rvh()->SendNavigate(1, url1
);
1402 EXPECT_EQ(1, controller().GetEntryCount());
1404 // Initiate a browser navigation that will trigger the interstitial
1405 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1406 PAGE_TRANSITION_TYPED
, std::string());
1408 // Show an interstitial.
1409 TestInterstitialPage::InterstitialState state
=
1410 TestInterstitialPage::INVALID
;
1411 bool deleted
= false;
1412 GURL
url2("http://interstitial");
1413 TestInterstitialPage
* interstitial
=
1414 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1415 TestInterstitialPageStateGuard
state_guard(interstitial
);
1416 interstitial
->Show();
1417 // The interstitial should not show until its navigation has committed.
1418 EXPECT_FALSE(interstitial
->is_showing());
1419 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1420 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1421 // Let's commit the interstitial navigation.
1422 interstitial
->TestDidNavigate(1, url2
);
1423 EXPECT_TRUE(interstitial
->is_showing());
1424 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1425 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1426 NavigationEntry
* entry
= controller().GetVisibleEntry();
1427 ASSERT_TRUE(entry
!= NULL
);
1428 EXPECT_TRUE(entry
->GetURL() == url2
);
1430 // Now don't proceed.
1431 interstitial
->DontProceed();
1432 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1433 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1434 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1435 entry
= controller().GetVisibleEntry();
1436 ASSERT_TRUE(entry
!= NULL
);
1437 EXPECT_TRUE(entry
->GetURL() == url1
);
1438 EXPECT_EQ(1, controller().GetEntryCount());
1440 RunAllPendingInMessageLoop();
1441 EXPECT_TRUE(deleted
);
1444 // Test navigating to a page (with the navigation initiated from the renderer,
1445 // as when clicking on a link in the page) that shows an interstitial and
1446 // creates a new navigation entry, then hiding it without proceeding.
1447 TEST_F(WebContentsImplTest
,
1448 ShowInterstitiaFromRendererlWithNewNavigationDontProceed
) {
1449 // Navigate to a page.
1450 GURL
url1("http://www.google.com");
1451 test_rvh()->SendNavigate(1, url1
);
1452 EXPECT_EQ(1, controller().GetEntryCount());
1454 // Show an interstitial (no pending entry, the interstitial would have been
1455 // triggered by clicking on a link).
1456 TestInterstitialPage::InterstitialState state
=
1457 TestInterstitialPage::INVALID
;
1458 bool deleted
= false;
1459 GURL
url2("http://interstitial");
1460 TestInterstitialPage
* interstitial
=
1461 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1462 TestInterstitialPageStateGuard
state_guard(interstitial
);
1463 interstitial
->Show();
1464 // The interstitial should not show until its navigation has committed.
1465 EXPECT_FALSE(interstitial
->is_showing());
1466 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1467 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1468 // Let's commit the interstitial navigation.
1469 interstitial
->TestDidNavigate(1, url2
);
1470 EXPECT_TRUE(interstitial
->is_showing());
1471 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1472 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1473 NavigationEntry
* entry
= controller().GetVisibleEntry();
1474 ASSERT_TRUE(entry
!= NULL
);
1475 EXPECT_TRUE(entry
->GetURL() == url2
);
1477 // Now don't proceed.
1478 interstitial
->DontProceed();
1479 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1480 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1481 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1482 entry
= controller().GetVisibleEntry();
1483 ASSERT_TRUE(entry
!= NULL
);
1484 EXPECT_TRUE(entry
->GetURL() == url1
);
1485 EXPECT_EQ(1, controller().GetEntryCount());
1487 RunAllPendingInMessageLoop();
1488 EXPECT_TRUE(deleted
);
1491 // Test navigating to a page that shows an interstitial without creating a new
1492 // navigation entry (this happens when the interstitial is triggered by a
1493 // sub-resource in the page), then hiding it without proceeding.
1494 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1495 // Navigate to a page.
1496 GURL
url1("http://www.google.com");
1497 test_rvh()->SendNavigate(1, url1
);
1498 EXPECT_EQ(1, controller().GetEntryCount());
1500 // Show an interstitial.
1501 TestInterstitialPage::InterstitialState state
=
1502 TestInterstitialPage::INVALID
;
1503 bool deleted
= false;
1504 GURL
url2("http://interstitial");
1505 TestInterstitialPage
* interstitial
=
1506 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1507 TestInterstitialPageStateGuard
state_guard(interstitial
);
1508 interstitial
->Show();
1509 // The interstitial should not show until its navigation has committed.
1510 EXPECT_FALSE(interstitial
->is_showing());
1511 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1512 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1513 // Let's commit the interstitial navigation.
1514 interstitial
->TestDidNavigate(1, url2
);
1515 EXPECT_TRUE(interstitial
->is_showing());
1516 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1517 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1518 NavigationEntry
* entry
= controller().GetVisibleEntry();
1519 ASSERT_TRUE(entry
!= NULL
);
1520 // The URL specified to the interstitial should have been ignored.
1521 EXPECT_TRUE(entry
->GetURL() == url1
);
1523 // Now don't proceed.
1524 interstitial
->DontProceed();
1525 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1526 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1527 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1528 entry
= controller().GetVisibleEntry();
1529 ASSERT_TRUE(entry
!= NULL
);
1530 EXPECT_TRUE(entry
->GetURL() == url1
);
1531 EXPECT_EQ(1, controller().GetEntryCount());
1533 RunAllPendingInMessageLoop();
1534 EXPECT_TRUE(deleted
);
1537 // Test navigating to a page (with the navigation initiated from the browser,
1538 // as when a URL is typed in the location bar) that shows an interstitial and
1539 // creates a new navigation entry, then proceeding.
1540 TEST_F(WebContentsImplTest
,
1541 ShowInterstitialFromBrowserNewNavigationProceed
) {
1542 // Navigate to a page.
1543 GURL
url1("http://www.google.com");
1544 test_rvh()->SendNavigate(1, url1
);
1545 EXPECT_EQ(1, controller().GetEntryCount());
1547 // Initiate a browser navigation that will trigger the interstitial
1548 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1549 PAGE_TRANSITION_TYPED
, std::string());
1551 // Show an interstitial.
1552 TestInterstitialPage::InterstitialState state
=
1553 TestInterstitialPage::INVALID
;
1554 bool deleted
= false;
1555 GURL
url2("http://interstitial");
1556 TestInterstitialPage
* interstitial
=
1557 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1558 TestInterstitialPageStateGuard
state_guard(interstitial
);
1559 interstitial
->Show();
1560 // The interstitial should not show until its navigation has committed.
1561 EXPECT_FALSE(interstitial
->is_showing());
1562 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1563 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1564 // Let's commit the interstitial navigation.
1565 interstitial
->TestDidNavigate(1, url2
);
1566 EXPECT_TRUE(interstitial
->is_showing());
1567 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1568 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1569 NavigationEntry
* entry
= controller().GetVisibleEntry();
1570 ASSERT_TRUE(entry
!= NULL
);
1571 EXPECT_TRUE(entry
->GetURL() == url2
);
1574 interstitial
->Proceed();
1575 // The interstitial should show until the new navigation commits.
1576 RunAllPendingInMessageLoop();
1577 ASSERT_FALSE(deleted
);
1578 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1579 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1580 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1582 // Simulate the navigation to the page, that's when the interstitial gets
1584 GURL
url3("http://www.thepage.com");
1585 test_rvh()->SendNavigate(2, url3
);
1587 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1588 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1589 entry
= controller().GetVisibleEntry();
1590 ASSERT_TRUE(entry
!= NULL
);
1591 EXPECT_TRUE(entry
->GetURL() == url3
);
1593 EXPECT_EQ(2, controller().GetEntryCount());
1595 RunAllPendingInMessageLoop();
1596 EXPECT_TRUE(deleted
);
1599 // Test navigating to a page (with the navigation initiated from the renderer,
1600 // as when clicking on a link in the page) that shows an interstitial and
1601 // creates a new navigation entry, then proceeding.
1602 TEST_F(WebContentsImplTest
,
1603 ShowInterstitialFromRendererNewNavigationProceed
) {
1604 // Navigate to a page.
1605 GURL
url1("http://www.google.com");
1606 test_rvh()->SendNavigate(1, url1
);
1607 EXPECT_EQ(1, controller().GetEntryCount());
1609 // Show an interstitial.
1610 TestInterstitialPage::InterstitialState state
=
1611 TestInterstitialPage::INVALID
;
1612 bool deleted
= false;
1613 GURL
url2("http://interstitial");
1614 TestInterstitialPage
* interstitial
=
1615 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1616 TestInterstitialPageStateGuard
state_guard(interstitial
);
1617 interstitial
->Show();
1618 // The interstitial should not show until its navigation has committed.
1619 EXPECT_FALSE(interstitial
->is_showing());
1620 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1621 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1622 // Let's commit the interstitial navigation.
1623 interstitial
->TestDidNavigate(1, url2
);
1624 EXPECT_TRUE(interstitial
->is_showing());
1625 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1626 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1627 NavigationEntry
* entry
= controller().GetVisibleEntry();
1628 ASSERT_TRUE(entry
!= NULL
);
1629 EXPECT_TRUE(entry
->GetURL() == url2
);
1632 interstitial
->Proceed();
1633 // The interstitial should show until the new navigation commits.
1634 RunAllPendingInMessageLoop();
1635 ASSERT_FALSE(deleted
);
1636 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1637 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1638 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1640 // Simulate the navigation to the page, that's when the interstitial gets
1642 GURL
url3("http://www.thepage.com");
1643 test_rvh()->SendNavigate(2, url3
);
1645 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1646 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1647 entry
= controller().GetVisibleEntry();
1648 ASSERT_TRUE(entry
!= NULL
);
1649 EXPECT_TRUE(entry
->GetURL() == url3
);
1651 EXPECT_EQ(2, controller().GetEntryCount());
1653 RunAllPendingInMessageLoop();
1654 EXPECT_TRUE(deleted
);
1657 // Test navigating to a page that shows an interstitial without creating a new
1658 // navigation entry (this happens when the interstitial is triggered by a
1659 // sub-resource in the page), then proceeding.
1660 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1661 // Navigate to a page so we have a navigation entry in the controller.
1662 GURL
url1("http://www.google.com");
1663 test_rvh()->SendNavigate(1, url1
);
1664 EXPECT_EQ(1, controller().GetEntryCount());
1666 // Show an interstitial.
1667 TestInterstitialPage::InterstitialState state
=
1668 TestInterstitialPage::INVALID
;
1669 bool deleted
= false;
1670 GURL
url2("http://interstitial");
1671 TestInterstitialPage
* interstitial
=
1672 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1673 TestInterstitialPageStateGuard
state_guard(interstitial
);
1674 interstitial
->Show();
1675 // The interstitial should not show until its navigation has committed.
1676 EXPECT_FALSE(interstitial
->is_showing());
1677 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1678 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1679 // Let's commit the interstitial navigation.
1680 interstitial
->TestDidNavigate(1, url2
);
1681 EXPECT_TRUE(interstitial
->is_showing());
1682 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1683 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1684 NavigationEntry
* entry
= controller().GetVisibleEntry();
1685 ASSERT_TRUE(entry
!= NULL
);
1686 // The URL specified to the interstitial should have been ignored.
1687 EXPECT_TRUE(entry
->GetURL() == url1
);
1690 interstitial
->Proceed();
1691 // Since this is not a new navigation, the previous page is dismissed right
1692 // away and shows the original page.
1693 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1694 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1695 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1696 entry
= controller().GetVisibleEntry();
1697 ASSERT_TRUE(entry
!= NULL
);
1698 EXPECT_TRUE(entry
->GetURL() == url1
);
1700 EXPECT_EQ(1, controller().GetEntryCount());
1702 RunAllPendingInMessageLoop();
1703 EXPECT_TRUE(deleted
);
1706 // Test navigating to a page that shows an interstitial, then navigating away.
1707 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1708 // Show interstitial.
1709 TestInterstitialPage::InterstitialState state
=
1710 TestInterstitialPage::INVALID
;
1711 bool deleted
= false;
1712 GURL
url("http://interstitial");
1713 TestInterstitialPage
* interstitial
=
1714 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1715 TestInterstitialPageStateGuard
state_guard(interstitial
);
1716 interstitial
->Show();
1717 interstitial
->TestDidNavigate(1, url
);
1719 // While interstitial showing, navigate to a new URL.
1720 const GURL
url2("http://www.yahoo.com");
1721 test_rvh()->SendNavigate(1, url2
);
1723 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1725 RunAllPendingInMessageLoop();
1726 EXPECT_TRUE(deleted
);
1729 // Test navigating to a page that shows an interstitial, then going back.
1730 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1731 // Navigate to a page so we have a navigation entry in the controller.
1732 GURL
url1("http://www.google.com");
1733 test_rvh()->SendNavigate(1, url1
);
1734 EXPECT_EQ(1, controller().GetEntryCount());
1736 // Show interstitial.
1737 TestInterstitialPage::InterstitialState state
=
1738 TestInterstitialPage::INVALID
;
1739 bool deleted
= false;
1740 GURL
interstitial_url("http://interstitial");
1741 TestInterstitialPage
* interstitial
=
1742 new TestInterstitialPage(contents(), true, interstitial_url
,
1744 TestInterstitialPageStateGuard
state_guard(interstitial
);
1745 interstitial
->Show();
1746 interstitial
->TestDidNavigate(2, interstitial_url
);
1748 // While the interstitial is showing, go back.
1749 controller().GoBack();
1750 test_rvh()->SendNavigate(1, url1
);
1752 // Make sure we are back to the original page and that the interstitial is
1754 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1755 NavigationEntry
* entry
= controller().GetVisibleEntry();
1757 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1759 RunAllPendingInMessageLoop();
1760 EXPECT_TRUE(deleted
);
1763 // Test navigating to a page that shows an interstitial, has a renderer crash,
1764 // and then goes back.
1765 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1766 // Navigate to a page so we have a navigation entry in the controller.
1767 GURL
url1("http://www.google.com");
1768 test_rvh()->SendNavigate(1, url1
);
1769 EXPECT_EQ(1, controller().GetEntryCount());
1771 // Show interstitial.
1772 TestInterstitialPage::InterstitialState state
=
1773 TestInterstitialPage::INVALID
;
1774 bool deleted
= false;
1775 GURL
interstitial_url("http://interstitial");
1776 TestInterstitialPage
* interstitial
=
1777 new TestInterstitialPage(contents(), true, interstitial_url
,
1779 TestInterstitialPageStateGuard
state_guard(interstitial
);
1780 interstitial
->Show();
1781 interstitial
->TestDidNavigate(2, interstitial_url
);
1783 // Crash the renderer
1784 test_rvh()->OnMessageReceived(
1785 ViewHostMsg_RenderProcessGone(
1786 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1788 // While the interstitial is showing, go back.
1789 controller().GoBack();
1790 test_rvh()->SendNavigate(1, url1
);
1792 // Make sure we are back to the original page and that the interstitial is
1794 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1795 NavigationEntry
* entry
= controller().GetVisibleEntry();
1797 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1799 RunAllPendingInMessageLoop();
1800 EXPECT_TRUE(deleted
);
1803 // Test navigating to a page that shows an interstitial, has the renderer crash,
1804 // and then navigates to the interstitial.
1805 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1806 // Navigate to a page so we have a navigation entry in the controller.
1807 GURL
url1("http://www.google.com");
1808 test_rvh()->SendNavigate(1, url1
);
1809 EXPECT_EQ(1, controller().GetEntryCount());
1811 // Show interstitial.
1812 TestInterstitialPage::InterstitialState state
=
1813 TestInterstitialPage::INVALID
;
1814 bool deleted
= false;
1815 GURL
interstitial_url("http://interstitial");
1816 TestInterstitialPage
* interstitial
=
1817 new TestInterstitialPage(contents(), true, interstitial_url
,
1819 TestInterstitialPageStateGuard
state_guard(interstitial
);
1820 interstitial
->Show();
1822 // Crash the renderer
1823 test_rvh()->OnMessageReceived(
1824 ViewHostMsg_RenderProcessGone(
1825 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1827 interstitial
->TestDidNavigate(2, interstitial_url
);
1830 // Test navigating to a page that shows an interstitial, then close the
1832 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1833 // Show interstitial.
1834 TestInterstitialPage::InterstitialState state
=
1835 TestInterstitialPage::INVALID
;
1836 bool deleted
= false;
1837 GURL
url("http://interstitial");
1838 TestInterstitialPage
* interstitial
=
1839 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1840 TestInterstitialPageStateGuard
state_guard(interstitial
);
1841 interstitial
->Show();
1842 interstitial
->TestDidNavigate(1, url
);
1844 // Now close the contents.
1846 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1848 RunAllPendingInMessageLoop();
1849 EXPECT_TRUE(deleted
);
1852 // Test navigating to a page that shows an interstitial, then close the
1854 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
1855 // Show interstitial.
1856 TestInterstitialPage::InterstitialState state
=
1857 TestInterstitialPage::INVALID
;
1858 bool deleted
= false;
1859 GURL
url("http://interstitial");
1860 TestInterstitialPage
* interstitial
=
1861 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1862 TestInterstitialPageStateGuard
state_guard(interstitial
);
1863 interstitial
->Show();
1864 interstitial
->TestDidNavigate(1, url
);
1865 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
1866 interstitial
->GetRenderViewHostForTesting());
1868 // Now close the contents.
1870 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1872 // Before the interstitial has a chance to process its shutdown task,
1873 // simulate quitting the browser. This goes through all processes and
1874 // tells them to destruct.
1875 rvh
->OnMessageReceived(
1876 ViewHostMsg_RenderProcessGone(0, 0, 0));
1878 RunAllPendingInMessageLoop();
1879 EXPECT_TRUE(deleted
);
1882 // Test that after Proceed is called and an interstitial is still shown, no more
1883 // commands get executed.
1884 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
1885 // Navigate to a page so we have a navigation entry in the controller.
1886 GURL
url1("http://www.google.com");
1887 test_rvh()->SendNavigate(1, url1
);
1888 EXPECT_EQ(1, controller().GetEntryCount());
1890 // Show an interstitial.
1891 TestInterstitialPage::InterstitialState state
=
1892 TestInterstitialPage::INVALID
;
1893 bool deleted
= false;
1894 GURL
url2("http://interstitial");
1895 TestInterstitialPage
* interstitial
=
1896 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1897 TestInterstitialPageStateGuard
state_guard(interstitial
);
1898 interstitial
->Show();
1899 interstitial
->TestDidNavigate(1, url2
);
1902 EXPECT_EQ(0, interstitial
->command_received_count());
1903 interstitial
->TestDomOperationResponse("toto");
1904 EXPECT_EQ(1, interstitial
->command_received_count());
1907 interstitial
->Proceed();
1908 RunAllPendingInMessageLoop();
1909 ASSERT_FALSE(deleted
);
1911 // While the navigation to the new page is pending, send other commands, they
1912 // should be ignored.
1913 interstitial
->TestDomOperationResponse("hello");
1914 interstitial
->TestDomOperationResponse("hi");
1915 EXPECT_EQ(1, interstitial
->command_received_count());
1918 // Test showing an interstitial while another interstitial is already showing.
1919 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
1920 // Navigate to a page so we have a navigation entry in the controller.
1921 GURL
start_url("http://www.google.com");
1922 test_rvh()->SendNavigate(1, start_url
);
1923 EXPECT_EQ(1, controller().GetEntryCount());
1925 // Show an interstitial.
1926 TestInterstitialPage::InterstitialState state1
=
1927 TestInterstitialPage::INVALID
;
1928 bool deleted1
= false;
1929 GURL
url1("http://interstitial1");
1930 TestInterstitialPage
* interstitial1
=
1931 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
1932 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
1933 interstitial1
->Show();
1934 interstitial1
->TestDidNavigate(1, url1
);
1936 // Now show another interstitial.
1937 TestInterstitialPage::InterstitialState state2
=
1938 TestInterstitialPage::INVALID
;
1939 bool deleted2
= false;
1940 GURL
url2("http://interstitial2");
1941 TestInterstitialPage
* interstitial2
=
1942 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
1943 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
1944 interstitial2
->Show();
1945 interstitial2
->TestDidNavigate(1, url2
);
1947 // Showing interstitial2 should have caused interstitial1 to go away.
1948 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
1949 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
1951 RunAllPendingInMessageLoop();
1952 EXPECT_TRUE(deleted1
);
1953 ASSERT_FALSE(deleted2
);
1955 // Let's make sure interstitial2 is working as intended.
1956 interstitial2
->Proceed();
1957 GURL
landing_url("http://www.thepage.com");
1958 test_rvh()->SendNavigate(2, landing_url
);
1960 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1961 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1962 NavigationEntry
* entry
= controller().GetVisibleEntry();
1963 ASSERT_TRUE(entry
!= NULL
);
1964 EXPECT_TRUE(entry
->GetURL() == landing_url
);
1965 EXPECT_EQ(2, controller().GetEntryCount());
1966 RunAllPendingInMessageLoop();
1967 EXPECT_TRUE(deleted2
);
1970 // Test showing an interstitial, proceeding and then navigating to another
1972 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
1973 // Navigate to a page so we have a navigation entry in the controller.
1974 GURL
start_url("http://www.google.com");
1975 test_rvh()->SendNavigate(1, start_url
);
1976 EXPECT_EQ(1, controller().GetEntryCount());
1978 // Show an interstitial.
1979 TestInterstitialPage::InterstitialState state1
=
1980 TestInterstitialPage::INVALID
;
1981 bool deleted1
= false;
1982 GURL
url1("http://interstitial1");
1983 TestInterstitialPage
* interstitial1
=
1984 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
1985 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
1986 interstitial1
->Show();
1987 interstitial1
->TestDidNavigate(1, url1
);
1989 // Take action. The interstitial won't be hidden until the navigation is
1991 interstitial1
->Proceed();
1992 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
1994 // Now show another interstitial (simulating the navigation causing another
1996 TestInterstitialPage::InterstitialState state2
=
1997 TestInterstitialPage::INVALID
;
1998 bool deleted2
= false;
1999 GURL
url2("http://interstitial2");
2000 TestInterstitialPage
* interstitial2
=
2001 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2002 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2003 interstitial2
->Show();
2004 interstitial2
->TestDidNavigate(1, url2
);
2006 // Showing interstitial2 should have caused interstitial1 to go away.
2007 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2008 RunAllPendingInMessageLoop();
2009 EXPECT_TRUE(deleted1
);
2010 ASSERT_FALSE(deleted2
);
2012 // Let's make sure interstitial2 is working as intended.
2013 interstitial2
->Proceed();
2014 GURL
landing_url("http://www.thepage.com");
2015 test_rvh()->SendNavigate(2, landing_url
);
2017 RunAllPendingInMessageLoop();
2018 EXPECT_TRUE(deleted2
);
2019 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2020 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2021 NavigationEntry
* entry
= controller().GetVisibleEntry();
2022 ASSERT_TRUE(entry
!= NULL
);
2023 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2024 EXPECT_EQ(2, controller().GetEntryCount());
2027 // Test that navigating away from an interstitial while it's loading cause it
2029 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2030 // Show an interstitial.
2031 TestInterstitialPage::InterstitialState state
=
2032 TestInterstitialPage::INVALID
;
2033 bool deleted
= false;
2034 GURL
interstitial_url("http://interstitial");
2035 TestInterstitialPage
* interstitial
=
2036 new TestInterstitialPage(contents(), true, interstitial_url
,
2038 TestInterstitialPageStateGuard
state_guard(interstitial
);
2039 interstitial
->Show();
2041 // Let's simulate a navigation initiated from the browser before the
2042 // interstitial finishes loading.
2043 const GURL
url("http://www.google.com");
2044 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2045 EXPECT_FALSE(interstitial
->is_showing());
2046 RunAllPendingInMessageLoop();
2047 ASSERT_FALSE(deleted
);
2049 // Now let's make the interstitial navigation commit.
2050 interstitial
->TestDidNavigate(1, interstitial_url
);
2052 // After it loaded the interstitial should be gone.
2053 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2055 RunAllPendingInMessageLoop();
2056 EXPECT_TRUE(deleted
);
2059 // Test that a new request to show an interstitial while an interstitial is
2060 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2061 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2062 GURL
interstitial_url("http://interstitial");
2064 // Show a first interstitial.
2065 TestInterstitialPage::InterstitialState state1
=
2066 TestInterstitialPage::INVALID
;
2067 bool deleted1
= false;
2068 TestInterstitialPage
* interstitial1
=
2069 new TestInterstitialPage(contents(), true, interstitial_url
,
2070 &state1
, &deleted1
);
2071 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2072 interstitial1
->Show();
2074 // Show another interstitial on that same contents before the first one had
2076 TestInterstitialPage::InterstitialState state2
=
2077 TestInterstitialPage::INVALID
;
2078 bool deleted2
= false;
2079 TestInterstitialPage
* interstitial2
=
2080 new TestInterstitialPage(contents(), true, interstitial_url
,
2081 &state2
, &deleted2
);
2082 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2083 interstitial2
->Show();
2085 // The first interstitial should have been closed and deleted.
2086 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2087 // The 2nd one should still be OK.
2088 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2090 RunAllPendingInMessageLoop();
2091 EXPECT_TRUE(deleted1
);
2092 ASSERT_FALSE(deleted2
);
2094 // Make the interstitial navigation commit it should be showing.
2095 interstitial2
->TestDidNavigate(1, interstitial_url
);
2096 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2099 // Test showing an interstitial and have its renderer crash.
2100 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2101 // Show an interstitial.
2102 TestInterstitialPage::InterstitialState state
=
2103 TestInterstitialPage::INVALID
;
2104 bool deleted
= false;
2105 GURL
url("http://interstitial");
2106 TestInterstitialPage
* interstitial
=
2107 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2108 TestInterstitialPageStateGuard
state_guard(interstitial
);
2109 interstitial
->Show();
2110 // Simulate a renderer crash before the interstitial is shown.
2111 interstitial
->TestRenderViewTerminated(
2112 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2113 // The interstitial should have been dismissed.
2114 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2115 RunAllPendingInMessageLoop();
2116 EXPECT_TRUE(deleted
);
2118 // Now try again but this time crash the intersitial after it was shown.
2120 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2121 interstitial
->Show();
2122 interstitial
->TestDidNavigate(1, url
);
2123 // Simulate a renderer crash.
2124 interstitial
->TestRenderViewTerminated(
2125 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2126 // The interstitial should have been dismissed.
2127 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2128 RunAllPendingInMessageLoop();
2129 EXPECT_TRUE(deleted
);
2132 // Tests that showing an interstitial as a result of a browser initiated
2133 // navigation while an interstitial is showing does not remove the pending
2134 // entry (see http://crbug.com/9791).
2135 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2136 const char kUrl
[] = "http://www.badguys.com/";
2137 const GURL
kGURL(kUrl
);
2139 // Start a navigation to a page
2140 contents()->GetController().LoadURL(
2141 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2143 // Simulate that navigation triggering an interstitial.
2144 TestInterstitialPage::InterstitialState state
=
2145 TestInterstitialPage::INVALID
;
2146 bool deleted
= false;
2147 TestInterstitialPage
* interstitial
=
2148 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2149 TestInterstitialPageStateGuard
state_guard(interstitial
);
2150 interstitial
->Show();
2151 interstitial
->TestDidNavigate(1, kGURL
);
2153 // Initiate a new navigation from the browser that also triggers an
2155 contents()->GetController().LoadURL(
2156 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2157 TestInterstitialPage::InterstitialState state2
=
2158 TestInterstitialPage::INVALID
;
2159 bool deleted2
= false;
2160 TestInterstitialPage
* interstitial2
=
2161 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2162 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2163 interstitial2
->Show();
2164 interstitial2
->TestDidNavigate(1, kGURL
);
2166 // Make sure we still have an entry.
2167 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2169 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2171 // And that the first interstitial is gone, but not the second.
2172 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2173 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2174 RunAllPendingInMessageLoop();
2175 EXPECT_TRUE(deleted
);
2176 EXPECT_FALSE(deleted2
);
2179 // Tests that Javascript messages are not shown while an interstitial is
2181 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2182 const char kUrl
[] = "http://www.badguys.com/";
2183 const GURL
kGURL(kUrl
);
2185 // Start a navigation to a page
2186 contents()->GetController().LoadURL(
2187 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2188 // DidNavigate from the page
2189 contents()->TestDidNavigate(rvh(), 1, kGURL
, PAGE_TRANSITION_TYPED
);
2191 // Simulate showing an interstitial while the page is showing.
2192 TestInterstitialPage::InterstitialState state
=
2193 TestInterstitialPage::INVALID
;
2194 bool deleted
= false;
2195 TestInterstitialPage
* interstitial
=
2196 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2197 TestInterstitialPageStateGuard
state_guard(interstitial
);
2198 interstitial
->Show();
2199 interstitial
->TestDidNavigate(1, kGURL
);
2201 // While the interstitial is showing, let's simulate the hidden page
2202 // attempting to show a JS message.
2203 IPC::Message
* dummy_message
= new IPC::Message
;
2204 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2205 base::ASCIIToUTF16("This is an informative message"),
2206 base::ASCIIToUTF16("OK"),
2207 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2208 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2211 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2212 // interstitial it isn't copied over to the destination.
2213 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2214 // Navigate to a page.
2215 GURL
url1("http://www.google.com");
2216 test_rvh()->SendNavigate(1, url1
);
2217 EXPECT_EQ(1, controller().GetEntryCount());
2219 // Initiate a browser navigation that will trigger the interstitial
2220 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2221 PAGE_TRANSITION_TYPED
, std::string());
2223 // Show an interstitial.
2224 TestInterstitialPage::InterstitialState state
=
2225 TestInterstitialPage::INVALID
;
2226 bool deleted
= false;
2227 GURL
url2("http://interstitial");
2228 TestInterstitialPage
* interstitial
=
2229 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2230 TestInterstitialPageStateGuard
state_guard(interstitial
);
2231 interstitial
->Show();
2232 interstitial
->TestDidNavigate(1, url2
);
2233 EXPECT_TRUE(interstitial
->is_showing());
2234 EXPECT_EQ(2, controller().GetEntryCount());
2236 // Create another NavigationController.
2237 GURL
url3("http://foo2");
2238 scoped_ptr
<TestWebContents
> other_contents(
2239 static_cast<TestWebContents
*>(CreateTestWebContents()));
2240 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2241 other_contents
->NavigateAndCommit(url3
);
2242 other_contents
->ExpectSetHistoryLengthAndPrune(
2243 NavigationEntryImpl::FromNavigationEntry(
2244 other_controller
.GetEntryAtIndex(0))->site_instance(), 1,
2245 other_controller
.GetEntryAtIndex(0)->GetPageID());
2246 other_controller
.CopyStateFromAndPrune(&controller(), false);
2248 // The merged controller should only have two entries: url1 and url2.
2249 ASSERT_EQ(2, other_controller
.GetEntryCount());
2250 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2251 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2252 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2254 // And the merged controller shouldn't be showing an interstitial.
2255 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2258 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2259 // showing an interstitial.
2260 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2261 // Navigate to a page.
2262 GURL
url1("http://www.google.com");
2263 contents()->NavigateAndCommit(url1
);
2265 // Create another NavigationController.
2266 scoped_ptr
<TestWebContents
> other_contents(
2267 static_cast<TestWebContents
*>(CreateTestWebContents()));
2268 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2270 // Navigate it to url2.
2271 GURL
url2("http://foo2");
2272 other_contents
->NavigateAndCommit(url2
);
2274 // Show an interstitial.
2275 TestInterstitialPage::InterstitialState state
=
2276 TestInterstitialPage::INVALID
;
2277 bool deleted
= false;
2278 GURL
url3("http://interstitial");
2279 TestInterstitialPage
* interstitial
=
2280 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2282 TestInterstitialPageStateGuard
state_guard(interstitial
);
2283 interstitial
->Show();
2284 interstitial
->TestDidNavigate(1, url3
);
2285 EXPECT_TRUE(interstitial
->is_showing());
2286 EXPECT_EQ(2, other_controller
.GetEntryCount());
2288 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2289 // interstitial is showing in the target.
2290 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2293 // Regression test for http://crbug.com/168611 - the URLs passed by the
2294 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2295 TEST_F(WebContentsImplTest
, FilterURLs
) {
2296 TestWebContentsObserver
observer(contents());
2298 // A navigation to about:whatever should always look like a navigation to
2300 GURL
url_normalized(kAboutBlankURL
);
2301 GURL
url_from_ipc("about:whatever");
2303 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2304 // will use the given URL to create the NavigationEntry as well, and that
2305 // entry should contain the filtered URL.
2306 contents()->NavigateAndCommit(url_normalized
);
2308 // Check that an IPC with about:whatever is correctly normalized.
2309 contents()->TestDidFinishLoad(url_from_ipc
);
2311 EXPECT_EQ(url_normalized
, observer
.last_url());
2313 // Create and navigate another WebContents.
2314 scoped_ptr
<TestWebContents
> other_contents(
2315 static_cast<TestWebContents
*>(CreateTestWebContents()));
2316 TestWebContentsObserver
other_observer(other_contents
.get());
2317 other_contents
->NavigateAndCommit(url_normalized
);
2319 // Check that an IPC with about:whatever is correctly normalized.
2320 other_contents
->TestDidFailLoadWithError(
2321 url_from_ipc
, 1, base::string16());
2322 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2325 // Test that if a pending contents is deleted before it is shown, we don't
2327 TEST_F(WebContentsImplTest
, PendingContents
) {
2328 scoped_ptr
<TestWebContents
> other_contents(
2329 static_cast<TestWebContents
*>(CreateTestWebContents()));
2330 contents()->AddPendingContents(other_contents
.get());
2331 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2332 other_contents
.reset();
2333 EXPECT_EQ(NULL
, contents()->GetCreatedWindow(route_id
));
2336 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2337 const gfx::Size
original_preferred_size(1024, 768);
2338 contents()->UpdatePreferredSize(original_preferred_size
);
2340 // With no capturers, expect the preferred size to be the one propagated into
2341 // WebContentsImpl via the RenderViewHostDelegate interface.
2342 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2343 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2345 // Increment capturer count, but without specifying a capture size. Expect
2346 // a "not set" preferred size.
2347 contents()->IncrementCapturerCount(gfx::Size());
2348 EXPECT_EQ(1, contents()->GetCapturerCount());
2349 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2351 // Increment capturer count again, but with an overriding capture size.
2352 // Expect preferred size to now be overridden to the capture size.
2353 const gfx::Size
capture_size(1280, 720);
2354 contents()->IncrementCapturerCount(capture_size
);
2355 EXPECT_EQ(2, contents()->GetCapturerCount());
2356 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2358 // Increment capturer count a third time, but the expect that the preferred
2359 // size is still the first capture size.
2360 const gfx::Size
another_capture_size(720, 480);
2361 contents()->IncrementCapturerCount(another_capture_size
);
2362 EXPECT_EQ(3, contents()->GetCapturerCount());
2363 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2365 // Decrement capturer count twice, but expect the preferred size to still be
2367 contents()->DecrementCapturerCount();
2368 contents()->DecrementCapturerCount();
2369 EXPECT_EQ(1, contents()->GetCapturerCount());
2370 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2372 // Decrement capturer count, and since the count has dropped to zero, the
2373 // original preferred size should be restored.
2374 contents()->DecrementCapturerCount();
2375 EXPECT_EQ(0, contents()->GetCapturerCount());
2376 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2379 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2381 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2382 // The WebContents starts with a valid creation time.
2383 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2385 // Reset the last active time to a known-bad value.
2386 contents()->last_active_time_
= base::TimeTicks();
2387 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2389 // Simulate activating the WebContents. The active time should update.
2390 contents()->WasShown();
2391 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2394 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2396 ContentsZoomChangedDelegate() :
2397 contents_zoom_changed_call_count_(0),
2398 last_zoom_in_(false) {
2401 int GetAndResetContentsZoomChangedCallCount() {
2402 int count
= contents_zoom_changed_call_count_
;
2403 contents_zoom_changed_call_count_
= 0;
2407 bool last_zoom_in() const {
2408 return last_zoom_in_
;
2411 // WebContentsDelegate:
2412 virtual void ContentsZoomChange(bool zoom_in
) OVERRIDE
{
2413 contents_zoom_changed_call_count_
++;
2414 last_zoom_in_
= zoom_in
;
2418 int contents_zoom_changed_call_count_
;
2421 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2424 // Tests that some mouseehweel events get turned into browser zoom requests.
2425 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2426 using blink::WebInputEvent
;
2428 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2429 new ContentsZoomChangedDelegate());
2430 contents()->SetDelegate(delegate
.get());
2433 // Verify that normal mouse wheel events do nothing to change the zoom level.
2434 blink::WebMouseWheelEvent event
=
2435 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2436 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2437 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2439 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
;
2440 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2441 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2442 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2444 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2445 // Except on MacOS where we never want to adjust zoom with mousewheel.
2446 modifiers
= WebInputEvent::ControlKey
;
2447 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2448 bool handled
= contents()->HandleWheelEvent(event
);
2449 #if defined(OS_MACOSX)
2450 EXPECT_FALSE(handled
);
2451 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2453 EXPECT_TRUE(handled
);
2454 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2455 EXPECT_TRUE(delegate
->last_zoom_in());
2458 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2459 WebInputEvent::AltKey
;
2460 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2461 handled
= contents()->HandleWheelEvent(event
);
2462 #if defined(OS_MACOSX)
2463 EXPECT_FALSE(handled
);
2464 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2466 EXPECT_TRUE(handled
);
2467 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2468 EXPECT_FALSE(delegate
->last_zoom_in());
2471 // Unless there is no vertical movement.
2472 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2473 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2474 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2476 // Events containing precise scrolling deltas also shouldn't result in the
2477 // zoom being adjusted, to avoid accidental adjustments caused by
2478 // two-finger-scrolling on a touchpad.
2479 modifiers
= WebInputEvent::ControlKey
;
2480 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2481 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2482 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2484 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2485 contents()->SetDelegate(NULL
);
2488 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2489 TEST_F(WebContentsImplTest
, HandleGestureEvent
) {
2490 using blink::WebGestureEvent
;
2491 using blink::WebInputEvent
;
2493 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2494 new ContentsZoomChangedDelegate());
2495 contents()->SetDelegate(delegate
.get());
2497 const float kZoomStepValue
= 0.6f
;
2498 blink::WebGestureEvent event
= SyntheticWebGestureEventBuilder::Build(
2499 WebInputEvent::GesturePinchUpdate
, WebGestureEvent::Touchpad
);
2501 // A pinch less than the step value doesn't change the zoom level.
2502 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 0.8f
;
2503 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2504 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2506 // But repeating the event so the combined scale is greater does.
2507 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2508 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2509 EXPECT_TRUE(delegate
->last_zoom_in());
2511 // Pinching back out one step goes back to 100%.
2512 event
.data
.pinchUpdate
.scale
= 1.0f
- kZoomStepValue
;
2513 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2514 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2515 EXPECT_FALSE(delegate
->last_zoom_in());
2517 // Pinching out again doesn't zoom (step is twice as large around 100%).
2518 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2519 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2521 // And again now it zooms once per step.
2522 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2523 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2524 EXPECT_FALSE(delegate
->last_zoom_in());
2526 // No other type of gesture event is handled by WebContentsImpl (for example
2527 // a touchscreen pinch gesture).
2528 event
= SyntheticWebGestureEventBuilder::Build(
2529 WebInputEvent::GesturePinchUpdate
, WebGestureEvent::Touchscreen
);
2530 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 3;
2531 EXPECT_FALSE(contents()->HandleGestureEvent(event
));
2532 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2534 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2535 contents()->SetDelegate(NULL
);
2538 } // namespace content