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(RenderFrameHost
* render_frame_host
,
276 const GURL
& validated_url
) OVERRIDE
{
277 last_url_
= validated_url
;
279 virtual void DidFailLoad(RenderFrameHost
* render_frame_host
,
280 const GURL
& validated_url
,
282 const base::string16
& error_description
) OVERRIDE
{
283 last_url_
= validated_url
;
286 const GURL
& last_url() const { return last_url_
; }
291 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver
);
294 // Pretends to be a normal browser that receives toggles and transitions to/from
295 // a fullscreened state.
296 class FakeFullscreenDelegate
: public WebContentsDelegate
{
298 FakeFullscreenDelegate() : fullscreened_contents_(NULL
) {}
299 virtual ~FakeFullscreenDelegate() {}
301 virtual void ToggleFullscreenModeForTab(WebContents
* web_contents
,
302 bool enter_fullscreen
) OVERRIDE
{
303 fullscreened_contents_
= enter_fullscreen
? web_contents
: NULL
;
306 virtual bool IsFullscreenForTabOrPending(const WebContents
* web_contents
)
308 return fullscreened_contents_
&& web_contents
== fullscreened_contents_
;
312 WebContents
* fullscreened_contents_
;
314 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate
);
317 class FakeValidationMessageDelegate
: public WebContentsDelegate
{
319 FakeValidationMessageDelegate()
320 : hide_validation_message_was_called_(false) {}
321 virtual ~FakeValidationMessageDelegate() {}
323 virtual void HideValidationMessage(WebContents
* web_contents
) OVERRIDE
{
324 hide_validation_message_was_called_
= true;
327 bool hide_validation_message_was_called() const {
328 return hide_validation_message_was_called_
;
332 bool hide_validation_message_was_called_
;
334 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate
);
339 // Test to make sure that title updates get stripped of whitespace.
340 TEST_F(WebContentsImplTest
, UpdateTitle
) {
341 NavigationControllerImpl
& cont
=
342 static_cast<NavigationControllerImpl
&>(controller());
343 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
345 ¶ms
, 0, GURL(url::kAboutBlankURL
), PAGE_TRANSITION_TYPED
);
347 LoadCommittedDetails details
;
348 cont
.RendererDidNavigate(main_test_rfh(), params
, &details
);
350 contents()->UpdateTitle(main_test_rfh(), 0,
351 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
352 base::i18n::LEFT_TO_RIGHT
);
353 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
356 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
357 const GURL
kGURL("chrome://blah");
358 controller().LoadURL(
359 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
360 EXPECT_EQ(base::string16(), contents()->GetTitle());
363 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
364 const GURL
kGURL("chrome://blah");
365 const base::string16 title
= base::ASCIIToUTF16("My Title");
366 controller().LoadURL(
367 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
369 NavigationEntry
* entry
= controller().GetVisibleEntry();
370 ASSERT_EQ(kGURL
, entry
->GetURL());
371 entry
->SetTitle(title
);
373 EXPECT_EQ(title
, contents()->GetTitle());
376 // Test view source mode for a webui page.
377 TEST_F(WebContentsImplTest
, NTPViewSource
) {
378 NavigationControllerImpl
& cont
=
379 static_cast<NavigationControllerImpl
&>(controller());
380 const char kUrl
[] = "view-source:chrome://blah";
381 const GURL
kGURL(kUrl
);
383 process()->sink().ClearMessages();
386 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
387 rvh()->GetDelegate()->RenderViewCreated(rvh());
388 // Did we get the expected message?
389 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
390 ViewMsg_EnableViewSourceMode::ID
));
392 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
393 InitNavigateParams(¶ms
, 0, kGURL
, PAGE_TRANSITION_TYPED
);
394 LoadCommittedDetails details
;
395 cont
.RendererDidNavigate(main_test_rfh(), params
, &details
);
396 // Also check title and url.
397 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
400 // Test to ensure UpdateMaxPageID is working properly.
401 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
402 SiteInstance
* instance1
= contents()->GetSiteInstance();
403 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(NULL
));
406 EXPECT_EQ(-1, contents()->GetMaxPageID());
407 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
408 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
410 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
411 contents()->UpdateMaxPageID(3);
412 contents()->UpdateMaxPageID(1);
413 EXPECT_EQ(3, contents()->GetMaxPageID());
414 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
415 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
417 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
418 EXPECT_EQ(3, contents()->GetMaxPageID());
419 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
420 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
423 // Test simple same-SiteInstance navigation.
424 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
425 TestRenderViewHost
* orig_rvh
= test_rvh();
426 SiteInstance
* instance1
= contents()->GetSiteInstance();
427 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
430 const GURL
url("http://www.google.com");
431 controller().LoadURL(
432 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
433 EXPECT_FALSE(contents()->cross_navigation_pending());
434 EXPECT_EQ(instance1
, orig_rvh
->GetSiteInstance());
435 // Controller's pending entry will have a NULL site instance until we assign
436 // it in DidNavigate.
438 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
439 site_instance() == NULL
);
441 // DidNavigate from the page
442 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
443 EXPECT_FALSE(contents()->cross_navigation_pending());
444 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
445 EXPECT_EQ(instance1
, orig_rvh
->GetSiteInstance());
446 // Controller's entry should now have the SiteInstance, or else we won't be
447 // able to find it later.
450 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
454 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
455 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
456 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
457 const GURL
url(std::string("http://example.org/").append(
458 GetMaxURLChars() + 1, 'a'));
460 controller().LoadURL(
461 url
, Referrer(), PAGE_TRANSITION_GENERATED
, std::string());
462 EXPECT_TRUE(controller().GetVisibleEntry() == NULL
);
465 // Test that navigating across a site boundary creates a new RenderViewHost
466 // with a new SiteInstance. Going back should do the same.
467 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
468 TestRenderViewHost
* orig_rvh
= test_rvh();
469 RenderFrameHostImpl
* orig_rfh
=
470 contents()->GetFrameTree()->root()->current_frame_host();
471 int orig_rvh_delete_count
= 0;
472 orig_rvh
->set_delete_counter(&orig_rvh_delete_count
);
473 SiteInstance
* instance1
= contents()->GetSiteInstance();
475 // Navigate to URL. First URL should use first RenderViewHost.
476 const GURL
url("http://www.google.com");
477 controller().LoadURL(
478 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
479 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
481 // Keep the number of active views in orig_rvh's SiteInstance
482 // non-zero so that orig_rvh doesn't get deleted when it gets
484 static_cast<SiteInstanceImpl
*>(orig_rvh
->GetSiteInstance())->
485 increment_active_view_count();
487 EXPECT_FALSE(contents()->cross_navigation_pending());
488 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
489 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
490 EXPECT_EQ(url
, contents()->GetVisibleURL());
492 // Navigate to new site
493 const GURL
url2("http://www.yahoo.com");
494 controller().LoadURL(
495 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
496 EXPECT_TRUE(contents()->cross_navigation_pending());
497 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
498 EXPECT_EQ(url2
, contents()->GetVisibleURL());
499 TestRenderViewHost
* pending_rvh
=
500 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
501 int pending_rvh_delete_count
= 0;
502 pending_rvh
->set_delete_counter(&pending_rvh_delete_count
);
503 RenderFrameHostImpl
* pending_rfh
= contents()->GetFrameTree()->root()->
504 render_manager()->pending_frame_host();
506 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
507 EXPECT_TRUE(pending_rvh
->are_navigations_suspended());
508 orig_rvh
->SendBeforeUnloadACK(true);
509 EXPECT_FALSE(pending_rvh
->are_navigations_suspended());
511 // DidNavigate from the pending page
512 contents()->TestDidNavigate(
513 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
514 SiteInstance
* instance2
= contents()->GetSiteInstance();
516 // Keep the number of active views in pending_rvh's SiteInstance
517 // non-zero so that orig_rvh doesn't get deleted when it gets
519 static_cast<SiteInstanceImpl
*>(pending_rvh
->GetSiteInstance())->
520 increment_active_view_count();
522 EXPECT_FALSE(contents()->cross_navigation_pending());
523 EXPECT_EQ(pending_rvh
, contents()->GetRenderViewHost());
524 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
525 EXPECT_EQ(url2
, contents()->GetVisibleURL());
526 EXPECT_NE(instance1
, instance2
);
527 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
528 // We keep the original RFH around, swapped out.
529 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
531 EXPECT_EQ(orig_rvh_delete_count
, 0);
533 // Going back should switch SiteInstances again. The first SiteInstance is
534 // stored in the NavigationEntry, so it should be the same as at the start.
535 // We should use the same RVH as before, swapping it back in.
536 controller().GoBack();
537 TestRenderViewHost
* goback_rvh
=
538 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
539 EXPECT_EQ(orig_rvh
, goback_rvh
);
540 EXPECT_TRUE(contents()->cross_navigation_pending());
542 // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
543 EXPECT_TRUE(goback_rvh
->are_navigations_suspended());
544 pending_rvh
->SendBeforeUnloadACK(true);
545 EXPECT_FALSE(goback_rvh
->are_navigations_suspended());
547 // DidNavigate from the back action
548 contents()->TestDidNavigate(
549 goback_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
550 EXPECT_FALSE(contents()->cross_navigation_pending());
551 EXPECT_EQ(goback_rvh
, contents()->GetRenderViewHost());
552 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
553 // The pending RFH should now be swapped out, not deleted.
554 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
555 IsOnSwappedOutList(pending_rfh
));
556 EXPECT_EQ(pending_rvh_delete_count
, 0);
557 pending_rvh
->OnSwappedOut(false);
559 // Close contents and ensure RVHs are deleted.
561 EXPECT_EQ(orig_rvh_delete_count
, 1);
562 EXPECT_EQ(pending_rvh_delete_count
, 1);
565 // Test that navigating across a site boundary after a crash creates a new
566 // RVH without requiring a cross-site transition (i.e., PENDING state).
567 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
568 TestRenderViewHost
* orig_rvh
= test_rvh();
569 int orig_rvh_delete_count
= 0;
570 orig_rvh
->set_delete_counter(&orig_rvh_delete_count
);
571 SiteInstance
* instance1
= contents()->GetSiteInstance();
573 // Navigate to URL. First URL should use first RenderViewHost.
574 const GURL
url("http://www.google.com");
575 controller().LoadURL(
576 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
577 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
579 EXPECT_FALSE(contents()->cross_navigation_pending());
580 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
582 // Crash the renderer.
583 orig_rvh
->set_render_view_created(false);
585 // Navigate to new site. We should not go into PENDING.
586 const GURL
url2("http://www.yahoo.com");
587 controller().LoadURL(
588 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
589 RenderViewHost
* new_rvh
= rvh();
590 EXPECT_FALSE(contents()->cross_navigation_pending());
591 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
592 EXPECT_NE(orig_rvh
, new_rvh
);
593 EXPECT_EQ(orig_rvh_delete_count
, 1);
595 // DidNavigate from the new page
596 contents()->TestDidNavigate(new_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
597 SiteInstance
* instance2
= contents()->GetSiteInstance();
599 EXPECT_FALSE(contents()->cross_navigation_pending());
600 EXPECT_EQ(new_rvh
, rvh());
601 EXPECT_NE(instance1
, instance2
);
602 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
604 // Close contents and ensure RVHs are deleted.
606 EXPECT_EQ(orig_rvh_delete_count
, 1);
609 // Test that opening a new contents in the same SiteInstance and then navigating
610 // both contentses to a new site will place both contentses in a single
612 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
613 TestRenderViewHost
* orig_rvh
= test_rvh();
614 SiteInstance
* instance1
= contents()->GetSiteInstance();
616 // Navigate to URL. First URL should use first RenderViewHost.
617 const GURL
url("http://www.google.com");
618 controller().LoadURL(
619 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
620 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
622 // Open a new contents with the same SiteInstance, navigated to the same site.
623 scoped_ptr
<TestWebContents
> contents2(
624 TestWebContents::Create(browser_context(), instance1
));
625 contents2
->GetController().LoadURL(url
, Referrer(),
626 PAGE_TRANSITION_TYPED
,
628 // Need this page id to be 2 since the site instance is the same (which is the
629 // scope of page IDs) and we want to consider this a new page.
630 contents2
->TestDidNavigate(
631 contents2
->GetRenderViewHost(), 2, url
, PAGE_TRANSITION_TYPED
);
633 // Navigate first contents to a new site.
634 const GURL
url2a("http://www.yahoo.com");
635 controller().LoadURL(
636 url2a
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
637 orig_rvh
->SendBeforeUnloadACK(true);
638 TestRenderViewHost
* pending_rvh_a
=
639 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
640 contents()->TestDidNavigate(
641 pending_rvh_a
, 1, url2a
, PAGE_TRANSITION_TYPED
);
642 SiteInstance
* instance2a
= contents()->GetSiteInstance();
643 EXPECT_NE(instance1
, instance2a
);
645 // Navigate second contents to the same site as the first tab.
646 const GURL
url2b("http://mail.yahoo.com");
647 contents2
->GetController().LoadURL(url2b
, Referrer(),
648 PAGE_TRANSITION_TYPED
,
650 TestRenderViewHost
* rvh2
=
651 static_cast<TestRenderViewHost
*>(contents2
->GetRenderViewHost());
652 rvh2
->SendBeforeUnloadACK(true);
653 TestRenderViewHost
* pending_rvh_b
=
654 static_cast<TestRenderViewHost
*>(contents2
->GetPendingRenderViewHost());
655 EXPECT_TRUE(pending_rvh_b
!= NULL
);
656 EXPECT_TRUE(contents2
->cross_navigation_pending());
658 // NOTE(creis): We used to be in danger of showing a crash page here if the
659 // second contents hadn't navigated somewhere first (bug 1145430). That case
660 // is now covered by the CrossSiteBoundariesAfterCrash test.
661 contents2
->TestDidNavigate(
662 pending_rvh_b
, 2, url2b
, PAGE_TRANSITION_TYPED
);
663 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
664 EXPECT_NE(instance1
, instance2b
);
666 // Both contentses should now be in the same SiteInstance.
667 EXPECT_EQ(instance2a
, instance2b
);
670 // The embedder can request sites for certain urls not be be assigned to the
671 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
672 // allowing to reuse the renderer backing certain chrome urls for subsequent
673 // navigation. The test verifies that the override is honored.
674 TEST_F(WebContentsImplTest
, NavigateFromSitelessUrl
) {
675 WebContentsImplTestBrowserClient browser_client
;
676 SetBrowserClientForTesting(&browser_client
);
678 TestRenderViewHost
* orig_rvh
= test_rvh();
679 RenderFrameHostImpl
* orig_rfh
=
680 contents()->GetFrameTree()->root()->current_frame_host();
681 int orig_rvh_delete_count
= 0;
682 orig_rvh
->set_delete_counter(&orig_rvh_delete_count
);
683 SiteInstanceImpl
* orig_instance
=
684 static_cast<SiteInstanceImpl
*>(contents()->GetSiteInstance());
686 browser_client
.set_assign_site_for_url(false);
687 // Navigate to an URL that will not assign a new SiteInstance.
688 const GURL
native_url("non-site-url://stuffandthings");
689 controller().LoadURL(
690 native_url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
691 contents()->TestDidNavigate(orig_rvh
, 1, native_url
, PAGE_TRANSITION_TYPED
);
693 EXPECT_FALSE(contents()->cross_navigation_pending());
694 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
695 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
696 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
697 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
698 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
699 EXPECT_FALSE(orig_instance
->HasSite());
701 browser_client
.set_assign_site_for_url(true);
702 // Navigate to new site (should keep same site instance).
703 const GURL
url("http://www.google.com");
704 controller().LoadURL(
705 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
706 EXPECT_FALSE(contents()->cross_navigation_pending());
707 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
708 EXPECT_EQ(url
, contents()->GetVisibleURL());
709 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
710 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
712 // Keep the number of active views in orig_rvh's SiteInstance
713 // non-zero so that orig_rvh doesn't get deleted when it gets
715 static_cast<SiteInstanceImpl
*>(orig_rvh
->GetSiteInstance())->
716 increment_active_view_count();
718 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
720 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
721 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
723 // Navigate to another new site (should create a new site instance).
724 const GURL
url2("http://www.yahoo.com");
725 controller().LoadURL(
726 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
727 EXPECT_TRUE(contents()->cross_navigation_pending());
728 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
729 EXPECT_EQ(url2
, contents()->GetVisibleURL());
730 TestRenderViewHost
* pending_rvh
=
731 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
732 int pending_rvh_delete_count
= 0;
733 pending_rvh
->set_delete_counter(&pending_rvh_delete_count
);
735 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
736 EXPECT_TRUE(pending_rvh
->are_navigations_suspended());
737 orig_rvh
->SendBeforeUnloadACK(true);
738 EXPECT_FALSE(pending_rvh
->are_navigations_suspended());
740 // DidNavigate from the pending page.
741 contents()->TestDidNavigate(
742 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
743 SiteInstance
* new_instance
= contents()->GetSiteInstance();
745 EXPECT_FALSE(contents()->cross_navigation_pending());
746 EXPECT_EQ(pending_rvh
, contents()->GetRenderViewHost());
747 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
748 EXPECT_EQ(url2
, contents()->GetVisibleURL());
749 EXPECT_NE(new_instance
, orig_instance
);
750 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
751 // We keep the original RFH around, swapped out.
752 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
754 EXPECT_EQ(orig_rvh_delete_count
, 0);
755 orig_rvh
->OnSwappedOut(false);
757 // Close contents and ensure RVHs are deleted.
759 EXPECT_EQ(orig_rvh_delete_count
, 1);
760 EXPECT_EQ(pending_rvh_delete_count
, 1);
763 // Regression test for http://crbug.com/386542 - variation of
764 // NavigateFromSitelessUrl in which the original navigation is a session
766 TEST_F(WebContentsImplTest
, NavigateFromRestoredSitelessUrl
) {
767 WebContentsImplTestBrowserClient browser_client
;
768 SetBrowserClientForTesting(&browser_client
);
769 SiteInstanceImpl
* orig_instance
=
770 static_cast<SiteInstanceImpl
*>(contents()->GetSiteInstance());
771 TestRenderViewHost
* orig_rvh
= test_rvh();
773 // Restore a navigation entry for URL that should not assign site to the
775 browser_client
.set_assign_site_for_url(false);
776 const GURL
native_url("non-site-url://stuffandthings");
777 std::vector
<NavigationEntry
*> entries
;
778 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
779 native_url
, Referrer(), PAGE_TRANSITION_LINK
, false, std::string(),
782 entries
.push_back(entry
);
783 controller().Restore(
785 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
787 ASSERT_EQ(0u, entries
.size());
788 ASSERT_EQ(1, controller().GetEntryCount());
789 controller().GoToIndex(0);
790 contents()->TestDidNavigate(orig_rvh
, 0, native_url
, PAGE_TRANSITION_RELOAD
);
791 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
792 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
793 EXPECT_FALSE(orig_instance
->HasSite());
795 // Navigate to a regular site and verify that the SiteInstance was kept.
796 browser_client
.set_assign_site_for_url(true);
797 const GURL
url("http://www.google.com");
798 controller().LoadURL(
799 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
800 contents()->TestDidNavigate(orig_rvh
, 2, url
, PAGE_TRANSITION_TYPED
);
801 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
807 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
808 // tab is restored, the SiteInstance will change upon navigation.
809 TEST_F(WebContentsImplTest
, NavigateFromRestoredRegularUrl
) {
810 WebContentsImplTestBrowserClient browser_client
;
811 SetBrowserClientForTesting(&browser_client
);
812 SiteInstanceImpl
* orig_instance
=
813 static_cast<SiteInstanceImpl
*>(contents()->GetSiteInstance());
814 TestRenderViewHost
* orig_rvh
= test_rvh();
816 // Restore a navigation entry for a regular URL ensuring that the embedder
817 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
818 browser_client
.set_assign_site_for_url(true);
819 const GURL
regular_url("http://www.yahoo.com");
820 std::vector
<NavigationEntry
*> entries
;
821 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
822 regular_url
, Referrer(), PAGE_TRANSITION_LINK
, false, std::string(),
825 entries
.push_back(entry
);
826 controller().Restore(
828 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
830 ASSERT_EQ(0u, entries
.size());
831 ASSERT_EQ(1, controller().GetEntryCount());
832 controller().GoToIndex(0);
833 contents()->TestDidNavigate(orig_rvh
, 0, regular_url
, PAGE_TRANSITION_RELOAD
);
834 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
835 EXPECT_TRUE(orig_instance
->HasSite());
837 // Navigate to another site and verify that a new SiteInstance was created.
838 const GURL
url("http://www.google.com");
839 controller().LoadURL(
840 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
841 contents()->TestDidNavigate(
842 contents()->GetPendingRenderViewHost(), 2, url
, PAGE_TRANSITION_TYPED
);
843 EXPECT_NE(orig_instance
, contents()->GetSiteInstance());
849 // Test that we can find an opener RVH even if it's pending.
850 // http://crbug.com/176252.
851 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
852 TestRenderViewHost
* orig_rvh
= test_rvh();
854 // Navigate to a URL.
855 const GURL
url("http://www.google.com");
856 controller().LoadURL(
857 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
858 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
860 // Start to navigate first tab to a new site, so that it has a pending RVH.
861 const GURL
url2("http://www.yahoo.com");
862 controller().LoadURL(
863 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
864 orig_rvh
->SendBeforeUnloadACK(true);
865 TestRenderViewHost
* pending_rvh
=
866 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
868 // While it is still pending, simulate opening a new tab with the first tab
869 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
870 // on the opener to ensure that an RVH exists.
871 int opener_routing_id
= contents()->CreateOpenerRenderViews(
872 pending_rvh
->GetSiteInstance());
874 // We should find the pending RVH and not create a new one.
875 EXPECT_EQ(pending_rvh
->GetRoutingID(), opener_routing_id
);
878 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
879 // to determine whether a navigation is cross-site.
880 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
881 RenderViewHost
* orig_rvh
= rvh();
882 SiteInstance
* instance1
= contents()->GetSiteInstance();
885 const GURL
url("http://www.google.com");
886 controller().LoadURL(
887 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
888 contents()->TestDidNavigate(
889 orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
891 // Open a related contents to a second site.
892 scoped_ptr
<TestWebContents
> contents2(
893 TestWebContents::Create(browser_context(), instance1
));
894 const GURL
url2("http://www.yahoo.com");
895 contents2
->GetController().LoadURL(url2
, Referrer(),
896 PAGE_TRANSITION_TYPED
,
898 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
900 TestRenderViewHost
* rvh2
= static_cast<TestRenderViewHost
*>(
901 contents2
->GetRenderViewHost());
902 EXPECT_FALSE(contents2
->cross_navigation_pending());
903 contents2
->TestDidNavigate(rvh2
, 2, url2
, PAGE_TRANSITION_TYPED
);
904 SiteInstance
* instance2
= contents2
->GetSiteInstance();
905 EXPECT_NE(instance1
, instance2
);
906 EXPECT_FALSE(contents2
->cross_navigation_pending());
908 // Simulate a link click in first contents to second site. Doesn't switch
909 // SiteInstances, because we don't intercept WebKit navigations.
910 contents()->TestDidNavigate(
911 orig_rvh
, 2, url2
, PAGE_TRANSITION_TYPED
);
912 SiteInstance
* instance3
= contents()->GetSiteInstance();
913 EXPECT_EQ(instance1
, instance3
);
914 EXPECT_FALSE(contents()->cross_navigation_pending());
916 // Navigate to the new site. Doesn't switch SiteInstancees, because we
917 // compare against the current URL, not the SiteInstance's site.
918 const GURL
url3("http://mail.yahoo.com");
919 controller().LoadURL(
920 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
921 EXPECT_FALSE(contents()->cross_navigation_pending());
922 contents()->TestDidNavigate(
923 orig_rvh
, 3, url3
, PAGE_TRANSITION_TYPED
);
924 SiteInstance
* instance4
= contents()->GetSiteInstance();
925 EXPECT_EQ(instance1
, instance4
);
928 // Test that the onbeforeunload and onunload handlers run when navigating
929 // across site boundaries.
930 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
931 TestRenderViewHost
* orig_rvh
= test_rvh();
932 SiteInstance
* instance1
= contents()->GetSiteInstance();
934 // Navigate to URL. First URL should use first RenderViewHost.
935 const GURL
url("http://www.google.com");
936 controller().LoadURL(
937 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
938 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
939 EXPECT_FALSE(contents()->cross_navigation_pending());
940 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
942 // Navigate to new site, but simulate an onbeforeunload denial.
943 const GURL
url2("http://www.yahoo.com");
944 controller().LoadURL(
945 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
946 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
947 base::TimeTicks now
= base::TimeTicks::Now();
948 orig_rvh
->GetMainFrame()->OnMessageReceived(
949 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
950 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
951 EXPECT_FALSE(contents()->cross_navigation_pending());
952 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
954 // Navigate again, but simulate an onbeforeunload approval.
955 controller().LoadURL(
956 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
957 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
958 now
= base::TimeTicks::Now();
959 orig_rvh
->GetMainFrame()->OnMessageReceived(
960 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
961 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
962 EXPECT_TRUE(contents()->cross_navigation_pending());
963 TestRenderViewHost
* pending_rvh
= static_cast<TestRenderViewHost
*>(
964 contents()->GetPendingRenderViewHost());
966 // We won't hear DidNavigate until the onunload handler has finished running.
968 // DidNavigate from the pending page.
969 contents()->TestDidNavigate(
970 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
971 SiteInstance
* instance2
= contents()->GetSiteInstance();
972 EXPECT_FALSE(contents()->cross_navigation_pending());
973 EXPECT_EQ(pending_rvh
, rvh());
974 EXPECT_NE(instance1
, instance2
);
975 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
978 // Test that during a slow cross-site navigation, the original renderer can
979 // navigate to a different URL and have it displayed, canceling the slow
981 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
982 TestRenderViewHost
* orig_rvh
= test_rvh();
983 SiteInstance
* instance1
= contents()->GetSiteInstance();
985 // Navigate to URL. First URL should use first RenderViewHost.
986 const GURL
url("http://www.google.com");
987 controller().LoadURL(
988 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
989 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
990 EXPECT_FALSE(contents()->cross_navigation_pending());
991 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
993 // Navigate to new site, simulating an onbeforeunload approval.
994 const GURL
url2("http://www.yahoo.com");
995 controller().LoadURL(
996 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
997 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
998 base::TimeTicks now
= base::TimeTicks::Now();
999 orig_rvh
->GetMainFrame()->OnMessageReceived(
1000 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1001 EXPECT_TRUE(contents()->cross_navigation_pending());
1003 // Suppose the original renderer navigates before the new one is ready.
1004 orig_rvh
->SendNavigate(2, GURL("http://www.google.com/foo"));
1006 // Verify that the pending navigation is cancelled.
1007 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1008 SiteInstance
* instance2
= contents()->GetSiteInstance();
1009 EXPECT_FALSE(contents()->cross_navigation_pending());
1010 EXPECT_EQ(orig_rvh
, rvh());
1011 EXPECT_EQ(instance1
, instance2
);
1012 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
1015 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1016 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1017 const GURL
url1("chrome://blah");
1018 controller().LoadURL(
1019 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1020 TestRenderViewHost
* ntp_rvh
= test_rvh();
1021 contents()->TestDidNavigate(ntp_rvh
, 1, url1
, PAGE_TRANSITION_TYPED
);
1022 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1023 SiteInstance
* instance1
= contents()->GetSiteInstance();
1025 EXPECT_FALSE(contents()->cross_navigation_pending());
1026 EXPECT_EQ(ntp_rvh
, contents()->GetRenderViewHost());
1027 EXPECT_EQ(url1
, entry1
->GetURL());
1028 EXPECT_EQ(instance1
,
1029 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1030 EXPECT_TRUE(ntp_rvh
->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
1032 // Navigate to new site.
1033 const GURL
url2("http://www.google.com");
1034 controller().LoadURL(
1035 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1036 EXPECT_TRUE(contents()->cross_navigation_pending());
1037 TestRenderViewHost
* google_rvh
=
1038 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
1040 // Simulate beforeunload approval.
1041 EXPECT_TRUE(ntp_rvh
->is_waiting_for_beforeunload_ack());
1042 base::TimeTicks now
= base::TimeTicks::Now();
1043 ntp_rvh
->GetMainFrame()->OnMessageReceived(
1044 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1046 // DidNavigate from the pending page.
1047 contents()->TestDidNavigate(
1048 google_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1049 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1050 SiteInstance
* instance2
= contents()->GetSiteInstance();
1052 EXPECT_FALSE(contents()->cross_navigation_pending());
1053 EXPECT_EQ(google_rvh
, contents()->GetRenderViewHost());
1054 EXPECT_NE(instance1
, instance2
);
1055 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
1056 EXPECT_EQ(url2
, entry2
->GetURL());
1057 EXPECT_EQ(instance2
,
1058 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1059 EXPECT_FALSE(google_rvh
->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI
);
1061 // Navigate to third page on same site.
1062 const GURL
url3("http://news.google.com");
1063 controller().LoadURL(
1064 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1065 EXPECT_FALSE(contents()->cross_navigation_pending());
1066 contents()->TestDidNavigate(
1067 google_rvh
, 2, url3
, PAGE_TRANSITION_TYPED
);
1068 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1069 SiteInstance
* instance3
= contents()->GetSiteInstance();
1071 EXPECT_FALSE(contents()->cross_navigation_pending());
1072 EXPECT_EQ(google_rvh
, contents()->GetRenderViewHost());
1073 EXPECT_EQ(instance2
, instance3
);
1074 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
1075 EXPECT_EQ(url3
, entry3
->GetURL());
1076 EXPECT_EQ(instance3
,
1077 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1079 // Go back within the site.
1080 controller().GoBack();
1081 EXPECT_FALSE(contents()->cross_navigation_pending());
1082 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1084 // Before that commits, go back again.
1085 controller().GoBack();
1086 EXPECT_TRUE(contents()->cross_navigation_pending());
1087 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
1088 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1090 // Simulate beforeunload approval.
1091 EXPECT_TRUE(google_rvh
->is_waiting_for_beforeunload_ack());
1092 now
= base::TimeTicks::Now();
1093 google_rvh
->GetMainFrame()->OnMessageReceived(
1094 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1096 // DidNavigate from the first back. This aborts the second back's pending RVH.
1097 contents()->TestDidNavigate(google_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1099 // We should commit this page and forget about the second back.
1100 EXPECT_FALSE(contents()->cross_navigation_pending());
1101 EXPECT_FALSE(controller().GetPendingEntry());
1102 EXPECT_EQ(google_rvh
, contents()->GetRenderViewHost());
1103 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1105 // We should not have corrupted the NTP entry.
1106 EXPECT_EQ(instance3
,
1107 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1108 EXPECT_EQ(instance2
,
1109 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1110 EXPECT_EQ(instance1
,
1111 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1112 EXPECT_EQ(url1
, entry1
->GetURL());
1115 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1116 // original renderer will not cancel the slow navigation (bug 42029).
1117 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1118 TestRenderViewHost
* orig_rvh
= test_rvh();
1120 // Navigate to URL. First URL should use first RenderViewHost.
1121 const GURL
url("http://www.google.com");
1122 controller().LoadURL(
1123 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1124 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1125 EXPECT_FALSE(contents()->cross_navigation_pending());
1126 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1128 // Start navigating to new site.
1129 const GURL
url2("http://www.yahoo.com");
1130 controller().LoadURL(
1131 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1133 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1134 // waiting for a before unload response.
1135 TestRenderFrameHost
* child_rfh
= static_cast<TestRenderFrameHost
*>(
1136 orig_rvh
->main_render_frame_host()->AppendChild("subframe"));
1137 child_rfh
->SendNavigateWithTransition(
1138 1, GURL("http://google.com/frame"), PAGE_TRANSITION_AUTO_SUBFRAME
);
1139 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
1141 // Now simulate the onbeforeunload approval and verify the navigation is
1143 base::TimeTicks now
= base::TimeTicks::Now();
1144 orig_rvh
->GetMainFrame()->OnMessageReceived(
1145 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1146 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1147 EXPECT_TRUE(contents()->cross_navigation_pending());
1150 // Test that a cross-site navigation is not preempted if the previous
1151 // renderer sends a FrameNavigate message just before being told to stop.
1152 // We should only preempt the cross-site navigation if the previous renderer
1153 // has started a new navigation. See http://crbug.com/79176.
1154 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1155 // Navigate to NTP URL.
1156 const GURL
url("chrome://blah");
1157 controller().LoadURL(
1158 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1159 TestRenderViewHost
* orig_rvh
= test_rvh();
1160 EXPECT_FALSE(contents()->cross_navigation_pending());
1162 // Navigate to new site, with the beforeunload request in flight.
1163 const GURL
url2("http://www.yahoo.com");
1164 controller().LoadURL(
1165 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1166 TestRenderViewHost
* pending_rvh
=
1167 static_cast<TestRenderViewHost
*>(contents()->GetPendingRenderViewHost());
1168 EXPECT_TRUE(contents()->cross_navigation_pending());
1169 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
1171 // Suppose the first navigation tries to commit now, with a
1172 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1173 // but it should act as if the beforeunload ack arrived.
1174 orig_rvh
->SendNavigate(1, GURL("chrome://blah"));
1175 EXPECT_TRUE(contents()->cross_navigation_pending());
1176 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1177 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1179 // The pending navigation should be able to commit successfully.
1180 contents()->TestDidNavigate(pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1181 EXPECT_FALSE(contents()->cross_navigation_pending());
1182 EXPECT_EQ(pending_rvh
, contents()->GetRenderViewHost());
1185 // Test that the original renderer cannot preempt a cross-site navigation once
1186 // the unload request has been made. At this point, the cross-site navigation
1187 // is almost ready to be displayed, and the original renderer is only given a
1188 // short chance to run an unload handler. Prevents regression of bug 23942.
1189 TEST_F(WebContentsImplTest
, CrossSiteCantPreemptAfterUnload
) {
1190 TestRenderViewHost
* orig_rvh
= test_rvh();
1191 SiteInstance
* instance1
= contents()->GetSiteInstance();
1193 // Navigate to URL. First URL should use first RenderViewHost.
1194 const GURL
url("http://www.google.com");
1195 controller().LoadURL(
1196 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1197 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1198 EXPECT_FALSE(contents()->cross_navigation_pending());
1199 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1201 // Navigate to new site, simulating an onbeforeunload approval.
1202 const GURL
url2("http://www.yahoo.com");
1203 controller().LoadURL(
1204 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1205 base::TimeTicks now
= base::TimeTicks::Now();
1206 orig_rvh
->GetMainFrame()->OnMessageReceived(
1207 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1208 EXPECT_TRUE(contents()->cross_navigation_pending());
1209 TestRenderViewHost
* pending_rvh
= static_cast<TestRenderViewHost
*>(
1210 contents()->GetPendingRenderViewHost());
1212 // Simulate the pending renderer's response, which leads to an unload request
1213 // being sent to orig_rvh.
1214 std::vector
<GURL
> url_chain
;
1215 url_chain
.push_back(GURL());
1216 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1217 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1218 GlobalRequestID(0, 0), scoped_ptr
<CrossSiteTransferringRequest
>(),
1219 url_chain
, Referrer(), PAGE_TRANSITION_TYPED
, false);
1221 // Suppose the original renderer navigates now, while the unload request is in
1222 // flight. We should ignore it, wait for the unload ack, and let the pending
1223 // request continue. Otherwise, the contents may close spontaneously or stop
1224 // responding to navigation requests. (See bug 23942.)
1225 FrameHostMsg_DidCommitProvisionalLoad_Params params1a
;
1226 InitNavigateParams(¶ms1a
, 2, GURL("http://www.google.com/foo"),
1227 PAGE_TRANSITION_TYPED
);
1228 orig_rvh
->SendNavigate(2, GURL("http://www.google.com/foo"));
1230 // Verify that the pending navigation is still in progress.
1231 EXPECT_TRUE(contents()->cross_navigation_pending());
1232 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL
);
1234 // DidNavigate from the pending page should commit it.
1235 contents()->TestDidNavigate(
1236 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1237 SiteInstance
* instance2
= contents()->GetSiteInstance();
1238 EXPECT_FALSE(contents()->cross_navigation_pending());
1239 EXPECT_EQ(pending_rvh
, rvh());
1240 EXPECT_NE(instance1
, instance2
);
1241 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
1244 // Test that a cross-site navigation that doesn't commit after the unload
1245 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1246 TEST_F(WebContentsImplTest
, CrossSiteNavigationCanceled
) {
1247 TestRenderViewHost
* orig_rvh
= test_rvh();
1248 SiteInstance
* instance1
= contents()->GetSiteInstance();
1250 // Navigate to URL. First URL should use first RenderViewHost.
1251 const GURL
url("http://www.google.com");
1252 controller().LoadURL(
1253 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1254 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1255 EXPECT_FALSE(contents()->cross_navigation_pending());
1256 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1258 // Navigate to new site, simulating an onbeforeunload approval.
1259 const GURL
url2("http://www.yahoo.com");
1260 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1261 EXPECT_TRUE(orig_rvh
->is_waiting_for_beforeunload_ack());
1262 base::TimeTicks now
= base::TimeTicks::Now();
1263 orig_rvh
->GetMainFrame()->OnMessageReceived(
1264 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1265 EXPECT_TRUE(contents()->cross_navigation_pending());
1267 // Simulate swap out message when the response arrives.
1268 orig_rvh
->OnSwappedOut(false);
1270 // Suppose the navigation doesn't get a chance to commit, and the user
1271 // navigates in the current RVH's SiteInstance.
1272 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1274 // Verify that the pending navigation is cancelled and the renderer is no
1275 // longer swapped out.
1276 EXPECT_FALSE(orig_rvh
->is_waiting_for_beforeunload_ack());
1277 SiteInstance
* instance2
= contents()->GetSiteInstance();
1278 EXPECT_FALSE(contents()->cross_navigation_pending());
1279 EXPECT_EQ(orig_rvh
, rvh());
1280 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT
, orig_rvh
->rvh_state());
1281 EXPECT_EQ(instance1
, instance2
);
1282 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL
);
1285 // Test that NavigationEntries have the correct page state after going
1286 // forward and back. Prevents regression for bug 1116137.
1287 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1288 TestRenderViewHost
* orig_rvh
= test_rvh();
1290 // Navigate to URL. There should be no committed entry yet.
1291 const GURL
url("http://www.google.com");
1292 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1293 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1294 EXPECT_TRUE(entry
== NULL
);
1296 // Committed entry should have page state after DidNavigate.
1297 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1298 entry
= controller().GetLastCommittedEntry();
1299 EXPECT_TRUE(entry
->GetPageState().IsValid());
1301 // Navigate to same site.
1302 const GURL
url2("http://images.google.com");
1303 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1304 entry
= controller().GetLastCommittedEntry();
1305 EXPECT_TRUE(entry
->GetPageState().IsValid());
1307 // Committed entry should have page state after DidNavigate.
1308 contents()->TestDidNavigate(orig_rvh
, 2, url2
, PAGE_TRANSITION_TYPED
);
1309 entry
= controller().GetLastCommittedEntry();
1310 EXPECT_TRUE(entry
->GetPageState().IsValid());
1312 // Now go back. Committed entry should still have page state.
1313 controller().GoBack();
1314 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1315 entry
= controller().GetLastCommittedEntry();
1316 EXPECT_TRUE(entry
->GetPageState().IsValid());
1319 // Test that NavigationEntries have the correct page state and SiteInstance
1320 // state after opening a new window to about:blank. Prevents regression for
1321 // bugs b/1116137 and http://crbug.com/111975.
1322 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1323 TestRenderViewHost
* orig_rvh
= test_rvh();
1325 // When opening a new window, it is navigated to about:blank internally.
1326 // Currently, this results in two DidNavigate events.
1327 const GURL
url(url::kAboutBlankURL
);
1328 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1329 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1331 // Should have a page state here.
1332 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1333 EXPECT_TRUE(entry
->GetPageState().IsValid());
1335 // The SiteInstance should be available for other navigations to use.
1336 NavigationEntryImpl
* entry_impl
=
1337 NavigationEntryImpl::FromNavigationEntry(entry
);
1338 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1339 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1341 // Navigating to a normal page should not cause a process swap.
1342 const GURL
new_url("http://www.google.com");
1343 controller().LoadURL(new_url
, Referrer(),
1344 PAGE_TRANSITION_TYPED
, std::string());
1345 EXPECT_FALSE(contents()->cross_navigation_pending());
1346 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1347 contents()->TestDidNavigate(orig_rvh
, 1, new_url
, PAGE_TRANSITION_TYPED
);
1348 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1349 controller().GetLastCommittedEntry());
1350 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1351 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1354 // Tests that fullscreen is exited throughout the object hierarchy when
1355 // navigating to a new page.
1356 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1357 FakeFullscreenDelegate fake_delegate
;
1358 contents()->SetDelegate(&fake_delegate
);
1359 TestRenderViewHost
* orig_rvh
= test_rvh();
1361 // Navigate to a site.
1362 const GURL
url("http://www.google.com");
1363 controller().LoadURL(
1364 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1365 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1366 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1368 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1369 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1370 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1371 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1372 orig_rvh
->OnMessageReceived(
1373 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1374 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1375 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1376 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1378 // Navigate to a new site.
1379 const GURL
url2("http://www.yahoo.com");
1380 controller().LoadURL(
1381 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1382 RenderViewHost
* const pending_rvh
= contents()->GetPendingRenderViewHost();
1383 contents()->TestDidNavigate(
1384 pending_rvh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1386 // Confirm fullscreen has exited.
1387 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1388 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1389 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1391 contents()->SetDelegate(NULL
);
1394 // Tests that fullscreen is exited throughout the object hierarchy when
1395 // instructing NavigationController to GoBack() or GoForward().
1396 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1397 FakeFullscreenDelegate fake_delegate
;
1398 contents()->SetDelegate(&fake_delegate
);
1399 TestRenderViewHost
* const orig_rvh
= test_rvh();
1401 // Navigate to a site.
1402 const GURL
url("http://www.google.com");
1403 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1404 contents()->TestDidNavigate(orig_rvh
, 1, url
, PAGE_TRANSITION_TYPED
);
1405 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1407 // Now, navigate to another page on the same site.
1408 const GURL
url2("http://www.google.com/search?q=kittens");
1409 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1410 EXPECT_FALSE(contents()->cross_navigation_pending());
1411 contents()->TestDidNavigate(orig_rvh
, 2, url2
, PAGE_TRANSITION_TYPED
);
1412 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1414 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1415 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1416 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1417 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1419 for (int i
= 0; i
< 2; ++i
) {
1420 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1421 orig_rvh
->OnMessageReceived(
1422 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1423 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1424 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1425 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1427 // Navigate backward (or forward).
1429 controller().GoBack();
1431 controller().GoForward();
1432 EXPECT_FALSE(contents()->cross_navigation_pending());
1433 EXPECT_EQ(orig_rvh
, contents()->GetRenderViewHost());
1434 contents()->TestDidNavigate(
1435 orig_rvh
, i
+ 1, url
, PAGE_TRANSITION_FORWARD_BACK
);
1437 // Confirm fullscreen has exited.
1438 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1439 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1440 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1443 contents()->SetDelegate(NULL
);
1446 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1447 FakeValidationMessageDelegate fake_delegate
;
1448 contents()->SetDelegate(&fake_delegate
);
1449 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1451 // Crash the renderer.
1452 test_rvh()->OnMessageReceived(
1453 ViewHostMsg_RenderProcessGone(
1454 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1456 // Confirm HideValidationMessage was called.
1457 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1459 contents()->SetDelegate(NULL
);
1462 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1464 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1465 FakeFullscreenDelegate fake_delegate
;
1466 contents()->SetDelegate(&fake_delegate
);
1468 // Navigate to a site.
1469 const GURL
url("http://www.google.com");
1470 controller().LoadURL(
1471 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1472 contents()->TestDidNavigate(test_rvh(), 1, url
, PAGE_TRANSITION_TYPED
);
1473 EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
1475 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1476 EXPECT_FALSE(test_rvh()->IsFullscreen());
1477 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1478 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1479 test_rvh()->OnMessageReceived(
1480 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1481 EXPECT_TRUE(test_rvh()->IsFullscreen());
1482 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1483 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1485 // Crash the renderer.
1486 test_rvh()->OnMessageReceived(
1487 ViewHostMsg_RenderProcessGone(
1488 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1490 // Confirm fullscreen has exited.
1491 EXPECT_FALSE(test_rvh()->IsFullscreen());
1492 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1493 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1495 contents()->SetDelegate(NULL
);
1498 ////////////////////////////////////////////////////////////////////////////////
1499 // Interstitial Tests
1500 ////////////////////////////////////////////////////////////////////////////////
1502 // Test navigating to a page (with the navigation initiated from the browser,
1503 // as when a URL is typed in the location bar) that shows an interstitial and
1504 // creates a new navigation entry, then hiding it without proceeding.
1505 TEST_F(WebContentsImplTest
,
1506 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1507 // Navigate to a page.
1508 GURL
url1("http://www.google.com");
1509 test_rvh()->SendNavigate(1, url1
);
1510 EXPECT_EQ(1, controller().GetEntryCount());
1512 // Initiate a browser navigation that will trigger the interstitial
1513 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1514 PAGE_TRANSITION_TYPED
, std::string());
1516 // Show an interstitial.
1517 TestInterstitialPage::InterstitialState state
=
1518 TestInterstitialPage::INVALID
;
1519 bool deleted
= false;
1520 GURL
url2("http://interstitial");
1521 TestInterstitialPage
* interstitial
=
1522 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1523 TestInterstitialPageStateGuard
state_guard(interstitial
);
1524 interstitial
->Show();
1525 // The interstitial should not show until its navigation has committed.
1526 EXPECT_FALSE(interstitial
->is_showing());
1527 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1528 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1529 // Let's commit the interstitial navigation.
1530 interstitial
->TestDidNavigate(1, url2
);
1531 EXPECT_TRUE(interstitial
->is_showing());
1532 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1533 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1534 NavigationEntry
* entry
= controller().GetVisibleEntry();
1535 ASSERT_TRUE(entry
!= NULL
);
1536 EXPECT_TRUE(entry
->GetURL() == url2
);
1538 // Now don't proceed.
1539 interstitial
->DontProceed();
1540 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1541 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1542 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1543 entry
= controller().GetVisibleEntry();
1544 ASSERT_TRUE(entry
!= NULL
);
1545 EXPECT_TRUE(entry
->GetURL() == url1
);
1546 EXPECT_EQ(1, controller().GetEntryCount());
1548 RunAllPendingInMessageLoop();
1549 EXPECT_TRUE(deleted
);
1552 // Test navigating to a page (with the navigation initiated from the renderer,
1553 // as when clicking on a link in the page) that shows an interstitial and
1554 // creates a new navigation entry, then hiding it without proceeding.
1555 TEST_F(WebContentsImplTest
,
1556 ShowInterstitiaFromRendererlWithNewNavigationDontProceed
) {
1557 // Navigate to a page.
1558 GURL
url1("http://www.google.com");
1559 test_rvh()->SendNavigate(1, url1
);
1560 EXPECT_EQ(1, controller().GetEntryCount());
1562 // Show an interstitial (no pending entry, the interstitial would have been
1563 // triggered by clicking on a link).
1564 TestInterstitialPage::InterstitialState state
=
1565 TestInterstitialPage::INVALID
;
1566 bool deleted
= false;
1567 GURL
url2("http://interstitial");
1568 TestInterstitialPage
* interstitial
=
1569 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1570 TestInterstitialPageStateGuard
state_guard(interstitial
);
1571 interstitial
->Show();
1572 // The interstitial should not show until its navigation has committed.
1573 EXPECT_FALSE(interstitial
->is_showing());
1574 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1575 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1576 // Let's commit the interstitial navigation.
1577 interstitial
->TestDidNavigate(1, url2
);
1578 EXPECT_TRUE(interstitial
->is_showing());
1579 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1580 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1581 NavigationEntry
* entry
= controller().GetVisibleEntry();
1582 ASSERT_TRUE(entry
!= NULL
);
1583 EXPECT_TRUE(entry
->GetURL() == url2
);
1585 // Now don't proceed.
1586 interstitial
->DontProceed();
1587 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1588 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1589 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1590 entry
= controller().GetVisibleEntry();
1591 ASSERT_TRUE(entry
!= NULL
);
1592 EXPECT_TRUE(entry
->GetURL() == url1
);
1593 EXPECT_EQ(1, controller().GetEntryCount());
1595 RunAllPendingInMessageLoop();
1596 EXPECT_TRUE(deleted
);
1599 // Test navigating to a page that shows an interstitial without creating a new
1600 // navigation entry (this happens when the interstitial is triggered by a
1601 // sub-resource in the page), then hiding it without proceeding.
1602 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1603 // Navigate to a page.
1604 GURL
url1("http://www.google.com");
1605 test_rvh()->SendNavigate(1, url1
);
1606 EXPECT_EQ(1, controller().GetEntryCount());
1608 // Show an interstitial.
1609 TestInterstitialPage::InterstitialState state
=
1610 TestInterstitialPage::INVALID
;
1611 bool deleted
= false;
1612 GURL
url2("http://interstitial");
1613 TestInterstitialPage
* interstitial
=
1614 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1615 TestInterstitialPageStateGuard
state_guard(interstitial
);
1616 interstitial
->Show();
1617 // The interstitial should not show until its navigation has committed.
1618 EXPECT_FALSE(interstitial
->is_showing());
1619 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1620 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1621 // Let's commit the interstitial navigation.
1622 interstitial
->TestDidNavigate(1, url2
);
1623 EXPECT_TRUE(interstitial
->is_showing());
1624 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1625 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1626 NavigationEntry
* entry
= controller().GetVisibleEntry();
1627 ASSERT_TRUE(entry
!= NULL
);
1628 // The URL specified to the interstitial should have been ignored.
1629 EXPECT_TRUE(entry
->GetURL() == url1
);
1631 // Now don't proceed.
1632 interstitial
->DontProceed();
1633 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1634 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1635 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1636 entry
= controller().GetVisibleEntry();
1637 ASSERT_TRUE(entry
!= NULL
);
1638 EXPECT_TRUE(entry
->GetURL() == url1
);
1639 EXPECT_EQ(1, controller().GetEntryCount());
1641 RunAllPendingInMessageLoop();
1642 EXPECT_TRUE(deleted
);
1645 // Test navigating to a page (with the navigation initiated from the browser,
1646 // as when a URL is typed in the location bar) that shows an interstitial and
1647 // creates a new navigation entry, then proceeding.
1648 TEST_F(WebContentsImplTest
,
1649 ShowInterstitialFromBrowserNewNavigationProceed
) {
1650 // Navigate to a page.
1651 GURL
url1("http://www.google.com");
1652 test_rvh()->SendNavigate(1, url1
);
1653 EXPECT_EQ(1, controller().GetEntryCount());
1655 // Initiate a browser navigation that will trigger the interstitial
1656 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1657 PAGE_TRANSITION_TYPED
, std::string());
1659 // Show an interstitial.
1660 TestInterstitialPage::InterstitialState state
=
1661 TestInterstitialPage::INVALID
;
1662 bool deleted
= false;
1663 GURL
url2("http://interstitial");
1664 TestInterstitialPage
* interstitial
=
1665 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1666 TestInterstitialPageStateGuard
state_guard(interstitial
);
1667 interstitial
->Show();
1668 // The interstitial should not show until its navigation has committed.
1669 EXPECT_FALSE(interstitial
->is_showing());
1670 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1671 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1672 // Let's commit the interstitial navigation.
1673 interstitial
->TestDidNavigate(1, url2
);
1674 EXPECT_TRUE(interstitial
->is_showing());
1675 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1676 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1677 NavigationEntry
* entry
= controller().GetVisibleEntry();
1678 ASSERT_TRUE(entry
!= NULL
);
1679 EXPECT_TRUE(entry
->GetURL() == url2
);
1682 interstitial
->Proceed();
1683 // The interstitial should show until the new navigation commits.
1684 RunAllPendingInMessageLoop();
1685 ASSERT_FALSE(deleted
);
1686 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1687 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1688 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1690 // Simulate the navigation to the page, that's when the interstitial gets
1692 GURL
url3("http://www.thepage.com");
1693 test_rvh()->SendNavigate(2, url3
);
1695 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1696 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1697 entry
= controller().GetVisibleEntry();
1698 ASSERT_TRUE(entry
!= NULL
);
1699 EXPECT_TRUE(entry
->GetURL() == url3
);
1701 EXPECT_EQ(2, controller().GetEntryCount());
1703 RunAllPendingInMessageLoop();
1704 EXPECT_TRUE(deleted
);
1707 // Test navigating to a page (with the navigation initiated from the renderer,
1708 // as when clicking on a link in the page) that shows an interstitial and
1709 // creates a new navigation entry, then proceeding.
1710 TEST_F(WebContentsImplTest
,
1711 ShowInterstitialFromRendererNewNavigationProceed
) {
1712 // Navigate to a page.
1713 GURL
url1("http://www.google.com");
1714 test_rvh()->SendNavigate(1, url1
);
1715 EXPECT_EQ(1, controller().GetEntryCount());
1717 // Show an interstitial.
1718 TestInterstitialPage::InterstitialState state
=
1719 TestInterstitialPage::INVALID
;
1720 bool deleted
= false;
1721 GURL
url2("http://interstitial");
1722 TestInterstitialPage
* interstitial
=
1723 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1724 TestInterstitialPageStateGuard
state_guard(interstitial
);
1725 interstitial
->Show();
1726 // The interstitial should not show until its navigation has committed.
1727 EXPECT_FALSE(interstitial
->is_showing());
1728 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1729 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1730 // Let's commit the interstitial navigation.
1731 interstitial
->TestDidNavigate(1, url2
);
1732 EXPECT_TRUE(interstitial
->is_showing());
1733 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1734 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1735 NavigationEntry
* entry
= controller().GetVisibleEntry();
1736 ASSERT_TRUE(entry
!= NULL
);
1737 EXPECT_TRUE(entry
->GetURL() == url2
);
1740 interstitial
->Proceed();
1741 // The interstitial should show until the new navigation commits.
1742 RunAllPendingInMessageLoop();
1743 ASSERT_FALSE(deleted
);
1744 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1745 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1746 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1748 // Simulate the navigation to the page, that's when the interstitial gets
1750 GURL
url3("http://www.thepage.com");
1751 test_rvh()->SendNavigate(2, url3
);
1753 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1754 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1755 entry
= controller().GetVisibleEntry();
1756 ASSERT_TRUE(entry
!= NULL
);
1757 EXPECT_TRUE(entry
->GetURL() == url3
);
1759 EXPECT_EQ(2, controller().GetEntryCount());
1761 RunAllPendingInMessageLoop();
1762 EXPECT_TRUE(deleted
);
1765 // Test navigating to a page that shows an interstitial without creating a new
1766 // navigation entry (this happens when the interstitial is triggered by a
1767 // sub-resource in the page), then proceeding.
1768 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1769 // Navigate to a page so we have a navigation entry in the controller.
1770 GURL
url1("http://www.google.com");
1771 test_rvh()->SendNavigate(1, url1
);
1772 EXPECT_EQ(1, controller().GetEntryCount());
1774 // Show an interstitial.
1775 TestInterstitialPage::InterstitialState state
=
1776 TestInterstitialPage::INVALID
;
1777 bool deleted
= false;
1778 GURL
url2("http://interstitial");
1779 TestInterstitialPage
* interstitial
=
1780 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1781 TestInterstitialPageStateGuard
state_guard(interstitial
);
1782 interstitial
->Show();
1783 // The interstitial should not show until its navigation has committed.
1784 EXPECT_FALSE(interstitial
->is_showing());
1785 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1786 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1787 // Let's commit the interstitial navigation.
1788 interstitial
->TestDidNavigate(1, url2
);
1789 EXPECT_TRUE(interstitial
->is_showing());
1790 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1791 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1792 NavigationEntry
* entry
= controller().GetVisibleEntry();
1793 ASSERT_TRUE(entry
!= NULL
);
1794 // The URL specified to the interstitial should have been ignored.
1795 EXPECT_TRUE(entry
->GetURL() == url1
);
1798 interstitial
->Proceed();
1799 // Since this is not a new navigation, the previous page is dismissed right
1800 // away and shows the original page.
1801 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1802 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1803 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1804 entry
= controller().GetVisibleEntry();
1805 ASSERT_TRUE(entry
!= NULL
);
1806 EXPECT_TRUE(entry
->GetURL() == url1
);
1808 EXPECT_EQ(1, controller().GetEntryCount());
1810 RunAllPendingInMessageLoop();
1811 EXPECT_TRUE(deleted
);
1814 // Test navigating to a page that shows an interstitial, then navigating away.
1815 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1816 // Show interstitial.
1817 TestInterstitialPage::InterstitialState state
=
1818 TestInterstitialPage::INVALID
;
1819 bool deleted
= false;
1820 GURL
url("http://interstitial");
1821 TestInterstitialPage
* interstitial
=
1822 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1823 TestInterstitialPageStateGuard
state_guard(interstitial
);
1824 interstitial
->Show();
1825 interstitial
->TestDidNavigate(1, url
);
1827 // While interstitial showing, navigate to a new URL.
1828 const GURL
url2("http://www.yahoo.com");
1829 test_rvh()->SendNavigate(1, url2
);
1831 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1833 RunAllPendingInMessageLoop();
1834 EXPECT_TRUE(deleted
);
1837 // Test navigating to a page that shows an interstitial, then going back.
1838 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1839 // Navigate to a page so we have a navigation entry in the controller.
1840 GURL
url1("http://www.google.com");
1841 test_rvh()->SendNavigate(1, url1
);
1842 EXPECT_EQ(1, controller().GetEntryCount());
1844 // Show interstitial.
1845 TestInterstitialPage::InterstitialState state
=
1846 TestInterstitialPage::INVALID
;
1847 bool deleted
= false;
1848 GURL
interstitial_url("http://interstitial");
1849 TestInterstitialPage
* interstitial
=
1850 new TestInterstitialPage(contents(), true, interstitial_url
,
1852 TestInterstitialPageStateGuard
state_guard(interstitial
);
1853 interstitial
->Show();
1854 interstitial
->TestDidNavigate(2, interstitial_url
);
1856 // While the interstitial is showing, go back.
1857 controller().GoBack();
1858 test_rvh()->SendNavigate(1, url1
);
1860 // Make sure we are back to the original page and that the interstitial is
1862 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1863 NavigationEntry
* entry
= controller().GetVisibleEntry();
1865 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1867 RunAllPendingInMessageLoop();
1868 EXPECT_TRUE(deleted
);
1871 // Test navigating to a page that shows an interstitial, has a renderer crash,
1872 // and then goes back.
1873 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1874 // Navigate to a page so we have a navigation entry in the controller.
1875 GURL
url1("http://www.google.com");
1876 test_rvh()->SendNavigate(1, url1
);
1877 EXPECT_EQ(1, controller().GetEntryCount());
1879 // Show interstitial.
1880 TestInterstitialPage::InterstitialState state
=
1881 TestInterstitialPage::INVALID
;
1882 bool deleted
= false;
1883 GURL
interstitial_url("http://interstitial");
1884 TestInterstitialPage
* interstitial
=
1885 new TestInterstitialPage(contents(), true, interstitial_url
,
1887 TestInterstitialPageStateGuard
state_guard(interstitial
);
1888 interstitial
->Show();
1889 interstitial
->TestDidNavigate(2, interstitial_url
);
1891 // Crash the renderer
1892 test_rvh()->OnMessageReceived(
1893 ViewHostMsg_RenderProcessGone(
1894 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1896 // While the interstitial is showing, go back.
1897 controller().GoBack();
1898 test_rvh()->SendNavigate(1, url1
);
1900 // Make sure we are back to the original page and that the interstitial is
1902 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1903 NavigationEntry
* entry
= controller().GetVisibleEntry();
1905 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1907 RunAllPendingInMessageLoop();
1908 EXPECT_TRUE(deleted
);
1911 // Test navigating to a page that shows an interstitial, has the renderer crash,
1912 // and then navigates to the interstitial.
1913 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1914 // Navigate to a page so we have a navigation entry in the controller.
1915 GURL
url1("http://www.google.com");
1916 test_rvh()->SendNavigate(1, url1
);
1917 EXPECT_EQ(1, controller().GetEntryCount());
1919 // Show interstitial.
1920 TestInterstitialPage::InterstitialState state
=
1921 TestInterstitialPage::INVALID
;
1922 bool deleted
= false;
1923 GURL
interstitial_url("http://interstitial");
1924 TestInterstitialPage
* interstitial
=
1925 new TestInterstitialPage(contents(), true, interstitial_url
,
1927 TestInterstitialPageStateGuard
state_guard(interstitial
);
1928 interstitial
->Show();
1930 // Crash the renderer
1931 test_rvh()->OnMessageReceived(
1932 ViewHostMsg_RenderProcessGone(
1933 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1935 interstitial
->TestDidNavigate(2, interstitial_url
);
1938 // Test navigating to a page that shows an interstitial, then close the
1940 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1941 // Show interstitial.
1942 TestInterstitialPage::InterstitialState state
=
1943 TestInterstitialPage::INVALID
;
1944 bool deleted
= false;
1945 GURL
url("http://interstitial");
1946 TestInterstitialPage
* interstitial
=
1947 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1948 TestInterstitialPageStateGuard
state_guard(interstitial
);
1949 interstitial
->Show();
1950 interstitial
->TestDidNavigate(1, url
);
1952 // Now close the contents.
1954 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1956 RunAllPendingInMessageLoop();
1957 EXPECT_TRUE(deleted
);
1960 // Test navigating to a page that shows an interstitial, then close the
1962 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
1963 // Show interstitial.
1964 TestInterstitialPage::InterstitialState state
=
1965 TestInterstitialPage::INVALID
;
1966 bool deleted
= false;
1967 GURL
url("http://interstitial");
1968 TestInterstitialPage
* interstitial
=
1969 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1970 TestInterstitialPageStateGuard
state_guard(interstitial
);
1971 interstitial
->Show();
1972 interstitial
->TestDidNavigate(1, url
);
1973 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
1974 interstitial
->GetRenderViewHostForTesting());
1976 // Now close the contents.
1978 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1980 // Before the interstitial has a chance to process its shutdown task,
1981 // simulate quitting the browser. This goes through all processes and
1982 // tells them to destruct.
1983 rvh
->OnMessageReceived(
1984 ViewHostMsg_RenderProcessGone(0, 0, 0));
1986 RunAllPendingInMessageLoop();
1987 EXPECT_TRUE(deleted
);
1990 // Test that after Proceed is called and an interstitial is still shown, no more
1991 // commands get executed.
1992 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
1993 // Navigate to a page so we have a navigation entry in the controller.
1994 GURL
url1("http://www.google.com");
1995 test_rvh()->SendNavigate(1, url1
);
1996 EXPECT_EQ(1, controller().GetEntryCount());
1998 // Show an interstitial.
1999 TestInterstitialPage::InterstitialState state
=
2000 TestInterstitialPage::INVALID
;
2001 bool deleted
= false;
2002 GURL
url2("http://interstitial");
2003 TestInterstitialPage
* interstitial
=
2004 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2005 TestInterstitialPageStateGuard
state_guard(interstitial
);
2006 interstitial
->Show();
2007 interstitial
->TestDidNavigate(1, url2
);
2010 EXPECT_EQ(0, interstitial
->command_received_count());
2011 interstitial
->TestDomOperationResponse("toto");
2012 EXPECT_EQ(1, interstitial
->command_received_count());
2015 interstitial
->Proceed();
2016 RunAllPendingInMessageLoop();
2017 ASSERT_FALSE(deleted
);
2019 // While the navigation to the new page is pending, send other commands, they
2020 // should be ignored.
2021 interstitial
->TestDomOperationResponse("hello");
2022 interstitial
->TestDomOperationResponse("hi");
2023 EXPECT_EQ(1, interstitial
->command_received_count());
2026 // Test showing an interstitial while another interstitial is already showing.
2027 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
2028 // Navigate to a page so we have a navigation entry in the controller.
2029 GURL
start_url("http://www.google.com");
2030 test_rvh()->SendNavigate(1, start_url
);
2031 EXPECT_EQ(1, controller().GetEntryCount());
2033 // Show an interstitial.
2034 TestInterstitialPage::InterstitialState state1
=
2035 TestInterstitialPage::INVALID
;
2036 bool deleted1
= false;
2037 GURL
url1("http://interstitial1");
2038 TestInterstitialPage
* interstitial1
=
2039 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2040 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2041 interstitial1
->Show();
2042 interstitial1
->TestDidNavigate(1, url1
);
2044 // Now show another interstitial.
2045 TestInterstitialPage::InterstitialState state2
=
2046 TestInterstitialPage::INVALID
;
2047 bool deleted2
= false;
2048 GURL
url2("http://interstitial2");
2049 TestInterstitialPage
* interstitial2
=
2050 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2051 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2052 interstitial2
->Show();
2053 interstitial2
->TestDidNavigate(1, url2
);
2055 // Showing interstitial2 should have caused interstitial1 to go away.
2056 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2057 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2059 RunAllPendingInMessageLoop();
2060 EXPECT_TRUE(deleted1
);
2061 ASSERT_FALSE(deleted2
);
2063 // Let's make sure interstitial2 is working as intended.
2064 interstitial2
->Proceed();
2065 GURL
landing_url("http://www.thepage.com");
2066 test_rvh()->SendNavigate(2, landing_url
);
2068 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2069 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2070 NavigationEntry
* entry
= controller().GetVisibleEntry();
2071 ASSERT_TRUE(entry
!= NULL
);
2072 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2073 EXPECT_EQ(2, controller().GetEntryCount());
2074 RunAllPendingInMessageLoop();
2075 EXPECT_TRUE(deleted2
);
2078 // Test showing an interstitial, proceeding and then navigating to another
2080 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2081 // Navigate to a page so we have a navigation entry in the controller.
2082 GURL
start_url("http://www.google.com");
2083 test_rvh()->SendNavigate(1, start_url
);
2084 EXPECT_EQ(1, controller().GetEntryCount());
2086 // Show an interstitial.
2087 TestInterstitialPage::InterstitialState state1
=
2088 TestInterstitialPage::INVALID
;
2089 bool deleted1
= false;
2090 GURL
url1("http://interstitial1");
2091 TestInterstitialPage
* interstitial1
=
2092 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2093 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2094 interstitial1
->Show();
2095 interstitial1
->TestDidNavigate(1, url1
);
2097 // Take action. The interstitial won't be hidden until the navigation is
2099 interstitial1
->Proceed();
2100 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2102 // Now show another interstitial (simulating the navigation causing another
2104 TestInterstitialPage::InterstitialState state2
=
2105 TestInterstitialPage::INVALID
;
2106 bool deleted2
= false;
2107 GURL
url2("http://interstitial2");
2108 TestInterstitialPage
* interstitial2
=
2109 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2110 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2111 interstitial2
->Show();
2112 interstitial2
->TestDidNavigate(1, url2
);
2114 // Showing interstitial2 should have caused interstitial1 to go away.
2115 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2116 RunAllPendingInMessageLoop();
2117 EXPECT_TRUE(deleted1
);
2118 ASSERT_FALSE(deleted2
);
2120 // Let's make sure interstitial2 is working as intended.
2121 interstitial2
->Proceed();
2122 GURL
landing_url("http://www.thepage.com");
2123 test_rvh()->SendNavigate(2, landing_url
);
2125 RunAllPendingInMessageLoop();
2126 EXPECT_TRUE(deleted2
);
2127 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2128 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2129 NavigationEntry
* entry
= controller().GetVisibleEntry();
2130 ASSERT_TRUE(entry
!= NULL
);
2131 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2132 EXPECT_EQ(2, controller().GetEntryCount());
2135 // Test that navigating away from an interstitial while it's loading cause it
2137 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2138 // Show an interstitial.
2139 TestInterstitialPage::InterstitialState state
=
2140 TestInterstitialPage::INVALID
;
2141 bool deleted
= false;
2142 GURL
interstitial_url("http://interstitial");
2143 TestInterstitialPage
* interstitial
=
2144 new TestInterstitialPage(contents(), true, interstitial_url
,
2146 TestInterstitialPageStateGuard
state_guard(interstitial
);
2147 interstitial
->Show();
2149 // Let's simulate a navigation initiated from the browser before the
2150 // interstitial finishes loading.
2151 const GURL
url("http://www.google.com");
2152 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2153 EXPECT_FALSE(interstitial
->is_showing());
2154 RunAllPendingInMessageLoop();
2155 ASSERT_FALSE(deleted
);
2157 // Now let's make the interstitial navigation commit.
2158 interstitial
->TestDidNavigate(1, interstitial_url
);
2160 // After it loaded the interstitial should be gone.
2161 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2163 RunAllPendingInMessageLoop();
2164 EXPECT_TRUE(deleted
);
2167 // Test that a new request to show an interstitial while an interstitial is
2168 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2169 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2170 GURL
interstitial_url("http://interstitial");
2172 // Show a first interstitial.
2173 TestInterstitialPage::InterstitialState state1
=
2174 TestInterstitialPage::INVALID
;
2175 bool deleted1
= false;
2176 TestInterstitialPage
* interstitial1
=
2177 new TestInterstitialPage(contents(), true, interstitial_url
,
2178 &state1
, &deleted1
);
2179 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2180 interstitial1
->Show();
2182 // Show another interstitial on that same contents before the first one had
2184 TestInterstitialPage::InterstitialState state2
=
2185 TestInterstitialPage::INVALID
;
2186 bool deleted2
= false;
2187 TestInterstitialPage
* interstitial2
=
2188 new TestInterstitialPage(contents(), true, interstitial_url
,
2189 &state2
, &deleted2
);
2190 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2191 interstitial2
->Show();
2193 // The first interstitial should have been closed and deleted.
2194 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2195 // The 2nd one should still be OK.
2196 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2198 RunAllPendingInMessageLoop();
2199 EXPECT_TRUE(deleted1
);
2200 ASSERT_FALSE(deleted2
);
2202 // Make the interstitial navigation commit it should be showing.
2203 interstitial2
->TestDidNavigate(1, interstitial_url
);
2204 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2207 // Test showing an interstitial and have its renderer crash.
2208 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2209 // Show an interstitial.
2210 TestInterstitialPage::InterstitialState state
=
2211 TestInterstitialPage::INVALID
;
2212 bool deleted
= false;
2213 GURL
url("http://interstitial");
2214 TestInterstitialPage
* interstitial
=
2215 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2216 TestInterstitialPageStateGuard
state_guard(interstitial
);
2217 interstitial
->Show();
2218 // Simulate a renderer crash before the interstitial is shown.
2219 interstitial
->TestRenderViewTerminated(
2220 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2221 // The interstitial should have been dismissed.
2222 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2223 RunAllPendingInMessageLoop();
2224 EXPECT_TRUE(deleted
);
2226 // Now try again but this time crash the intersitial after it was shown.
2228 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2229 interstitial
->Show();
2230 interstitial
->TestDidNavigate(1, url
);
2231 // Simulate a renderer crash.
2232 interstitial
->TestRenderViewTerminated(
2233 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2234 // The interstitial should have been dismissed.
2235 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2236 RunAllPendingInMessageLoop();
2237 EXPECT_TRUE(deleted
);
2240 // Tests that showing an interstitial as a result of a browser initiated
2241 // navigation while an interstitial is showing does not remove the pending
2242 // entry (see http://crbug.com/9791).
2243 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2244 const char kUrl
[] = "http://www.badguys.com/";
2245 const GURL
kGURL(kUrl
);
2247 // Start a navigation to a page
2248 contents()->GetController().LoadURL(
2249 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2251 // Simulate that navigation triggering an interstitial.
2252 TestInterstitialPage::InterstitialState state
=
2253 TestInterstitialPage::INVALID
;
2254 bool deleted
= false;
2255 TestInterstitialPage
* interstitial
=
2256 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2257 TestInterstitialPageStateGuard
state_guard(interstitial
);
2258 interstitial
->Show();
2259 interstitial
->TestDidNavigate(1, kGURL
);
2261 // Initiate a new navigation from the browser that also triggers an
2263 contents()->GetController().LoadURL(
2264 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2265 TestInterstitialPage::InterstitialState state2
=
2266 TestInterstitialPage::INVALID
;
2267 bool deleted2
= false;
2268 TestInterstitialPage
* interstitial2
=
2269 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2270 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2271 interstitial2
->Show();
2272 interstitial2
->TestDidNavigate(1, kGURL
);
2274 // Make sure we still have an entry.
2275 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2277 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2279 // And that the first interstitial is gone, but not the second.
2280 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2281 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2282 RunAllPendingInMessageLoop();
2283 EXPECT_TRUE(deleted
);
2284 EXPECT_FALSE(deleted2
);
2287 // Tests that Javascript messages are not shown while an interstitial is
2289 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2290 const char kUrl
[] = "http://www.badguys.com/";
2291 const GURL
kGURL(kUrl
);
2293 // Start a navigation to a page
2294 contents()->GetController().LoadURL(
2295 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2296 // DidNavigate from the page
2297 contents()->TestDidNavigate(rvh(), 1, kGURL
, PAGE_TRANSITION_TYPED
);
2299 // Simulate showing an interstitial while the page is showing.
2300 TestInterstitialPage::InterstitialState state
=
2301 TestInterstitialPage::INVALID
;
2302 bool deleted
= false;
2303 TestInterstitialPage
* interstitial
=
2304 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2305 TestInterstitialPageStateGuard
state_guard(interstitial
);
2306 interstitial
->Show();
2307 interstitial
->TestDidNavigate(1, kGURL
);
2309 // While the interstitial is showing, let's simulate the hidden page
2310 // attempting to show a JS message.
2311 IPC::Message
* dummy_message
= new IPC::Message
;
2312 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2313 base::ASCIIToUTF16("This is an informative message"),
2314 base::ASCIIToUTF16("OK"),
2315 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2316 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2319 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2320 // interstitial it isn't copied over to the destination.
2321 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2322 // Navigate to a page.
2323 GURL
url1("http://www.google.com");
2324 test_rvh()->SendNavigate(1, url1
);
2325 EXPECT_EQ(1, controller().GetEntryCount());
2327 // Initiate a browser navigation that will trigger the interstitial
2328 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2329 PAGE_TRANSITION_TYPED
, std::string());
2331 // Show an interstitial.
2332 TestInterstitialPage::InterstitialState state
=
2333 TestInterstitialPage::INVALID
;
2334 bool deleted
= false;
2335 GURL
url2("http://interstitial");
2336 TestInterstitialPage
* interstitial
=
2337 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2338 TestInterstitialPageStateGuard
state_guard(interstitial
);
2339 interstitial
->Show();
2340 interstitial
->TestDidNavigate(1, url2
);
2341 EXPECT_TRUE(interstitial
->is_showing());
2342 EXPECT_EQ(2, controller().GetEntryCount());
2344 // Create another NavigationController.
2345 GURL
url3("http://foo2");
2346 scoped_ptr
<TestWebContents
> other_contents(
2347 static_cast<TestWebContents
*>(CreateTestWebContents()));
2348 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2349 other_contents
->NavigateAndCommit(url3
);
2350 other_contents
->ExpectSetHistoryLengthAndPrune(
2351 NavigationEntryImpl::FromNavigationEntry(
2352 other_controller
.GetEntryAtIndex(0))->site_instance(), 1,
2353 other_controller
.GetEntryAtIndex(0)->GetPageID());
2354 other_controller
.CopyStateFromAndPrune(&controller(), false);
2356 // The merged controller should only have two entries: url1 and url2.
2357 ASSERT_EQ(2, other_controller
.GetEntryCount());
2358 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2359 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2360 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2362 // And the merged controller shouldn't be showing an interstitial.
2363 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2366 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2367 // showing an interstitial.
2368 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2369 // Navigate to a page.
2370 GURL
url1("http://www.google.com");
2371 contents()->NavigateAndCommit(url1
);
2373 // Create another NavigationController.
2374 scoped_ptr
<TestWebContents
> other_contents(
2375 static_cast<TestWebContents
*>(CreateTestWebContents()));
2376 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2378 // Navigate it to url2.
2379 GURL
url2("http://foo2");
2380 other_contents
->NavigateAndCommit(url2
);
2382 // Show an interstitial.
2383 TestInterstitialPage::InterstitialState state
=
2384 TestInterstitialPage::INVALID
;
2385 bool deleted
= false;
2386 GURL
url3("http://interstitial");
2387 TestInterstitialPage
* interstitial
=
2388 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2390 TestInterstitialPageStateGuard
state_guard(interstitial
);
2391 interstitial
->Show();
2392 interstitial
->TestDidNavigate(1, url3
);
2393 EXPECT_TRUE(interstitial
->is_showing());
2394 EXPECT_EQ(2, other_controller
.GetEntryCount());
2396 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2397 // interstitial is showing in the target.
2398 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2401 // Regression test for http://crbug.com/168611 - the URLs passed by the
2402 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2403 TEST_F(WebContentsImplTest
, FilterURLs
) {
2404 TestWebContentsObserver
observer(contents());
2406 // A navigation to about:whatever should always look like a navigation to
2408 GURL
url_normalized(url::kAboutBlankURL
);
2409 GURL
url_from_ipc("about:whatever");
2411 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2412 // will use the given URL to create the NavigationEntry as well, and that
2413 // entry should contain the filtered URL.
2414 contents()->NavigateAndCommit(url_normalized
);
2416 // Check that an IPC with about:whatever is correctly normalized.
2417 contents()->TestDidFinishLoad(url_from_ipc
);
2419 EXPECT_EQ(url_normalized
, observer
.last_url());
2421 // Create and navigate another WebContents.
2422 scoped_ptr
<TestWebContents
> other_contents(
2423 static_cast<TestWebContents
*>(CreateTestWebContents()));
2424 TestWebContentsObserver
other_observer(other_contents
.get());
2425 other_contents
->NavigateAndCommit(url_normalized
);
2427 // Check that an IPC with about:whatever is correctly normalized.
2428 other_contents
->TestDidFailLoadWithError(
2429 url_from_ipc
, 1, base::string16());
2430 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2433 // Test that if a pending contents is deleted before it is shown, we don't
2435 TEST_F(WebContentsImplTest
, PendingContents
) {
2436 scoped_ptr
<TestWebContents
> other_contents(
2437 static_cast<TestWebContents
*>(CreateTestWebContents()));
2438 contents()->AddPendingContents(other_contents
.get());
2439 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2440 other_contents
.reset();
2441 EXPECT_EQ(NULL
, contents()->GetCreatedWindow(route_id
));
2444 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2445 const gfx::Size
original_preferred_size(1024, 768);
2446 contents()->UpdatePreferredSize(original_preferred_size
);
2448 // With no capturers, expect the preferred size to be the one propagated into
2449 // WebContentsImpl via the RenderViewHostDelegate interface.
2450 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2451 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2453 // Increment capturer count, but without specifying a capture size. Expect
2454 // a "not set" preferred size.
2455 contents()->IncrementCapturerCount(gfx::Size());
2456 EXPECT_EQ(1, contents()->GetCapturerCount());
2457 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2459 // Increment capturer count again, but with an overriding capture size.
2460 // Expect preferred size to now be overridden to the capture size.
2461 const gfx::Size
capture_size(1280, 720);
2462 contents()->IncrementCapturerCount(capture_size
);
2463 EXPECT_EQ(2, contents()->GetCapturerCount());
2464 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2466 // Increment capturer count a third time, but the expect that the preferred
2467 // size is still the first capture size.
2468 const gfx::Size
another_capture_size(720, 480);
2469 contents()->IncrementCapturerCount(another_capture_size
);
2470 EXPECT_EQ(3, contents()->GetCapturerCount());
2471 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2473 // Decrement capturer count twice, but expect the preferred size to still be
2475 contents()->DecrementCapturerCount();
2476 contents()->DecrementCapturerCount();
2477 EXPECT_EQ(1, contents()->GetCapturerCount());
2478 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2480 // Decrement capturer count, and since the count has dropped to zero, the
2481 // original preferred size should be restored.
2482 contents()->DecrementCapturerCount();
2483 EXPECT_EQ(0, contents()->GetCapturerCount());
2484 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2487 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2489 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2490 // The WebContents starts with a valid creation time.
2491 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2493 // Reset the last active time to a known-bad value.
2494 contents()->last_active_time_
= base::TimeTicks();
2495 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2497 // Simulate activating the WebContents. The active time should update.
2498 contents()->WasShown();
2499 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2502 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2504 ContentsZoomChangedDelegate() :
2505 contents_zoom_changed_call_count_(0),
2506 last_zoom_in_(false) {
2509 int GetAndResetContentsZoomChangedCallCount() {
2510 int count
= contents_zoom_changed_call_count_
;
2511 contents_zoom_changed_call_count_
= 0;
2515 bool last_zoom_in() const {
2516 return last_zoom_in_
;
2519 // WebContentsDelegate:
2520 virtual void ContentsZoomChange(bool zoom_in
) OVERRIDE
{
2521 contents_zoom_changed_call_count_
++;
2522 last_zoom_in_
= zoom_in
;
2526 int contents_zoom_changed_call_count_
;
2529 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2532 // Tests that some mouseehweel events get turned into browser zoom requests.
2533 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2534 using blink::WebInputEvent
;
2536 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2537 new ContentsZoomChangedDelegate());
2538 contents()->SetDelegate(delegate
.get());
2541 // Verify that normal mouse wheel events do nothing to change the zoom level.
2542 blink::WebMouseWheelEvent event
=
2543 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2544 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2545 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2547 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
;
2548 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2549 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2550 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2552 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2553 // Except on MacOS where we never want to adjust zoom with mousewheel.
2554 modifiers
= WebInputEvent::ControlKey
;
2555 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2556 bool handled
= contents()->HandleWheelEvent(event
);
2557 #if defined(OS_MACOSX)
2558 EXPECT_FALSE(handled
);
2559 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2561 EXPECT_TRUE(handled
);
2562 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2563 EXPECT_TRUE(delegate
->last_zoom_in());
2566 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2567 WebInputEvent::AltKey
;
2568 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2569 handled
= contents()->HandleWheelEvent(event
);
2570 #if defined(OS_MACOSX)
2571 EXPECT_FALSE(handled
);
2572 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2574 EXPECT_TRUE(handled
);
2575 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2576 EXPECT_FALSE(delegate
->last_zoom_in());
2579 // Unless there is no vertical movement.
2580 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2581 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2582 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2584 // Events containing precise scrolling deltas also shouldn't result in the
2585 // zoom being adjusted, to avoid accidental adjustments caused by
2586 // two-finger-scrolling on a touchpad.
2587 modifiers
= WebInputEvent::ControlKey
;
2588 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2589 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2590 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2592 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2593 contents()->SetDelegate(NULL
);
2596 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2597 TEST_F(WebContentsImplTest
, HandleGestureEvent
) {
2598 using blink::WebGestureEvent
;
2599 using blink::WebInputEvent
;
2601 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2602 new ContentsZoomChangedDelegate());
2603 contents()->SetDelegate(delegate
.get());
2605 const float kZoomStepValue
= 0.6f
;
2606 blink::WebGestureEvent event
= SyntheticWebGestureEventBuilder::Build(
2607 WebInputEvent::GesturePinchUpdate
, blink::WebGestureDeviceTouchpad
);
2609 // A pinch less than the step value doesn't change the zoom level.
2610 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 0.8f
;
2611 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2612 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2614 // But repeating the event so the combined scale is greater does.
2615 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2616 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2617 EXPECT_TRUE(delegate
->last_zoom_in());
2619 // Pinching back out one step goes back to 100%.
2620 event
.data
.pinchUpdate
.scale
= 1.0f
- kZoomStepValue
;
2621 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2622 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2623 EXPECT_FALSE(delegate
->last_zoom_in());
2625 // Pinching out again doesn't zoom (step is twice as large around 100%).
2626 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2627 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2629 // And again now it zooms once per step.
2630 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2631 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2632 EXPECT_FALSE(delegate
->last_zoom_in());
2634 // No other type of gesture event is handled by WebContentsImpl (for example
2635 // a touchscreen pinch gesture).
2636 event
= SyntheticWebGestureEventBuilder::Build(
2637 WebInputEvent::GesturePinchUpdate
, blink::WebGestureDeviceTouchscreen
);
2638 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 3;
2639 EXPECT_FALSE(contents()->HandleGestureEvent(event
));
2640 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2642 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2643 contents()->SetDelegate(NULL
);
2646 // Tests that GetRelatedActiveContentsCount is shared between related
2647 // SiteInstances and includes WebContents that have not navigated yet.
2648 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2649 scoped_refptr
<SiteInstance
> instance1(
2650 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2651 scoped_refptr
<SiteInstance
> instance2(
2652 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2654 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2655 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2657 scoped_ptr
<TestWebContents
> contents1(
2658 TestWebContents::Create(browser_context(), instance1
));
2659 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2660 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2662 scoped_ptr
<TestWebContents
> contents2(
2663 TestWebContents::Create(browser_context(), instance1
));
2664 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2665 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2668 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2669 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2672 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2673 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2676 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2677 // same-site and cross-site navigations.
2678 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2679 scoped_refptr
<SiteInstance
> instance(
2680 SiteInstance::Create(browser_context()));
2682 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2684 scoped_ptr
<TestWebContents
> contents(
2685 TestWebContents::Create(browser_context(), instance
));
2686 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2688 // Navigate to a URL.
2689 contents
->GetController().LoadURL(
2690 GURL("http://a.com/1"), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2691 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2692 contents
->CommitPendingNavigation();
2693 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2695 // Navigate to a URL in the same site.
2696 contents
->GetController().LoadURL(
2697 GURL("http://a.com/2"), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2698 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2699 contents
->CommitPendingNavigation();
2700 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2702 // Navigate to a URL in a different site.
2703 contents
->GetController().LoadURL(
2704 GURL("http://b.com"), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2705 EXPECT_TRUE(contents
->cross_navigation_pending());
2706 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2707 contents
->CommitPendingNavigation();
2708 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2711 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2714 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2716 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2717 scoped_refptr
<SiteInstance
> instance(
2718 SiteInstance::Create(browser_context()));
2720 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2722 scoped_ptr
<TestWebContents
> contents(
2723 TestWebContents::Create(browser_context(), instance
));
2724 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2726 // Navigate to a URL.
2727 contents
->NavigateAndCommit(GURL("http://a.com"));
2728 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2730 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2731 contents
->GetController().LoadURL(
2732 GURL(kTestWebUIUrl
), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2733 EXPECT_TRUE(contents
->cross_navigation_pending());
2734 scoped_refptr
<SiteInstance
> instance_webui(
2735 contents
->GetPendingRenderViewHost()->GetSiteInstance());
2736 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2738 // At this point, contents still counts for the old BrowsingInstance.
2739 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2740 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2742 // Commit and contents counts for the new one.
2743 contents
->CommitPendingNavigation();
2744 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2745 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2748 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2749 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2752 } // namespace content