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_frame_host.h"
34 #include "content/test/test_render_view_host.h"
35 #include "content/test/test_web_contents.h"
36 #include "testing/gtest/include/gtest/gtest.h"
41 const char kTestWebUIUrl
[] = "chrome://blah";
43 class WebContentsImplTestWebUIControllerFactory
44 : public WebUIControllerFactory
{
46 virtual WebUIController
* CreateWebUIControllerForURL(
47 WebUI
* web_ui
, const GURL
& url
) const OVERRIDE
{
50 return new WebUIController(web_ui
);
53 virtual WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
54 const GURL
& url
) const OVERRIDE
{
55 return WebUI::kNoWebUI
;
58 virtual bool UseWebUIForURL(BrowserContext
* browser_context
,
59 const GURL
& url
) const OVERRIDE
{
63 virtual bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
64 const GURL
& url
) const OVERRIDE
{
69 bool UseWebUI(const GURL
& url
) const {
70 return url
== GURL(kTestWebUIUrl
);
74 class TestInterstitialPage
;
76 class TestInterstitialPageDelegate
: public InterstitialPageDelegate
{
78 explicit TestInterstitialPageDelegate(TestInterstitialPage
* interstitial_page
)
79 : interstitial_page_(interstitial_page
) {}
80 virtual void CommandReceived(const std::string
& command
) OVERRIDE
;
81 virtual std::string
GetHTMLContents() OVERRIDE
{ return std::string(); }
82 virtual void OnDontProceed() OVERRIDE
;
83 virtual void OnProceed() OVERRIDE
;
85 TestInterstitialPage
* interstitial_page_
;
88 class TestInterstitialPage
: public InterstitialPageImpl
{
90 enum InterstitialState
{
91 INVALID
= 0, // Hasn't yet been initialized.
92 UNDECIDED
, // Initialized, but no decision taken yet.
93 OKED
, // Proceed was called.
94 CANCELED
// DontProceed was called.
99 virtual void TestInterstitialPageDeleted(
100 TestInterstitialPage
* interstitial
) = 0;
103 virtual ~Delegate() {}
106 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
107 // |deleted| (like all interstitial related tests do at this point), make sure
108 // to create an instance of the TestInterstitialPageStateGuard class on the
109 // stack in your test. This will ensure that the TestInterstitialPage states
110 // are cleared when the test finishes.
111 // Not doing so will cause stack trashing if your test does not hide the
112 // interstitial, as in such a case it will be destroyed in the test TearDown
113 // method and will dereference the |deleted| local variable which by then is
115 TestInterstitialPage(WebContentsImpl
* contents
,
118 InterstitialState
* state
,
120 : InterstitialPageImpl(
122 static_cast<RenderWidgetHostDelegate
*>(contents
),
123 new_navigation
, url
, new TestInterstitialPageDelegate(this)),
126 command_received_count_(0),
132 virtual ~TestInterstitialPage() {
136 delegate_
->TestInterstitialPageDeleted(this);
139 void OnDontProceed() {
148 int command_received_count() const {
149 return command_received_count_
;
152 void TestDomOperationResponse(const std::string
& json_string
) {
157 void TestDidNavigate(int page_id
, const GURL
& url
) {
158 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
159 InitNavigateParams(¶ms
, page_id
, url
, PAGE_TRANSITION_TYPED
);
160 DidNavigate(GetRenderViewHostForTesting(), params
);
163 void TestRenderViewTerminated(base::TerminationStatus status
,
165 RenderViewTerminated(GetRenderViewHostForTesting(), status
, error_code
);
168 bool is_showing() const {
169 return static_cast<TestRenderWidgetHostView
*>(
170 GetRenderViewHostForTesting()->GetView())->is_showing();
179 void CommandReceived() {
180 command_received_count_
++;
183 void set_delegate(Delegate
* delegate
) {
184 delegate_
= delegate
;
188 virtual WebContentsView
* CreateWebContentsView() OVERRIDE
{
193 InterstitialState
* state_
;
195 int command_received_count_
;
199 void TestInterstitialPageDelegate::CommandReceived(const std::string
& command
) {
200 interstitial_page_
->CommandReceived();
203 void TestInterstitialPageDelegate::OnDontProceed() {
204 interstitial_page_
->OnDontProceed();
207 void TestInterstitialPageDelegate::OnProceed() {
208 interstitial_page_
->OnProceed();
211 class TestInterstitialPageStateGuard
: public TestInterstitialPage::Delegate
{
213 explicit TestInterstitialPageStateGuard(
214 TestInterstitialPage
* interstitial_page
)
215 : interstitial_page_(interstitial_page
) {
216 DCHECK(interstitial_page_
);
217 interstitial_page_
->set_delegate(this);
219 virtual ~TestInterstitialPageStateGuard() {
220 if (interstitial_page_
)
221 interstitial_page_
->ClearStates();
224 virtual void TestInterstitialPageDeleted(
225 TestInterstitialPage
* interstitial
) OVERRIDE
{
226 DCHECK(interstitial_page_
== interstitial
);
227 interstitial_page_
= NULL
;
231 TestInterstitialPage
* interstitial_page_
;
234 class WebContentsImplTestBrowserClient
: public TestContentBrowserClient
{
236 WebContentsImplTestBrowserClient()
237 : assign_site_for_url_(false) {}
239 virtual ~WebContentsImplTestBrowserClient() {}
241 virtual bool ShouldAssignSiteForURL(const GURL
& url
) OVERRIDE
{
242 return assign_site_for_url_
;
245 void set_assign_site_for_url(bool assign
) {
246 assign_site_for_url_
= assign
;
250 bool assign_site_for_url_
;
253 class WebContentsImplTest
: public RenderViewHostImplTestHarness
{
255 virtual void SetUp() {
256 RenderViewHostImplTestHarness::SetUp();
257 WebUIControllerFactory::RegisterFactory(&factory_
);
260 virtual void TearDown() {
261 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_
);
262 RenderViewHostImplTestHarness::TearDown();
266 WebContentsImplTestWebUIControllerFactory factory_
;
269 class TestWebContentsObserver
: public WebContentsObserver
{
271 explicit TestWebContentsObserver(WebContents
* contents
)
272 : WebContentsObserver(contents
) {
274 virtual ~TestWebContentsObserver() {}
276 virtual void DidFinishLoad(RenderFrameHost
* render_frame_host
,
277 const GURL
& validated_url
) OVERRIDE
{
278 last_url_
= validated_url
;
280 virtual void DidFailLoad(RenderFrameHost
* render_frame_host
,
281 const GURL
& validated_url
,
283 const base::string16
& error_description
) OVERRIDE
{
284 last_url_
= validated_url
;
287 const GURL
& last_url() const { return last_url_
; }
292 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver
);
295 // Pretends to be a normal browser that receives toggles and transitions to/from
296 // a fullscreened state.
297 class FakeFullscreenDelegate
: public WebContentsDelegate
{
299 FakeFullscreenDelegate() : fullscreened_contents_(NULL
) {}
300 virtual ~FakeFullscreenDelegate() {}
302 virtual void ToggleFullscreenModeForTab(WebContents
* web_contents
,
303 bool enter_fullscreen
) OVERRIDE
{
304 fullscreened_contents_
= enter_fullscreen
? web_contents
: NULL
;
307 virtual bool IsFullscreenForTabOrPending(const WebContents
* web_contents
)
309 return fullscreened_contents_
&& web_contents
== fullscreened_contents_
;
313 WebContents
* fullscreened_contents_
;
315 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate
);
318 class FakeValidationMessageDelegate
: public WebContentsDelegate
{
320 FakeValidationMessageDelegate()
321 : hide_validation_message_was_called_(false) {}
322 virtual ~FakeValidationMessageDelegate() {}
324 virtual void HideValidationMessage(WebContents
* web_contents
) OVERRIDE
{
325 hide_validation_message_was_called_
= true;
328 bool hide_validation_message_was_called() const {
329 return hide_validation_message_was_called_
;
333 bool hide_validation_message_was_called_
;
335 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate
);
340 // Test to make sure that title updates get stripped of whitespace.
341 TEST_F(WebContentsImplTest
, UpdateTitle
) {
342 NavigationControllerImpl
& cont
=
343 static_cast<NavigationControllerImpl
&>(controller());
344 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
346 ¶ms
, 0, GURL(url::kAboutBlankURL
), PAGE_TRANSITION_TYPED
);
348 LoadCommittedDetails details
;
349 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
351 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
352 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
353 base::i18n::LEFT_TO_RIGHT
);
354 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
357 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
358 const GURL
kGURL("chrome://blah");
359 controller().LoadURL(
360 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
361 EXPECT_EQ(base::string16(), contents()->GetTitle());
364 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
365 const GURL
kGURL("chrome://blah");
366 const base::string16 title
= base::ASCIIToUTF16("My Title");
367 controller().LoadURL(
368 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
370 NavigationEntry
* entry
= controller().GetVisibleEntry();
371 ASSERT_EQ(kGURL
, entry
->GetURL());
372 entry
->SetTitle(title
);
374 EXPECT_EQ(title
, contents()->GetTitle());
377 // Test view source mode for a webui page.
378 TEST_F(WebContentsImplTest
, NTPViewSource
) {
379 NavigationControllerImpl
& cont
=
380 static_cast<NavigationControllerImpl
&>(controller());
381 const char kUrl
[] = "view-source:chrome://blah";
382 const GURL
kGURL(kUrl
);
384 process()->sink().ClearMessages();
387 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
388 rvh()->GetDelegate()->RenderViewCreated(rvh());
389 // Did we get the expected message?
390 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
391 ViewMsg_EnableViewSourceMode::ID
));
393 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
394 InitNavigateParams(¶ms
, 0, kGURL
, PAGE_TRANSITION_TYPED
);
395 LoadCommittedDetails details
;
396 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
397 // Also check title and url.
398 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
401 // Test to ensure UpdateMaxPageID is working properly.
402 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
403 SiteInstance
* instance1
= contents()->GetSiteInstance();
404 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(NULL
));
407 EXPECT_EQ(-1, contents()->GetMaxPageID());
408 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
409 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
411 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
412 contents()->UpdateMaxPageID(3);
413 contents()->UpdateMaxPageID(1);
414 EXPECT_EQ(3, contents()->GetMaxPageID());
415 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
416 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
418 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
419 EXPECT_EQ(3, contents()->GetMaxPageID());
420 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
421 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
424 // Test simple same-SiteInstance navigation.
425 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
426 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
427 SiteInstance
* instance1
= contents()->GetSiteInstance();
428 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
431 const GURL
url("http://www.google.com");
432 controller().LoadURL(
433 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
434 EXPECT_FALSE(contents()->cross_navigation_pending());
435 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
436 // Controller's pending entry will have a NULL site instance until we assign
437 // it in DidNavigate.
439 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
440 site_instance() == NULL
);
442 // DidNavigate from the page
443 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
444 EXPECT_FALSE(contents()->cross_navigation_pending());
445 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
446 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
447 // Controller's entry should now have the SiteInstance, or else we won't be
448 // able to find it later.
451 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
455 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
456 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
457 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
458 const GURL
url(std::string("http://example.org/").append(
459 GetMaxURLChars() + 1, 'a'));
461 controller().LoadURL(
462 url
, Referrer(), PAGE_TRANSITION_GENERATED
, std::string());
463 EXPECT_TRUE(controller().GetVisibleEntry() == NULL
);
466 // Test that navigating across a site boundary creates a new RenderViewHost
467 // with a new SiteInstance. Going back should do the same.
468 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
469 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
470 int orig_rvh_delete_count
= 0;
471 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
472 SiteInstance
* instance1
= contents()->GetSiteInstance();
474 // Navigate to URL. First URL should use first RenderViewHost.
475 const GURL
url("http://www.google.com");
476 controller().LoadURL(
477 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
478 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
480 // Keep the number of active views in orig_rfh's SiteInstance non-zero so that
481 // orig_rfh doesn't get deleted when it gets swapped out.
482 static_cast<SiteInstanceImpl
*>(orig_rfh
->GetSiteInstance())->
483 increment_active_view_count();
485 EXPECT_FALSE(contents()->cross_navigation_pending());
486 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
487 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
488 EXPECT_EQ(url
, contents()->GetVisibleURL());
490 // Navigate to new site
491 const GURL
url2("http://www.yahoo.com");
492 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
493 EXPECT_TRUE(contents()->cross_navigation_pending());
494 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
495 EXPECT_EQ(url2
, contents()->GetVisibleURL());
496 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
497 int pending_rvh_delete_count
= 0;
498 pending_rfh
->GetRenderViewHost()->set_delete_counter(
499 &pending_rvh_delete_count
);
501 // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
502 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
503 orig_rfh
->GetRenderViewHost()->SendBeforeUnloadACK(true);
504 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
506 // DidNavigate from the pending page
507 contents()->TestDidNavigate(
508 pending_rfh
, 1, url2
, PAGE_TRANSITION_TYPED
);
509 SiteInstance
* instance2
= contents()->GetSiteInstance();
511 // Keep the number of active views in pending_rfh's SiteInstance
512 // non-zero so that orig_rfh doesn't get deleted when it gets
514 static_cast<SiteInstanceImpl
*>(pending_rfh
->GetSiteInstance())->
515 increment_active_view_count();
517 EXPECT_FALSE(contents()->cross_navigation_pending());
518 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
519 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
520 EXPECT_EQ(url2
, contents()->GetVisibleURL());
521 EXPECT_NE(instance1
, instance2
);
522 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
523 // We keep the original RFH around, swapped out.
524 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
526 EXPECT_EQ(orig_rvh_delete_count
, 0);
528 // Going back should switch SiteInstances again. The first SiteInstance is
529 // stored in the NavigationEntry, so it should be the same as at the start.
530 // We should use the same RFH as before, swapping it back in.
531 controller().GoBack();
532 TestRenderFrameHost
* goback_rfh
= contents()->GetPendingMainFrame();
533 EXPECT_EQ(orig_rfh
, goback_rfh
);
534 EXPECT_TRUE(contents()->cross_navigation_pending());
536 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
537 EXPECT_TRUE(goback_rfh
->are_navigations_suspended());
538 pending_rfh
->GetRenderViewHost()->SendBeforeUnloadACK(true);
539 EXPECT_FALSE(goback_rfh
->are_navigations_suspended());
541 // DidNavigate from the back action
542 contents()->TestDidNavigate(goback_rfh
, 1, url2
, PAGE_TRANSITION_TYPED
);
543 EXPECT_FALSE(contents()->cross_navigation_pending());
544 EXPECT_EQ(goback_rfh
, contents()->GetMainFrame());
545 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
546 // The pending RFH should now be swapped out, not deleted.
547 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
548 IsOnSwappedOutList(pending_rfh
));
549 EXPECT_EQ(pending_rvh_delete_count
, 0);
550 pending_rfh
->OnSwappedOut(false);
552 // Close contents and ensure RVHs are deleted.
554 EXPECT_EQ(orig_rvh_delete_count
, 1);
555 EXPECT_EQ(pending_rvh_delete_count
, 1);
558 // Test that navigating across a site boundary after a crash creates a new
559 // RFH without requiring a cross-site transition (i.e., PENDING state).
560 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
561 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
563 int orig_rvh_delete_count
= 0;
564 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
565 SiteInstance
* instance1
= contents()->GetSiteInstance();
567 // Navigate to URL. First URL should use first RenderViewHost.
568 const GURL
url("http://www.google.com");
569 controller().LoadURL(
570 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
571 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
573 EXPECT_FALSE(contents()->cross_navigation_pending());
574 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
576 // Crash the renderer.
577 orig_rfh
->GetRenderViewHost()->set_render_view_created(false);
579 // Navigate to new site. We should not go into PENDING.
580 const GURL
url2("http://www.yahoo.com");
581 controller().LoadURL(
582 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
583 TestRenderFrameHost
* new_rfh
= contents()->GetMainFrame();
584 EXPECT_FALSE(contents()->cross_navigation_pending());
585 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
586 EXPECT_NE(orig_rfh
, new_rfh
);
587 EXPECT_EQ(orig_rvh_delete_count
, 1);
589 // DidNavigate from the new page
590 contents()->TestDidNavigate(new_rfh
, 1, url2
, PAGE_TRANSITION_TYPED
);
591 SiteInstance
* instance2
= contents()->GetSiteInstance();
593 EXPECT_FALSE(contents()->cross_navigation_pending());
594 EXPECT_EQ(new_rfh
, main_rfh());
595 EXPECT_NE(instance1
, instance2
);
596 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
598 // Close contents and ensure RVHs are deleted.
600 EXPECT_EQ(orig_rvh_delete_count
, 1);
603 // Test that opening a new contents in the same SiteInstance and then navigating
604 // both contentses to a new site will place both contentses in a single
606 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
607 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
608 SiteInstance
* instance1
= contents()->GetSiteInstance();
610 // Navigate to URL. First URL should use first RenderViewHost.
611 const GURL
url("http://www.google.com");
612 controller().LoadURL(
613 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
614 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
616 // Open a new contents with the same SiteInstance, navigated to the same site.
617 scoped_ptr
<TestWebContents
> contents2(
618 TestWebContents::Create(browser_context(), instance1
));
619 contents2
->GetController().LoadURL(url
, Referrer(),
620 PAGE_TRANSITION_TYPED
,
622 // Need this page id to be 2 since the site instance is the same (which is the
623 // scope of page IDs) and we want to consider this a new page.
624 contents2
->TestDidNavigate(
625 contents2
->GetMainFrame(), 2, url
, PAGE_TRANSITION_TYPED
);
627 // Navigate first contents to a new site.
628 const GURL
url2a("http://www.yahoo.com");
629 controller().LoadURL(
630 url2a
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
631 orig_rfh
->GetRenderViewHost()->SendBeforeUnloadACK(true);
632 TestRenderFrameHost
* pending_rfh_a
= contents()->GetPendingMainFrame();
633 contents()->TestDidNavigate(
634 pending_rfh_a
, 1, url2a
, PAGE_TRANSITION_TYPED
);
635 SiteInstance
* instance2a
= contents()->GetSiteInstance();
636 EXPECT_NE(instance1
, instance2a
);
638 // Navigate second contents to the same site as the first tab.
639 const GURL
url2b("http://mail.yahoo.com");
640 contents2
->GetController().LoadURL(url2b
, Referrer(),
641 PAGE_TRANSITION_TYPED
,
643 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
644 rfh2
->GetRenderViewHost()->SendBeforeUnloadACK(true);
645 TestRenderFrameHost
* pending_rfh_b
= contents2
->GetPendingMainFrame();
646 EXPECT_TRUE(pending_rfh_b
!= NULL
);
647 EXPECT_TRUE(contents2
->cross_navigation_pending());
649 // NOTE(creis): We used to be in danger of showing a crash page here if the
650 // second contents hadn't navigated somewhere first (bug 1145430). That case
651 // is now covered by the CrossSiteBoundariesAfterCrash test.
652 contents2
->TestDidNavigate(pending_rfh_b
, 2, url2b
, PAGE_TRANSITION_TYPED
);
653 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
654 EXPECT_NE(instance1
, instance2b
);
656 // Both contentses should now be in the same SiteInstance.
657 EXPECT_EQ(instance2a
, instance2b
);
660 // The embedder can request sites for certain urls not be be assigned to the
661 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
662 // allowing to reuse the renderer backing certain chrome urls for subsequent
663 // navigation. The test verifies that the override is honored.
664 TEST_F(WebContentsImplTest
, NavigateFromSitelessUrl
) {
665 WebContentsImplTestBrowserClient browser_client
;
666 SetBrowserClientForTesting(&browser_client
);
668 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
669 int orig_rvh_delete_count
= 0;
670 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
671 SiteInstanceImpl
* orig_instance
=
672 static_cast<SiteInstanceImpl
*>(contents()->GetSiteInstance());
674 browser_client
.set_assign_site_for_url(false);
675 // Navigate to an URL that will not assign a new SiteInstance.
676 const GURL
native_url("non-site-url://stuffandthings");
677 controller().LoadURL(
678 native_url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
679 contents()->TestDidNavigate(orig_rfh
, 1, native_url
, PAGE_TRANSITION_TYPED
);
681 EXPECT_FALSE(contents()->cross_navigation_pending());
682 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
683 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
684 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
685 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
686 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
687 EXPECT_FALSE(orig_instance
->HasSite());
689 browser_client
.set_assign_site_for_url(true);
690 // Navigate to new site (should keep same site instance).
691 const GURL
url("http://www.google.com");
692 controller().LoadURL(
693 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
694 EXPECT_FALSE(contents()->cross_navigation_pending());
695 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
696 EXPECT_EQ(url
, contents()->GetVisibleURL());
697 EXPECT_FALSE(contents()->GetPendingMainFrame());
698 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
700 // Keep the number of active views in orig_rfh's SiteInstance
701 // non-zero so that orig_rfh doesn't get deleted when it gets
703 static_cast<SiteInstanceImpl
*>(orig_rfh
->GetSiteInstance())->
704 increment_active_view_count();
706 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
708 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
709 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
711 // Navigate to another new site (should create a new site instance).
712 const GURL
url2("http://www.yahoo.com");
713 controller().LoadURL(
714 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
715 EXPECT_TRUE(contents()->cross_navigation_pending());
716 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
717 EXPECT_EQ(url2
, contents()->GetVisibleURL());
718 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
719 int pending_rvh_delete_count
= 0;
720 pending_rfh
->GetRenderViewHost()->set_delete_counter(
721 &pending_rvh_delete_count
);
723 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
724 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
725 orig_rfh
->GetRenderViewHost()->SendBeforeUnloadACK(true);
726 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
728 // DidNavigate from the pending page.
729 contents()->TestDidNavigate(
730 pending_rfh
, 1, url2
, PAGE_TRANSITION_TYPED
);
731 SiteInstance
* new_instance
= contents()->GetSiteInstance();
733 EXPECT_FALSE(contents()->cross_navigation_pending());
734 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
735 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
736 EXPECT_EQ(url2
, contents()->GetVisibleURL());
737 EXPECT_NE(new_instance
, orig_instance
);
738 EXPECT_FALSE(contents()->GetPendingMainFrame());
739 // We keep the original RFH around, swapped out.
740 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
742 EXPECT_EQ(orig_rvh_delete_count
, 0);
743 orig_rfh
->OnSwappedOut(false);
745 // Close contents and ensure RVHs are deleted.
747 EXPECT_EQ(orig_rvh_delete_count
, 1);
748 EXPECT_EQ(pending_rvh_delete_count
, 1);
751 // Regression test for http://crbug.com/386542 - variation of
752 // NavigateFromSitelessUrl in which the original navigation is a session
754 TEST_F(WebContentsImplTest
, NavigateFromRestoredSitelessUrl
) {
755 WebContentsImplTestBrowserClient browser_client
;
756 SetBrowserClientForTesting(&browser_client
);
757 SiteInstanceImpl
* orig_instance
=
758 static_cast<SiteInstanceImpl
*>(contents()->GetSiteInstance());
759 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
761 // Restore a navigation entry for URL that should not assign site to the
763 browser_client
.set_assign_site_for_url(false);
764 const GURL
native_url("non-site-url://stuffandthings");
765 std::vector
<NavigationEntry
*> entries
;
766 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
767 native_url
, Referrer(), PAGE_TRANSITION_LINK
, false, std::string(),
770 entries
.push_back(entry
);
771 controller().Restore(
773 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
775 ASSERT_EQ(0u, entries
.size());
776 ASSERT_EQ(1, controller().GetEntryCount());
777 controller().GoToIndex(0);
778 contents()->TestDidNavigate(orig_rfh
, 0, native_url
, PAGE_TRANSITION_RELOAD
);
779 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
780 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
781 EXPECT_FALSE(orig_instance
->HasSite());
783 // Navigate to a regular site and verify that the SiteInstance was kept.
784 browser_client
.set_assign_site_for_url(true);
785 const GURL
url("http://www.google.com");
786 controller().LoadURL(
787 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
788 contents()->TestDidNavigate(orig_rfh
, 2, url
, PAGE_TRANSITION_TYPED
);
789 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
795 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
796 // tab is restored, the SiteInstance will change upon navigation.
797 TEST_F(WebContentsImplTest
, NavigateFromRestoredRegularUrl
) {
798 WebContentsImplTestBrowserClient browser_client
;
799 SetBrowserClientForTesting(&browser_client
);
800 SiteInstanceImpl
* orig_instance
=
801 static_cast<SiteInstanceImpl
*>(contents()->GetSiteInstance());
802 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
804 // Restore a navigation entry for a regular URL ensuring that the embedder
805 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
806 browser_client
.set_assign_site_for_url(true);
807 const GURL
regular_url("http://www.yahoo.com");
808 std::vector
<NavigationEntry
*> entries
;
809 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
810 regular_url
, Referrer(), PAGE_TRANSITION_LINK
, false, std::string(),
813 entries
.push_back(entry
);
814 controller().Restore(
816 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
818 ASSERT_EQ(0u, entries
.size());
819 ASSERT_EQ(1, controller().GetEntryCount());
820 controller().GoToIndex(0);
821 contents()->TestDidNavigate(orig_rfh
, 0, regular_url
, PAGE_TRANSITION_RELOAD
);
822 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
823 EXPECT_TRUE(orig_instance
->HasSite());
825 // Navigate to another site and verify that a new SiteInstance was created.
826 const GURL
url("http://www.google.com");
827 controller().LoadURL(
828 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
829 contents()->TestDidNavigate(
830 contents()->GetPendingMainFrame(), 2, url
, PAGE_TRANSITION_TYPED
);
831 EXPECT_NE(orig_instance
, contents()->GetSiteInstance());
837 // Test that we can find an opener RVH even if it's pending.
838 // http://crbug.com/176252.
839 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
840 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
842 // Navigate to a URL.
843 const GURL
url("http://www.google.com");
844 controller().LoadURL(
845 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
846 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
848 // Start to navigate first tab to a new site, so that it has a pending RVH.
849 const GURL
url2("http://www.yahoo.com");
850 controller().LoadURL(
851 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
852 orig_rfh
->GetRenderViewHost()->SendBeforeUnloadACK(true);
853 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
855 // While it is still pending, simulate opening a new tab with the first tab
856 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
857 // on the opener to ensure that an RVH exists.
858 int opener_routing_id
=
859 contents()->CreateOpenerRenderViews(pending_rfh
->GetSiteInstance());
861 // We should find the pending RVH and not create a new one.
862 EXPECT_EQ(pending_rfh
->GetRenderViewHost()->GetRoutingID(),
866 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
867 // to determine whether a navigation is cross-site.
868 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
869 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
870 SiteInstance
* instance1
= contents()->GetSiteInstance();
873 const GURL
url("http://www.google.com");
874 controller().LoadURL(
875 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
876 contents()->TestDidNavigate(
877 orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
879 // Open a related contents to a second site.
880 scoped_ptr
<TestWebContents
> contents2(
881 TestWebContents::Create(browser_context(), instance1
));
882 const GURL
url2("http://www.yahoo.com");
883 contents2
->GetController().LoadURL(url2
, Referrer(),
884 PAGE_TRANSITION_TYPED
,
886 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
888 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
889 EXPECT_FALSE(contents2
->cross_navigation_pending());
890 contents2
->TestDidNavigate(rfh2
, 2, url2
, PAGE_TRANSITION_TYPED
);
891 SiteInstance
* instance2
= contents2
->GetSiteInstance();
892 EXPECT_NE(instance1
, instance2
);
893 EXPECT_FALSE(contents2
->cross_navigation_pending());
895 // Simulate a link click in first contents to second site. Doesn't switch
896 // SiteInstances, because we don't intercept WebKit navigations.
897 contents()->TestDidNavigate(
898 orig_rfh
, 2, url2
, PAGE_TRANSITION_TYPED
);
899 SiteInstance
* instance3
= contents()->GetSiteInstance();
900 EXPECT_EQ(instance1
, instance3
);
901 EXPECT_FALSE(contents()->cross_navigation_pending());
903 // Navigate to the new site. Doesn't switch SiteInstancees, because we
904 // compare against the current URL, not the SiteInstance's site.
905 const GURL
url3("http://mail.yahoo.com");
906 controller().LoadURL(
907 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
908 EXPECT_FALSE(contents()->cross_navigation_pending());
909 contents()->TestDidNavigate(
910 orig_rfh
, 3, url3
, PAGE_TRANSITION_TYPED
);
911 SiteInstance
* instance4
= contents()->GetSiteInstance();
912 EXPECT_EQ(instance1
, instance4
);
915 // Test that the onbeforeunload and onunload handlers run when navigating
916 // across site boundaries.
917 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
918 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
919 SiteInstance
* instance1
= contents()->GetSiteInstance();
921 // Navigate to URL. First URL should use first RenderViewHost.
922 const GURL
url("http://www.google.com");
923 controller().LoadURL(
924 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
925 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
926 EXPECT_FALSE(contents()->cross_navigation_pending());
927 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
929 // Navigate to new site, but simulate an onbeforeunload denial.
930 const GURL
url2("http://www.yahoo.com");
931 controller().LoadURL(
932 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
933 EXPECT_TRUE(orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
934 base::TimeTicks now
= base::TimeTicks::Now();
935 orig_rfh
->OnMessageReceived(
936 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
938 orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
939 EXPECT_FALSE(contents()->cross_navigation_pending());
940 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
942 // Navigate again, but simulate an onbeforeunload approval.
943 controller().LoadURL(
944 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
945 EXPECT_TRUE(orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
946 now
= base::TimeTicks::Now();
947 orig_rfh
->OnMessageReceived(
948 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
950 orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
951 EXPECT_TRUE(contents()->cross_navigation_pending());
952 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
954 // We won't hear DidNavigate until the onunload handler has finished running.
956 // DidNavigate from the pending page.
957 contents()->TestDidNavigate(
958 pending_rfh
, 1, url2
, PAGE_TRANSITION_TYPED
);
959 SiteInstance
* instance2
= contents()->GetSiteInstance();
960 EXPECT_FALSE(contents()->cross_navigation_pending());
961 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
962 EXPECT_NE(instance1
, instance2
);
963 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
966 // Test that during a slow cross-site navigation, the original renderer can
967 // navigate to a different URL and have it displayed, canceling the slow
969 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
970 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
971 SiteInstance
* instance1
= contents()->GetSiteInstance();
973 // Navigate to URL. First URL should use first RenderFrameHost.
974 const GURL
url("http://www.google.com");
975 controller().LoadURL(
976 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
977 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
978 EXPECT_FALSE(contents()->cross_navigation_pending());
979 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
981 // Navigate to new site, simulating an onbeforeunload approval.
982 const GURL
url2("http://www.yahoo.com");
983 controller().LoadURL(
984 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
985 EXPECT_TRUE(orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
986 base::TimeTicks now
= base::TimeTicks::Now();
987 orig_rfh
->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
988 EXPECT_TRUE(contents()->cross_navigation_pending());
990 // Suppose the original renderer navigates before the new one is ready.
991 orig_rfh
->SendNavigate(2, GURL("http://www.google.com/foo"));
993 // Verify that the pending navigation is cancelled.
995 orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
996 SiteInstance
* instance2
= contents()->GetSiteInstance();
997 EXPECT_FALSE(contents()->cross_navigation_pending());
998 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
999 EXPECT_EQ(instance1
, instance2
);
1000 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1003 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1004 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1005 const GURL
url1("chrome://blah");
1006 controller().LoadURL(
1007 url1
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1008 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
1009 contents()->TestDidNavigate(ntp_rfh
, 1, url1
, PAGE_TRANSITION_TYPED
);
1010 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1011 SiteInstance
* instance1
= contents()->GetSiteInstance();
1013 EXPECT_FALSE(contents()->cross_navigation_pending());
1014 EXPECT_EQ(ntp_rfh
, contents()->GetMainFrame());
1015 EXPECT_EQ(url1
, entry1
->GetURL());
1016 EXPECT_EQ(instance1
,
1017 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1018 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1019 BINDINGS_POLICY_WEB_UI
);
1021 // Navigate to new site.
1022 const GURL
url2("http://www.google.com");
1023 controller().LoadURL(
1024 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1025 EXPECT_TRUE(contents()->cross_navigation_pending());
1026 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1028 // Simulate beforeunload approval.
1029 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1030 base::TimeTicks now
= base::TimeTicks::Now();
1031 ntp_rfh
->OnMessageReceived(
1032 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1034 // DidNavigate from the pending page.
1035 contents()->TestDidNavigate(
1036 google_rfh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1037 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1038 SiteInstance
* instance2
= contents()->GetSiteInstance();
1040 EXPECT_FALSE(contents()->cross_navigation_pending());
1041 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1042 EXPECT_NE(instance1
, instance2
);
1043 EXPECT_FALSE(contents()->GetPendingMainFrame());
1044 EXPECT_EQ(url2
, entry2
->GetURL());
1045 EXPECT_EQ(instance2
,
1046 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1047 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1048 BINDINGS_POLICY_WEB_UI
);
1050 // Navigate to third page on same site.
1051 const GURL
url3("http://news.google.com");
1052 controller().LoadURL(
1053 url3
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1054 EXPECT_FALSE(contents()->cross_navigation_pending());
1055 contents()->TestDidNavigate(
1056 google_rfh
, 2, url3
, PAGE_TRANSITION_TYPED
);
1057 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1058 SiteInstance
* instance3
= contents()->GetSiteInstance();
1060 EXPECT_FALSE(contents()->cross_navigation_pending());
1061 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1062 EXPECT_EQ(instance2
, instance3
);
1063 EXPECT_FALSE(contents()->GetPendingMainFrame());
1064 EXPECT_EQ(url3
, entry3
->GetURL());
1065 EXPECT_EQ(instance3
,
1066 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1068 // Go back within the site.
1069 controller().GoBack();
1070 EXPECT_FALSE(contents()->cross_navigation_pending());
1071 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1073 // Before that commits, go back again.
1074 controller().GoBack();
1075 EXPECT_TRUE(contents()->cross_navigation_pending());
1076 EXPECT_TRUE(contents()->GetPendingMainFrame());
1077 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1079 // Simulate beforeunload approval.
1081 google_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1082 now
= base::TimeTicks::Now();
1083 google_rfh
->OnMessageReceived(
1084 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1086 // DidNavigate from the first back. This aborts the second back's pending RFH.
1087 contents()->TestDidNavigate(google_rfh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1089 // We should commit this page and forget about the second back.
1090 EXPECT_FALSE(contents()->cross_navigation_pending());
1091 EXPECT_FALSE(controller().GetPendingEntry());
1092 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1093 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1095 // We should not have corrupted the NTP entry.
1096 EXPECT_EQ(instance3
,
1097 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1098 EXPECT_EQ(instance2
,
1099 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1100 EXPECT_EQ(instance1
,
1101 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1102 EXPECT_EQ(url1
, entry1
->GetURL());
1105 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1106 // original renderer will not cancel the slow navigation (bug 42029).
1107 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1108 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1110 // Navigate to URL. First URL should use the original RenderFrameHost.
1111 const GURL
url("http://www.google.com");
1112 controller().LoadURL(
1113 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1114 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
1115 EXPECT_FALSE(contents()->cross_navigation_pending());
1116 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1118 // Start navigating to new site.
1119 const GURL
url2("http://www.yahoo.com");
1120 controller().LoadURL(
1121 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1123 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1124 // waiting for a before unload response.
1125 TestRenderFrameHost
* child_rfh
= orig_rfh
->AppendChild("subframe");
1126 child_rfh
->SendNavigateWithTransition(
1127 1, GURL("http://google.com/frame"), PAGE_TRANSITION_AUTO_SUBFRAME
);
1128 EXPECT_TRUE(orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1130 // Now simulate the onbeforeunload approval and verify the navigation is
1132 base::TimeTicks now
= base::TimeTicks::Now();
1133 orig_rfh
->OnMessageReceived(
1134 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1136 orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1137 EXPECT_TRUE(contents()->cross_navigation_pending());
1140 // Test that a cross-site navigation is not preempted if the previous
1141 // renderer sends a FrameNavigate message just before being told to stop.
1142 // We should only preempt the cross-site navigation if the previous renderer
1143 // has started a new navigation. See http://crbug.com/79176.
1144 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1145 // Navigate to NTP URL.
1146 const GURL
url("chrome://blah");
1147 controller().LoadURL(
1148 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1149 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1150 EXPECT_FALSE(contents()->cross_navigation_pending());
1152 // Navigate to new site, with the beforeunload request in flight.
1153 const GURL
url2("http://www.yahoo.com");
1154 controller().LoadURL(
1155 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1156 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1157 EXPECT_TRUE(contents()->cross_navigation_pending());
1158 EXPECT_TRUE(orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1160 // Suppose the first navigation tries to commit now, with a
1161 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1162 // but it should act as if the beforeunload ack arrived.
1163 orig_rfh
->SendNavigate(1, GURL("chrome://blah"));
1164 EXPECT_TRUE(contents()->cross_navigation_pending());
1165 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1167 orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1169 // The pending navigation should be able to commit successfully.
1170 contents()->TestDidNavigate(pending_rfh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1171 EXPECT_FALSE(contents()->cross_navigation_pending());
1172 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1175 // Test that a cross-site navigation that doesn't commit after the unload
1176 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1177 TEST_F(WebContentsImplTest
, CrossSiteNavigationCanceled
) {
1178 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1179 SiteInstance
* instance1
= contents()->GetSiteInstance();
1181 // Navigate to URL. First URL should use original RenderFrameHost.
1182 const GURL
url("http://www.google.com");
1183 controller().LoadURL(
1184 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1185 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
1186 EXPECT_FALSE(contents()->cross_navigation_pending());
1187 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1189 // Navigate to new site, simulating an onbeforeunload approval.
1190 const GURL
url2("http://www.yahoo.com");
1191 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1192 EXPECT_TRUE(orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1193 base::TimeTicks now
= base::TimeTicks::Now();
1194 orig_rfh
->OnMessageReceived(
1195 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1196 EXPECT_TRUE(contents()->cross_navigation_pending());
1198 // Simulate swap out message when the response arrives.
1199 orig_rfh
->OnSwappedOut(false);
1201 // Suppose the navigation doesn't get a chance to commit, and the user
1202 // navigates in the current RFH's SiteInstance.
1203 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1205 // Verify that the pending navigation is cancelled and the renderer is no
1206 // longer swapped out.
1208 orig_rfh
->GetRenderViewHost()->is_waiting_for_beforeunload_ack());
1209 SiteInstance
* instance2
= contents()->GetSiteInstance();
1210 EXPECT_FALSE(contents()->cross_navigation_pending());
1211 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1212 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT
,
1213 orig_rfh
->GetRenderViewHost()->rvh_state());
1214 EXPECT_EQ(instance1
, instance2
);
1215 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1218 // Test that NavigationEntries have the correct page state after going
1219 // forward and back. Prevents regression for bug 1116137.
1220 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1221 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1223 // Navigate to URL. There should be no committed entry yet.
1224 const GURL
url("http://www.google.com");
1225 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1226 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1227 EXPECT_TRUE(entry
== NULL
);
1229 // Committed entry should have page state after DidNavigate.
1230 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
1231 entry
= controller().GetLastCommittedEntry();
1232 EXPECT_TRUE(entry
->GetPageState().IsValid());
1234 // Navigate to same site.
1235 const GURL
url2("http://images.google.com");
1236 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1237 entry
= controller().GetLastCommittedEntry();
1238 EXPECT_TRUE(entry
->GetPageState().IsValid());
1240 // Committed entry should have page state after DidNavigate.
1241 contents()->TestDidNavigate(orig_rfh
, 2, url2
, PAGE_TRANSITION_TYPED
);
1242 entry
= controller().GetLastCommittedEntry();
1243 EXPECT_TRUE(entry
->GetPageState().IsValid());
1245 // Now go back. Committed entry should still have page state.
1246 controller().GoBack();
1247 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
1248 entry
= controller().GetLastCommittedEntry();
1249 EXPECT_TRUE(entry
->GetPageState().IsValid());
1252 // Test that NavigationEntries have the correct page state and SiteInstance
1253 // state after opening a new window to about:blank. Prevents regression for
1254 // bugs b/1116137 and http://crbug.com/111975.
1255 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1256 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1258 // When opening a new window, it is navigated to about:blank internally.
1259 // Currently, this results in two DidNavigate events.
1260 const GURL
url(url::kAboutBlankURL
);
1261 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
1262 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
1264 // Should have a page state here.
1265 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1266 EXPECT_TRUE(entry
->GetPageState().IsValid());
1268 // The SiteInstance should be available for other navigations to use.
1269 NavigationEntryImpl
* entry_impl
=
1270 NavigationEntryImpl::FromNavigationEntry(entry
);
1271 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1272 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1274 // Navigating to a normal page should not cause a process swap.
1275 const GURL
new_url("http://www.google.com");
1276 controller().LoadURL(new_url
, Referrer(),
1277 PAGE_TRANSITION_TYPED
, std::string());
1278 EXPECT_FALSE(contents()->cross_navigation_pending());
1279 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1280 contents()->TestDidNavigate(orig_rfh
, 1, new_url
, PAGE_TRANSITION_TYPED
);
1281 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1282 controller().GetLastCommittedEntry());
1283 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1284 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1287 // Tests that fullscreen is exited throughout the object hierarchy when
1288 // navigating to a new page.
1289 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1290 FakeFullscreenDelegate fake_delegate
;
1291 contents()->SetDelegate(&fake_delegate
);
1292 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1293 TestRenderViewHost
* orig_rvh
= orig_rfh
->GetRenderViewHost();
1295 // Navigate to a site.
1296 const GURL
url("http://www.google.com");
1297 controller().LoadURL(
1298 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1299 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
1300 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1302 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1303 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1304 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1305 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1306 orig_rvh
->OnMessageReceived(
1307 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1308 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1309 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1310 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1312 // Navigate to a new site.
1313 const GURL
url2("http://www.yahoo.com");
1314 controller().LoadURL(
1315 url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1316 TestRenderFrameHost
* const pending_rfh
= contents()->GetPendingMainFrame();
1317 contents()->TestDidNavigate(
1318 pending_rfh
, 1, url2
, PAGE_TRANSITION_TYPED
);
1320 // Confirm fullscreen has exited.
1321 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1322 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1323 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1325 contents()->SetDelegate(NULL
);
1328 // Tests that fullscreen is exited throughout the object hierarchy when
1329 // instructing NavigationController to GoBack() or GoForward().
1330 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1331 FakeFullscreenDelegate fake_delegate
;
1332 contents()->SetDelegate(&fake_delegate
);
1333 TestRenderFrameHost
* const orig_rfh
= contents()->GetMainFrame();
1334 TestRenderViewHost
* const orig_rvh
= orig_rfh
->GetRenderViewHost();
1336 // Navigate to a site.
1337 const GURL
url("http://www.google.com");
1338 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1339 contents()->TestDidNavigate(orig_rfh
, 1, url
, PAGE_TRANSITION_TYPED
);
1340 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1342 // Now, navigate to another page on the same site.
1343 const GURL
url2("http://www.google.com/search?q=kittens");
1344 controller().LoadURL(url2
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1345 EXPECT_FALSE(contents()->cross_navigation_pending());
1346 contents()->TestDidNavigate(orig_rfh
, 2, url2
, PAGE_TRANSITION_TYPED
);
1347 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1349 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1350 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1351 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1352 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1354 for (int i
= 0; i
< 2; ++i
) {
1355 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1356 orig_rvh
->OnMessageReceived(
1357 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1358 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1359 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1360 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1362 // Navigate backward (or forward).
1364 controller().GoBack();
1366 controller().GoForward();
1367 EXPECT_FALSE(contents()->cross_navigation_pending());
1368 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1369 contents()->TestDidNavigate(
1370 orig_rfh
, i
+ 1, url
, PAGE_TRANSITION_FORWARD_BACK
);
1372 // Confirm fullscreen has exited.
1373 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1374 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1375 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1378 contents()->SetDelegate(NULL
);
1381 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1382 FakeValidationMessageDelegate fake_delegate
;
1383 contents()->SetDelegate(&fake_delegate
);
1384 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1386 // Crash the renderer.
1387 contents()->GetMainFrame()->GetRenderViewHost()->OnMessageReceived(
1388 ViewHostMsg_RenderProcessGone(
1389 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1391 // Confirm HideValidationMessage was called.
1392 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1394 contents()->SetDelegate(NULL
);
1397 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1399 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1400 FakeFullscreenDelegate fake_delegate
;
1401 contents()->SetDelegate(&fake_delegate
);
1403 // Navigate to a site.
1404 const GURL
url("http://www.google.com");
1405 controller().LoadURL(
1406 url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
1407 contents()->TestDidNavigate(
1408 contents()->GetMainFrame(), 1, url
, PAGE_TRANSITION_TYPED
);
1410 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1411 EXPECT_FALSE(test_rvh()->IsFullscreen());
1412 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1413 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1414 test_rvh()->OnMessageReceived(
1415 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1416 EXPECT_TRUE(test_rvh()->IsFullscreen());
1417 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1418 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1420 // Crash the renderer.
1421 test_rvh()->OnMessageReceived(
1422 ViewHostMsg_RenderProcessGone(
1423 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1425 // Confirm fullscreen has exited.
1426 EXPECT_FALSE(test_rvh()->IsFullscreen());
1427 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1428 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1430 contents()->SetDelegate(NULL
);
1433 ////////////////////////////////////////////////////////////////////////////////
1434 // Interstitial Tests
1435 ////////////////////////////////////////////////////////////////////////////////
1437 // Test navigating to a page (with the navigation initiated from the browser,
1438 // as when a URL is typed in the location bar) that shows an interstitial and
1439 // creates a new navigation entry, then hiding it without proceeding.
1440 TEST_F(WebContentsImplTest
,
1441 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1442 // Navigate to a page.
1443 GURL
url1("http://www.google.com");
1444 contents()->GetMainFrame()->SendNavigate(1, url1
);
1445 EXPECT_EQ(1, controller().GetEntryCount());
1447 // Initiate a browser navigation that will trigger the interstitial
1448 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1449 PAGE_TRANSITION_TYPED
, std::string());
1451 // Show an interstitial.
1452 TestInterstitialPage::InterstitialState state
=
1453 TestInterstitialPage::INVALID
;
1454 bool deleted
= false;
1455 GURL
url2("http://interstitial");
1456 TestInterstitialPage
* interstitial
=
1457 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1458 TestInterstitialPageStateGuard
state_guard(interstitial
);
1459 interstitial
->Show();
1460 // The interstitial should not show until its navigation has committed.
1461 EXPECT_FALSE(interstitial
->is_showing());
1462 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1463 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1464 // Let's commit the interstitial navigation.
1465 interstitial
->TestDidNavigate(1, url2
);
1466 EXPECT_TRUE(interstitial
->is_showing());
1467 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1468 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1469 NavigationEntry
* entry
= controller().GetVisibleEntry();
1470 ASSERT_TRUE(entry
!= NULL
);
1471 EXPECT_TRUE(entry
->GetURL() == url2
);
1473 // Now don't proceed.
1474 interstitial
->DontProceed();
1475 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1476 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1477 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1478 entry
= controller().GetVisibleEntry();
1479 ASSERT_TRUE(entry
!= NULL
);
1480 EXPECT_TRUE(entry
->GetURL() == url1
);
1481 EXPECT_EQ(1, controller().GetEntryCount());
1483 RunAllPendingInMessageLoop();
1484 EXPECT_TRUE(deleted
);
1487 // Test navigating to a page (with the navigation initiated from the renderer,
1488 // as when clicking on a link in the page) that shows an interstitial and
1489 // creates a new navigation entry, then hiding it without proceeding.
1490 TEST_F(WebContentsImplTest
,
1491 ShowInterstitiaFromRendererlWithNewNavigationDontProceed
) {
1492 // Navigate to a page.
1493 GURL
url1("http://www.google.com");
1494 contents()->GetMainFrame()->SendNavigate(1, url1
);
1495 EXPECT_EQ(1, controller().GetEntryCount());
1497 // Show an interstitial (no pending entry, the interstitial would have been
1498 // triggered by clicking on a link).
1499 TestInterstitialPage::InterstitialState state
=
1500 TestInterstitialPage::INVALID
;
1501 bool deleted
= false;
1502 GURL
url2("http://interstitial");
1503 TestInterstitialPage
* interstitial
=
1504 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1505 TestInterstitialPageStateGuard
state_guard(interstitial
);
1506 interstitial
->Show();
1507 // The interstitial should not show until its navigation has committed.
1508 EXPECT_FALSE(interstitial
->is_showing());
1509 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1510 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1511 // Let's commit the interstitial navigation.
1512 interstitial
->TestDidNavigate(1, url2
);
1513 EXPECT_TRUE(interstitial
->is_showing());
1514 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1515 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1516 NavigationEntry
* entry
= controller().GetVisibleEntry();
1517 ASSERT_TRUE(entry
!= NULL
);
1518 EXPECT_TRUE(entry
->GetURL() == url2
);
1520 // Now don't proceed.
1521 interstitial
->DontProceed();
1522 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1523 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1524 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1525 entry
= controller().GetVisibleEntry();
1526 ASSERT_TRUE(entry
!= NULL
);
1527 EXPECT_TRUE(entry
->GetURL() == url1
);
1528 EXPECT_EQ(1, controller().GetEntryCount());
1530 RunAllPendingInMessageLoop();
1531 EXPECT_TRUE(deleted
);
1534 // Test navigating to a page that shows an interstitial without creating a new
1535 // navigation entry (this happens when the interstitial is triggered by a
1536 // sub-resource in the page), then hiding it without proceeding.
1537 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1538 // Navigate to a page.
1539 GURL
url1("http://www.google.com");
1540 contents()->GetMainFrame()->SendNavigate(1, url1
);
1541 EXPECT_EQ(1, controller().GetEntryCount());
1543 // Show an interstitial.
1544 TestInterstitialPage::InterstitialState state
=
1545 TestInterstitialPage::INVALID
;
1546 bool deleted
= false;
1547 GURL
url2("http://interstitial");
1548 TestInterstitialPage
* interstitial
=
1549 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1550 TestInterstitialPageStateGuard
state_guard(interstitial
);
1551 interstitial
->Show();
1552 // The interstitial should not show until its navigation has committed.
1553 EXPECT_FALSE(interstitial
->is_showing());
1554 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1555 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1556 // Let's commit the interstitial navigation.
1557 interstitial
->TestDidNavigate(1, url2
);
1558 EXPECT_TRUE(interstitial
->is_showing());
1559 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1560 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1561 NavigationEntry
* entry
= controller().GetVisibleEntry();
1562 ASSERT_TRUE(entry
!= NULL
);
1563 // The URL specified to the interstitial should have been ignored.
1564 EXPECT_TRUE(entry
->GetURL() == url1
);
1566 // Now don't proceed.
1567 interstitial
->DontProceed();
1568 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1569 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1570 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1571 entry
= controller().GetVisibleEntry();
1572 ASSERT_TRUE(entry
!= NULL
);
1573 EXPECT_TRUE(entry
->GetURL() == url1
);
1574 EXPECT_EQ(1, controller().GetEntryCount());
1576 RunAllPendingInMessageLoop();
1577 EXPECT_TRUE(deleted
);
1580 // Test navigating to a page (with the navigation initiated from the browser,
1581 // as when a URL is typed in the location bar) that shows an interstitial and
1582 // creates a new navigation entry, then proceeding.
1583 TEST_F(WebContentsImplTest
,
1584 ShowInterstitialFromBrowserNewNavigationProceed
) {
1585 // Navigate to a page.
1586 GURL
url1("http://www.google.com");
1587 contents()->GetMainFrame()->SendNavigate(1, url1
);
1588 EXPECT_EQ(1, controller().GetEntryCount());
1590 // Initiate a browser navigation that will trigger the interstitial
1591 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1592 PAGE_TRANSITION_TYPED
, std::string());
1594 // Show an interstitial.
1595 TestInterstitialPage::InterstitialState state
=
1596 TestInterstitialPage::INVALID
;
1597 bool deleted
= false;
1598 GURL
url2("http://interstitial");
1599 TestInterstitialPage
* interstitial
=
1600 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1601 TestInterstitialPageStateGuard
state_guard(interstitial
);
1602 interstitial
->Show();
1603 // The interstitial should not show until its navigation has committed.
1604 EXPECT_FALSE(interstitial
->is_showing());
1605 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1606 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1607 // Let's commit the interstitial navigation.
1608 interstitial
->TestDidNavigate(1, url2
);
1609 EXPECT_TRUE(interstitial
->is_showing());
1610 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1611 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1612 NavigationEntry
* entry
= controller().GetVisibleEntry();
1613 ASSERT_TRUE(entry
!= NULL
);
1614 EXPECT_TRUE(entry
->GetURL() == url2
);
1617 interstitial
->Proceed();
1618 // The interstitial should show until the new navigation commits.
1619 RunAllPendingInMessageLoop();
1620 ASSERT_FALSE(deleted
);
1621 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1622 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1623 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1625 // Simulate the navigation to the page, that's when the interstitial gets
1627 GURL
url3("http://www.thepage.com");
1628 contents()->GetMainFrame()->SendNavigate(2, url3
);
1630 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1631 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1632 entry
= controller().GetVisibleEntry();
1633 ASSERT_TRUE(entry
!= NULL
);
1634 EXPECT_TRUE(entry
->GetURL() == url3
);
1636 EXPECT_EQ(2, controller().GetEntryCount());
1638 RunAllPendingInMessageLoop();
1639 EXPECT_TRUE(deleted
);
1642 // Test navigating to a page (with the navigation initiated from the renderer,
1643 // as when clicking on a link in the page) that shows an interstitial and
1644 // creates a new navigation entry, then proceeding.
1645 TEST_F(WebContentsImplTest
,
1646 ShowInterstitialFromRendererNewNavigationProceed
) {
1647 // Navigate to a page.
1648 GURL
url1("http://www.google.com");
1649 contents()->GetMainFrame()->SendNavigate(1, url1
);
1650 EXPECT_EQ(1, controller().GetEntryCount());
1652 // Show an interstitial.
1653 TestInterstitialPage::InterstitialState state
=
1654 TestInterstitialPage::INVALID
;
1655 bool deleted
= false;
1656 GURL
url2("http://interstitial");
1657 TestInterstitialPage
* interstitial
=
1658 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1659 TestInterstitialPageStateGuard
state_guard(interstitial
);
1660 interstitial
->Show();
1661 // The interstitial should not show until its navigation has committed.
1662 EXPECT_FALSE(interstitial
->is_showing());
1663 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1664 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1665 // Let's commit the interstitial navigation.
1666 interstitial
->TestDidNavigate(1, url2
);
1667 EXPECT_TRUE(interstitial
->is_showing());
1668 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1669 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1670 NavigationEntry
* entry
= controller().GetVisibleEntry();
1671 ASSERT_TRUE(entry
!= NULL
);
1672 EXPECT_TRUE(entry
->GetURL() == url2
);
1675 interstitial
->Proceed();
1676 // The interstitial should show until the new navigation commits.
1677 RunAllPendingInMessageLoop();
1678 ASSERT_FALSE(deleted
);
1679 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1680 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1681 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1683 // Simulate the navigation to the page, that's when the interstitial gets
1685 GURL
url3("http://www.thepage.com");
1686 contents()->GetMainFrame()->SendNavigate(2, url3
);
1688 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1689 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1690 entry
= controller().GetVisibleEntry();
1691 ASSERT_TRUE(entry
!= NULL
);
1692 EXPECT_TRUE(entry
->GetURL() == url3
);
1694 EXPECT_EQ(2, controller().GetEntryCount());
1696 RunAllPendingInMessageLoop();
1697 EXPECT_TRUE(deleted
);
1700 // Test navigating to a page that shows an interstitial without creating a new
1701 // navigation entry (this happens when the interstitial is triggered by a
1702 // sub-resource in the page), then proceeding.
1703 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1704 // Navigate to a page so we have a navigation entry in the controller.
1705 GURL
url1("http://www.google.com");
1706 contents()->GetMainFrame()->SendNavigate(1, url1
);
1707 EXPECT_EQ(1, controller().GetEntryCount());
1709 // Show an interstitial.
1710 TestInterstitialPage::InterstitialState state
=
1711 TestInterstitialPage::INVALID
;
1712 bool deleted
= false;
1713 GURL
url2("http://interstitial");
1714 TestInterstitialPage
* interstitial
=
1715 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1716 TestInterstitialPageStateGuard
state_guard(interstitial
);
1717 interstitial
->Show();
1718 // The interstitial should not show until its navigation has committed.
1719 EXPECT_FALSE(interstitial
->is_showing());
1720 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1721 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1722 // Let's commit the interstitial navigation.
1723 interstitial
->TestDidNavigate(1, url2
);
1724 EXPECT_TRUE(interstitial
->is_showing());
1725 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1726 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1727 NavigationEntry
* entry
= controller().GetVisibleEntry();
1728 ASSERT_TRUE(entry
!= NULL
);
1729 // The URL specified to the interstitial should have been ignored.
1730 EXPECT_TRUE(entry
->GetURL() == url1
);
1733 interstitial
->Proceed();
1734 // Since this is not a new navigation, the previous page is dismissed right
1735 // away and shows the original page.
1736 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1737 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1738 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1739 entry
= controller().GetVisibleEntry();
1740 ASSERT_TRUE(entry
!= NULL
);
1741 EXPECT_TRUE(entry
->GetURL() == url1
);
1743 EXPECT_EQ(1, controller().GetEntryCount());
1745 RunAllPendingInMessageLoop();
1746 EXPECT_TRUE(deleted
);
1749 // Test navigating to a page that shows an interstitial, then navigating away.
1750 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1751 // Show interstitial.
1752 TestInterstitialPage::InterstitialState state
=
1753 TestInterstitialPage::INVALID
;
1754 bool deleted
= false;
1755 GURL
url("http://interstitial");
1756 TestInterstitialPage
* interstitial
=
1757 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1758 TestInterstitialPageStateGuard
state_guard(interstitial
);
1759 interstitial
->Show();
1760 interstitial
->TestDidNavigate(1, url
);
1762 // While interstitial showing, navigate to a new URL.
1763 const GURL
url2("http://www.yahoo.com");
1764 contents()->GetMainFrame()->SendNavigate(1, url2
);
1766 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1768 RunAllPendingInMessageLoop();
1769 EXPECT_TRUE(deleted
);
1772 // Test navigating to a page that shows an interstitial, then going back.
1773 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1774 // Navigate to a page so we have a navigation entry in the controller.
1775 GURL
url1("http://www.google.com");
1776 contents()->GetMainFrame()->SendNavigate(1, url1
);
1777 EXPECT_EQ(1, controller().GetEntryCount());
1779 // Show interstitial.
1780 TestInterstitialPage::InterstitialState state
=
1781 TestInterstitialPage::INVALID
;
1782 bool deleted
= false;
1783 GURL
interstitial_url("http://interstitial");
1784 TestInterstitialPage
* interstitial
=
1785 new TestInterstitialPage(contents(), true, interstitial_url
,
1787 TestInterstitialPageStateGuard
state_guard(interstitial
);
1788 interstitial
->Show();
1789 interstitial
->TestDidNavigate(2, interstitial_url
);
1791 // While the interstitial is showing, go back.
1792 controller().GoBack();
1793 contents()->GetMainFrame()->SendNavigate(1, url1
);
1795 // Make sure we are back to the original page and that the interstitial is
1797 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1798 NavigationEntry
* entry
= controller().GetVisibleEntry();
1800 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1802 RunAllPendingInMessageLoop();
1803 EXPECT_TRUE(deleted
);
1806 // Test navigating to a page that shows an interstitial, has a renderer crash,
1807 // and then goes back.
1808 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1809 // Navigate to a page so we have a navigation entry in the controller.
1810 GURL
url1("http://www.google.com");
1811 contents()->GetMainFrame()->SendNavigate(1, url1
);
1812 EXPECT_EQ(1, controller().GetEntryCount());
1814 // Show interstitial.
1815 TestInterstitialPage::InterstitialState state
=
1816 TestInterstitialPage::INVALID
;
1817 bool deleted
= false;
1818 GURL
interstitial_url("http://interstitial");
1819 TestInterstitialPage
* interstitial
=
1820 new TestInterstitialPage(contents(), true, interstitial_url
,
1822 TestInterstitialPageStateGuard
state_guard(interstitial
);
1823 interstitial
->Show();
1824 interstitial
->TestDidNavigate(2, interstitial_url
);
1826 // Crash the renderer
1827 test_rvh()->OnMessageReceived(
1828 ViewHostMsg_RenderProcessGone(
1829 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1831 // While the interstitial is showing, go back.
1832 controller().GoBack();
1833 contents()->GetMainFrame()->SendNavigate(1, url1
);
1835 // Make sure we are back to the original page and that the interstitial is
1837 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1838 NavigationEntry
* entry
= controller().GetVisibleEntry();
1840 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1842 RunAllPendingInMessageLoop();
1843 EXPECT_TRUE(deleted
);
1846 // Test navigating to a page that shows an interstitial, has the renderer crash,
1847 // and then navigates to the interstitial.
1848 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1849 // Navigate to a page so we have a navigation entry in the controller.
1850 GURL
url1("http://www.google.com");
1851 contents()->GetMainFrame()->SendNavigate(1, url1
);
1852 EXPECT_EQ(1, controller().GetEntryCount());
1854 // Show interstitial.
1855 TestInterstitialPage::InterstitialState state
=
1856 TestInterstitialPage::INVALID
;
1857 bool deleted
= false;
1858 GURL
interstitial_url("http://interstitial");
1859 TestInterstitialPage
* interstitial
=
1860 new TestInterstitialPage(contents(), true, interstitial_url
,
1862 TestInterstitialPageStateGuard
state_guard(interstitial
);
1863 interstitial
->Show();
1865 // Crash the renderer
1866 test_rvh()->OnMessageReceived(
1867 ViewHostMsg_RenderProcessGone(
1868 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1870 interstitial
->TestDidNavigate(2, interstitial_url
);
1873 // Test navigating to a page that shows an interstitial, then close the
1875 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1876 // Show interstitial.
1877 TestInterstitialPage::InterstitialState state
=
1878 TestInterstitialPage::INVALID
;
1879 bool deleted
= false;
1880 GURL
url("http://interstitial");
1881 TestInterstitialPage
* interstitial
=
1882 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1883 TestInterstitialPageStateGuard
state_guard(interstitial
);
1884 interstitial
->Show();
1885 interstitial
->TestDidNavigate(1, url
);
1887 // Now close the contents.
1889 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1891 RunAllPendingInMessageLoop();
1892 EXPECT_TRUE(deleted
);
1895 // Test navigating to a page that shows an interstitial, then close the
1897 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
1898 // Show interstitial.
1899 TestInterstitialPage::InterstitialState state
=
1900 TestInterstitialPage::INVALID
;
1901 bool deleted
= false;
1902 GURL
url("http://interstitial");
1903 TestInterstitialPage
* interstitial
=
1904 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1905 TestInterstitialPageStateGuard
state_guard(interstitial
);
1906 interstitial
->Show();
1907 interstitial
->TestDidNavigate(1, url
);
1908 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
1909 interstitial
->GetRenderViewHostForTesting());
1911 // Now close the contents.
1913 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1915 // Before the interstitial has a chance to process its shutdown task,
1916 // simulate quitting the browser. This goes through all processes and
1917 // tells them to destruct.
1918 rvh
->OnMessageReceived(
1919 ViewHostMsg_RenderProcessGone(0, 0, 0));
1921 RunAllPendingInMessageLoop();
1922 EXPECT_TRUE(deleted
);
1925 // Test that after Proceed is called and an interstitial is still shown, no more
1926 // commands get executed.
1927 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
1928 // Navigate to a page so we have a navigation entry in the controller.
1929 GURL
url1("http://www.google.com");
1930 contents()->GetMainFrame()->SendNavigate(1, url1
);
1931 EXPECT_EQ(1, controller().GetEntryCount());
1933 // Show an interstitial.
1934 TestInterstitialPage::InterstitialState state
=
1935 TestInterstitialPage::INVALID
;
1936 bool deleted
= false;
1937 GURL
url2("http://interstitial");
1938 TestInterstitialPage
* interstitial
=
1939 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1940 TestInterstitialPageStateGuard
state_guard(interstitial
);
1941 interstitial
->Show();
1942 interstitial
->TestDidNavigate(1, url2
);
1945 EXPECT_EQ(0, interstitial
->command_received_count());
1946 interstitial
->TestDomOperationResponse("toto");
1947 EXPECT_EQ(1, interstitial
->command_received_count());
1950 interstitial
->Proceed();
1951 RunAllPendingInMessageLoop();
1952 ASSERT_FALSE(deleted
);
1954 // While the navigation to the new page is pending, send other commands, they
1955 // should be ignored.
1956 interstitial
->TestDomOperationResponse("hello");
1957 interstitial
->TestDomOperationResponse("hi");
1958 EXPECT_EQ(1, interstitial
->command_received_count());
1961 // Test showing an interstitial while another interstitial is already showing.
1962 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
1963 // Navigate to a page so we have a navigation entry in the controller.
1964 GURL
start_url("http://www.google.com");
1965 contents()->GetMainFrame()->SendNavigate(1, start_url
);
1966 EXPECT_EQ(1, controller().GetEntryCount());
1968 // Show an interstitial.
1969 TestInterstitialPage::InterstitialState state1
=
1970 TestInterstitialPage::INVALID
;
1971 bool deleted1
= false;
1972 GURL
url1("http://interstitial1");
1973 TestInterstitialPage
* interstitial1
=
1974 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
1975 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
1976 interstitial1
->Show();
1977 interstitial1
->TestDidNavigate(1, url1
);
1979 // Now show another interstitial.
1980 TestInterstitialPage::InterstitialState state2
=
1981 TestInterstitialPage::INVALID
;
1982 bool deleted2
= false;
1983 GURL
url2("http://interstitial2");
1984 TestInterstitialPage
* interstitial2
=
1985 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
1986 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
1987 interstitial2
->Show();
1988 interstitial2
->TestDidNavigate(1, url2
);
1990 // Showing interstitial2 should have caused interstitial1 to go away.
1991 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
1992 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
1994 RunAllPendingInMessageLoop();
1995 EXPECT_TRUE(deleted1
);
1996 ASSERT_FALSE(deleted2
);
1998 // Let's make sure interstitial2 is working as intended.
1999 interstitial2
->Proceed();
2000 GURL
landing_url("http://www.thepage.com");
2001 contents()->GetMainFrame()->SendNavigate(2, landing_url
);
2003 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2004 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2005 NavigationEntry
* entry
= controller().GetVisibleEntry();
2006 ASSERT_TRUE(entry
!= NULL
);
2007 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2008 EXPECT_EQ(2, controller().GetEntryCount());
2009 RunAllPendingInMessageLoop();
2010 EXPECT_TRUE(deleted2
);
2013 // Test showing an interstitial, proceeding and then navigating to another
2015 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2016 // Navigate to a page so we have a navigation entry in the controller.
2017 GURL
start_url("http://www.google.com");
2018 contents()->GetMainFrame()->SendNavigate(1, start_url
);
2019 EXPECT_EQ(1, controller().GetEntryCount());
2021 // Show an interstitial.
2022 TestInterstitialPage::InterstitialState state1
=
2023 TestInterstitialPage::INVALID
;
2024 bool deleted1
= false;
2025 GURL
url1("http://interstitial1");
2026 TestInterstitialPage
* interstitial1
=
2027 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2028 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2029 interstitial1
->Show();
2030 interstitial1
->TestDidNavigate(1, url1
);
2032 // Take action. The interstitial won't be hidden until the navigation is
2034 interstitial1
->Proceed();
2035 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2037 // Now show another interstitial (simulating the navigation causing another
2039 TestInterstitialPage::InterstitialState state2
=
2040 TestInterstitialPage::INVALID
;
2041 bool deleted2
= false;
2042 GURL
url2("http://interstitial2");
2043 TestInterstitialPage
* interstitial2
=
2044 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2045 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2046 interstitial2
->Show();
2047 interstitial2
->TestDidNavigate(1, url2
);
2049 // Showing interstitial2 should have caused interstitial1 to go away.
2050 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2051 RunAllPendingInMessageLoop();
2052 EXPECT_TRUE(deleted1
);
2053 ASSERT_FALSE(deleted2
);
2055 // Let's make sure interstitial2 is working as intended.
2056 interstitial2
->Proceed();
2057 GURL
landing_url("http://www.thepage.com");
2058 contents()->GetMainFrame()->SendNavigate(2, landing_url
);
2060 RunAllPendingInMessageLoop();
2061 EXPECT_TRUE(deleted2
);
2062 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2063 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2064 NavigationEntry
* entry
= controller().GetVisibleEntry();
2065 ASSERT_TRUE(entry
!= NULL
);
2066 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2067 EXPECT_EQ(2, controller().GetEntryCount());
2070 // Test that navigating away from an interstitial while it's loading cause it
2072 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2073 // Show an interstitial.
2074 TestInterstitialPage::InterstitialState state
=
2075 TestInterstitialPage::INVALID
;
2076 bool deleted
= false;
2077 GURL
interstitial_url("http://interstitial");
2078 TestInterstitialPage
* interstitial
=
2079 new TestInterstitialPage(contents(), true, interstitial_url
,
2081 TestInterstitialPageStateGuard
state_guard(interstitial
);
2082 interstitial
->Show();
2084 // Let's simulate a navigation initiated from the browser before the
2085 // interstitial finishes loading.
2086 const GURL
url("http://www.google.com");
2087 controller().LoadURL(url
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2088 EXPECT_FALSE(interstitial
->is_showing());
2089 RunAllPendingInMessageLoop();
2090 ASSERT_FALSE(deleted
);
2092 // Now let's make the interstitial navigation commit.
2093 interstitial
->TestDidNavigate(1, interstitial_url
);
2095 // After it loaded the interstitial should be gone.
2096 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2098 RunAllPendingInMessageLoop();
2099 EXPECT_TRUE(deleted
);
2102 // Test that a new request to show an interstitial while an interstitial is
2103 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2104 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2105 GURL
interstitial_url("http://interstitial");
2107 // Show a first interstitial.
2108 TestInterstitialPage::InterstitialState state1
=
2109 TestInterstitialPage::INVALID
;
2110 bool deleted1
= false;
2111 TestInterstitialPage
* interstitial1
=
2112 new TestInterstitialPage(contents(), true, interstitial_url
,
2113 &state1
, &deleted1
);
2114 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2115 interstitial1
->Show();
2117 // Show another interstitial on that same contents before the first one had
2119 TestInterstitialPage::InterstitialState state2
=
2120 TestInterstitialPage::INVALID
;
2121 bool deleted2
= false;
2122 TestInterstitialPage
* interstitial2
=
2123 new TestInterstitialPage(contents(), true, interstitial_url
,
2124 &state2
, &deleted2
);
2125 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2126 interstitial2
->Show();
2128 // The first interstitial should have been closed and deleted.
2129 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2130 // The 2nd one should still be OK.
2131 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2133 RunAllPendingInMessageLoop();
2134 EXPECT_TRUE(deleted1
);
2135 ASSERT_FALSE(deleted2
);
2137 // Make the interstitial navigation commit it should be showing.
2138 interstitial2
->TestDidNavigate(1, interstitial_url
);
2139 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2142 // Test showing an interstitial and have its renderer crash.
2143 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2144 // Show an interstitial.
2145 TestInterstitialPage::InterstitialState state
=
2146 TestInterstitialPage::INVALID
;
2147 bool deleted
= false;
2148 GURL
url("http://interstitial");
2149 TestInterstitialPage
* interstitial
=
2150 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2151 TestInterstitialPageStateGuard
state_guard(interstitial
);
2152 interstitial
->Show();
2153 // Simulate a renderer crash before the interstitial is shown.
2154 interstitial
->TestRenderViewTerminated(
2155 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2156 // The interstitial should have been dismissed.
2157 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2158 RunAllPendingInMessageLoop();
2159 EXPECT_TRUE(deleted
);
2161 // Now try again but this time crash the intersitial after it was shown.
2163 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2164 interstitial
->Show();
2165 interstitial
->TestDidNavigate(1, url
);
2166 // Simulate a renderer crash.
2167 interstitial
->TestRenderViewTerminated(
2168 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2169 // The interstitial should have been dismissed.
2170 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2171 RunAllPendingInMessageLoop();
2172 EXPECT_TRUE(deleted
);
2175 // Tests that showing an interstitial as a result of a browser initiated
2176 // navigation while an interstitial is showing does not remove the pending
2177 // entry (see http://crbug.com/9791).
2178 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2179 const char kUrl
[] = "http://www.badguys.com/";
2180 const GURL
kGURL(kUrl
);
2182 // Start a navigation to a page
2183 contents()->GetController().LoadURL(
2184 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2186 // Simulate that navigation triggering an interstitial.
2187 TestInterstitialPage::InterstitialState state
=
2188 TestInterstitialPage::INVALID
;
2189 bool deleted
= false;
2190 TestInterstitialPage
* interstitial
=
2191 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2192 TestInterstitialPageStateGuard
state_guard(interstitial
);
2193 interstitial
->Show();
2194 interstitial
->TestDidNavigate(1, kGURL
);
2196 // Initiate a new navigation from the browser that also triggers an
2198 contents()->GetController().LoadURL(
2199 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2200 TestInterstitialPage::InterstitialState state2
=
2201 TestInterstitialPage::INVALID
;
2202 bool deleted2
= false;
2203 TestInterstitialPage
* interstitial2
=
2204 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2205 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2206 interstitial2
->Show();
2207 interstitial2
->TestDidNavigate(1, kGURL
);
2209 // Make sure we still have an entry.
2210 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2212 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2214 // And that the first interstitial is gone, but not the second.
2215 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2216 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2217 RunAllPendingInMessageLoop();
2218 EXPECT_TRUE(deleted
);
2219 EXPECT_FALSE(deleted2
);
2222 // Tests that Javascript messages are not shown while an interstitial is
2224 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2225 const char kUrl
[] = "http://www.badguys.com/";
2226 const GURL
kGURL(kUrl
);
2228 // Start a navigation to a page
2229 contents()->GetController().LoadURL(
2230 kGURL
, Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2231 // DidNavigate from the page
2232 contents()->TestDidNavigate(
2233 contents()->GetMainFrame(), 1, kGURL
, PAGE_TRANSITION_TYPED
);
2235 // Simulate showing an interstitial while the page is showing.
2236 TestInterstitialPage::InterstitialState state
=
2237 TestInterstitialPage::INVALID
;
2238 bool deleted
= false;
2239 TestInterstitialPage
* interstitial
=
2240 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2241 TestInterstitialPageStateGuard
state_guard(interstitial
);
2242 interstitial
->Show();
2243 interstitial
->TestDidNavigate(1, kGURL
);
2245 // While the interstitial is showing, let's simulate the hidden page
2246 // attempting to show a JS message.
2247 IPC::Message
* dummy_message
= new IPC::Message
;
2248 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2249 base::ASCIIToUTF16("This is an informative message"),
2250 base::ASCIIToUTF16("OK"),
2251 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2252 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2255 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2256 // interstitial it isn't copied over to the destination.
2257 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2258 // Navigate to a page.
2259 GURL
url1("http://www.google.com");
2260 contents()->GetMainFrame()->SendNavigate(1, url1
);
2261 EXPECT_EQ(1, controller().GetEntryCount());
2263 // Initiate a browser navigation that will trigger the interstitial
2264 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2265 PAGE_TRANSITION_TYPED
, std::string());
2267 // Show an interstitial.
2268 TestInterstitialPage::InterstitialState state
=
2269 TestInterstitialPage::INVALID
;
2270 bool deleted
= false;
2271 GURL
url2("http://interstitial");
2272 TestInterstitialPage
* interstitial
=
2273 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2274 TestInterstitialPageStateGuard
state_guard(interstitial
);
2275 interstitial
->Show();
2276 interstitial
->TestDidNavigate(1, url2
);
2277 EXPECT_TRUE(interstitial
->is_showing());
2278 EXPECT_EQ(2, controller().GetEntryCount());
2280 // Create another NavigationController.
2281 GURL
url3("http://foo2");
2282 scoped_ptr
<TestWebContents
> other_contents(
2283 static_cast<TestWebContents
*>(CreateTestWebContents()));
2284 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2285 other_contents
->NavigateAndCommit(url3
);
2286 other_contents
->ExpectSetHistoryLengthAndPrune(
2287 NavigationEntryImpl::FromNavigationEntry(
2288 other_controller
.GetEntryAtIndex(0))->site_instance(), 1,
2289 other_controller
.GetEntryAtIndex(0)->GetPageID());
2290 other_controller
.CopyStateFromAndPrune(&controller(), false);
2292 // The merged controller should only have two entries: url1 and url2.
2293 ASSERT_EQ(2, other_controller
.GetEntryCount());
2294 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2295 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2296 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2298 // And the merged controller shouldn't be showing an interstitial.
2299 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2302 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2303 // showing an interstitial.
2304 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2305 // Navigate to a page.
2306 GURL
url1("http://www.google.com");
2307 contents()->NavigateAndCommit(url1
);
2309 // Create another NavigationController.
2310 scoped_ptr
<TestWebContents
> other_contents(
2311 static_cast<TestWebContents
*>(CreateTestWebContents()));
2312 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2314 // Navigate it to url2.
2315 GURL
url2("http://foo2");
2316 other_contents
->NavigateAndCommit(url2
);
2318 // Show an interstitial.
2319 TestInterstitialPage::InterstitialState state
=
2320 TestInterstitialPage::INVALID
;
2321 bool deleted
= false;
2322 GURL
url3("http://interstitial");
2323 TestInterstitialPage
* interstitial
=
2324 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2326 TestInterstitialPageStateGuard
state_guard(interstitial
);
2327 interstitial
->Show();
2328 interstitial
->TestDidNavigate(1, url3
);
2329 EXPECT_TRUE(interstitial
->is_showing());
2330 EXPECT_EQ(2, other_controller
.GetEntryCount());
2332 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2333 // interstitial is showing in the target.
2334 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2337 // Regression test for http://crbug.com/168611 - the URLs passed by the
2338 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2339 TEST_F(WebContentsImplTest
, FilterURLs
) {
2340 TestWebContentsObserver
observer(contents());
2342 // A navigation to about:whatever should always look like a navigation to
2344 GURL
url_normalized(url::kAboutBlankURL
);
2345 GURL
url_from_ipc("about:whatever");
2347 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2348 // will use the given URL to create the NavigationEntry as well, and that
2349 // entry should contain the filtered URL.
2350 contents()->NavigateAndCommit(url_normalized
);
2352 // Check that an IPC with about:whatever is correctly normalized.
2353 contents()->TestDidFinishLoad(url_from_ipc
);
2355 EXPECT_EQ(url_normalized
, observer
.last_url());
2357 // Create and navigate another WebContents.
2358 scoped_ptr
<TestWebContents
> other_contents(
2359 static_cast<TestWebContents
*>(CreateTestWebContents()));
2360 TestWebContentsObserver
other_observer(other_contents
.get());
2361 other_contents
->NavigateAndCommit(url_normalized
);
2363 // Check that an IPC with about:whatever is correctly normalized.
2364 other_contents
->TestDidFailLoadWithError(
2365 url_from_ipc
, 1, base::string16());
2366 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2369 // Test that if a pending contents is deleted before it is shown, we don't
2371 TEST_F(WebContentsImplTest
, PendingContents
) {
2372 scoped_ptr
<TestWebContents
> other_contents(
2373 static_cast<TestWebContents
*>(CreateTestWebContents()));
2374 contents()->AddPendingContents(other_contents
.get());
2375 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2376 other_contents
.reset();
2377 EXPECT_EQ(NULL
, contents()->GetCreatedWindow(route_id
));
2380 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2381 const gfx::Size
original_preferred_size(1024, 768);
2382 contents()->UpdatePreferredSize(original_preferred_size
);
2384 // With no capturers, expect the preferred size to be the one propagated into
2385 // WebContentsImpl via the RenderViewHostDelegate interface.
2386 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2387 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2389 // Increment capturer count, but without specifying a capture size. Expect
2390 // a "not set" preferred size.
2391 contents()->IncrementCapturerCount(gfx::Size());
2392 EXPECT_EQ(1, contents()->GetCapturerCount());
2393 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2395 // Increment capturer count again, but with an overriding capture size.
2396 // Expect preferred size to now be overridden to the capture size.
2397 const gfx::Size
capture_size(1280, 720);
2398 contents()->IncrementCapturerCount(capture_size
);
2399 EXPECT_EQ(2, contents()->GetCapturerCount());
2400 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2402 // Increment capturer count a third time, but the expect that the preferred
2403 // size is still the first capture size.
2404 const gfx::Size
another_capture_size(720, 480);
2405 contents()->IncrementCapturerCount(another_capture_size
);
2406 EXPECT_EQ(3, contents()->GetCapturerCount());
2407 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2409 // Decrement capturer count twice, but expect the preferred size to still be
2411 contents()->DecrementCapturerCount();
2412 contents()->DecrementCapturerCount();
2413 EXPECT_EQ(1, contents()->GetCapturerCount());
2414 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2416 // Decrement capturer count, and since the count has dropped to zero, the
2417 // original preferred size should be restored.
2418 contents()->DecrementCapturerCount();
2419 EXPECT_EQ(0, contents()->GetCapturerCount());
2420 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2423 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2425 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2426 // The WebContents starts with a valid creation time.
2427 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2429 // Reset the last active time to a known-bad value.
2430 contents()->last_active_time_
= base::TimeTicks();
2431 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2433 // Simulate activating the WebContents. The active time should update.
2434 contents()->WasShown();
2435 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2438 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2440 ContentsZoomChangedDelegate() :
2441 contents_zoom_changed_call_count_(0),
2442 last_zoom_in_(false) {
2445 int GetAndResetContentsZoomChangedCallCount() {
2446 int count
= contents_zoom_changed_call_count_
;
2447 contents_zoom_changed_call_count_
= 0;
2451 bool last_zoom_in() const {
2452 return last_zoom_in_
;
2455 // WebContentsDelegate:
2456 virtual void ContentsZoomChange(bool zoom_in
) OVERRIDE
{
2457 contents_zoom_changed_call_count_
++;
2458 last_zoom_in_
= zoom_in
;
2462 int contents_zoom_changed_call_count_
;
2465 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2468 // Tests that some mouseehweel events get turned into browser zoom requests.
2469 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2470 using blink::WebInputEvent
;
2472 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2473 new ContentsZoomChangedDelegate());
2474 contents()->SetDelegate(delegate
.get());
2477 // Verify that normal mouse wheel events do nothing to change the zoom level.
2478 blink::WebMouseWheelEvent event
=
2479 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2480 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2481 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2483 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
;
2484 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2485 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2486 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2488 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2489 // Except on MacOS where we never want to adjust zoom with mousewheel.
2490 modifiers
= WebInputEvent::ControlKey
;
2491 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2492 bool handled
= contents()->HandleWheelEvent(event
);
2493 #if defined(OS_MACOSX)
2494 EXPECT_FALSE(handled
);
2495 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2497 EXPECT_TRUE(handled
);
2498 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2499 EXPECT_TRUE(delegate
->last_zoom_in());
2502 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2503 WebInputEvent::AltKey
;
2504 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2505 handled
= contents()->HandleWheelEvent(event
);
2506 #if defined(OS_MACOSX)
2507 EXPECT_FALSE(handled
);
2508 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2510 EXPECT_TRUE(handled
);
2511 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2512 EXPECT_FALSE(delegate
->last_zoom_in());
2515 // Unless there is no vertical movement.
2516 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2517 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2518 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2520 // Events containing precise scrolling deltas also shouldn't result in the
2521 // zoom being adjusted, to avoid accidental adjustments caused by
2522 // two-finger-scrolling on a touchpad.
2523 modifiers
= WebInputEvent::ControlKey
;
2524 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2525 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2526 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2528 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2529 contents()->SetDelegate(NULL
);
2532 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2533 TEST_F(WebContentsImplTest
, HandleGestureEvent
) {
2534 using blink::WebGestureEvent
;
2535 using blink::WebInputEvent
;
2537 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2538 new ContentsZoomChangedDelegate());
2539 contents()->SetDelegate(delegate
.get());
2541 const float kZoomStepValue
= 0.6f
;
2542 blink::WebGestureEvent event
= SyntheticWebGestureEventBuilder::Build(
2543 WebInputEvent::GesturePinchUpdate
, blink::WebGestureDeviceTouchpad
);
2545 // A pinch less than the step value doesn't change the zoom level.
2546 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 0.8f
;
2547 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2548 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2550 // But repeating the event so the combined scale is greater does.
2551 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2552 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2553 EXPECT_TRUE(delegate
->last_zoom_in());
2555 // Pinching back out one step goes back to 100%.
2556 event
.data
.pinchUpdate
.scale
= 1.0f
- kZoomStepValue
;
2557 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2558 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2559 EXPECT_FALSE(delegate
->last_zoom_in());
2561 // Pinching out again doesn't zoom (step is twice as large around 100%).
2562 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2563 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2565 // And again now it zooms once per step.
2566 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2567 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2568 EXPECT_FALSE(delegate
->last_zoom_in());
2570 // No other type of gesture event is handled by WebContentsImpl (for example
2571 // a touchscreen pinch gesture).
2572 event
= SyntheticWebGestureEventBuilder::Build(
2573 WebInputEvent::GesturePinchUpdate
, blink::WebGestureDeviceTouchscreen
);
2574 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 3;
2575 EXPECT_FALSE(contents()->HandleGestureEvent(event
));
2576 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2578 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2579 contents()->SetDelegate(NULL
);
2582 // Tests that GetRelatedActiveContentsCount is shared between related
2583 // SiteInstances and includes WebContents that have not navigated yet.
2584 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2585 scoped_refptr
<SiteInstance
> instance1(
2586 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2587 scoped_refptr
<SiteInstance
> instance2(
2588 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2590 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2591 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2593 scoped_ptr
<TestWebContents
> contents1(
2594 TestWebContents::Create(browser_context(), instance1
.get()));
2595 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2596 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2598 scoped_ptr
<TestWebContents
> contents2(
2599 TestWebContents::Create(browser_context(), instance1
.get()));
2600 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2601 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2604 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2605 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2608 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2609 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2612 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2613 // same-site and cross-site navigations.
2614 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2615 scoped_refptr
<SiteInstance
> instance(
2616 SiteInstance::Create(browser_context()));
2618 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2620 scoped_ptr
<TestWebContents
> contents(
2621 TestWebContents::Create(browser_context(), instance
.get()));
2622 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2624 // Navigate to a URL.
2625 contents
->GetController().LoadURL(
2626 GURL("http://a.com/1"), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2627 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2628 contents
->CommitPendingNavigation();
2629 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2631 // Navigate to a URL in the same site.
2632 contents
->GetController().LoadURL(
2633 GURL("http://a.com/2"), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2634 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2635 contents
->CommitPendingNavigation();
2636 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2638 // Navigate to a URL in a different site.
2639 contents
->GetController().LoadURL(
2640 GURL("http://b.com"), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2641 EXPECT_TRUE(contents
->cross_navigation_pending());
2642 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2643 contents
->CommitPendingNavigation();
2644 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2647 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2650 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2652 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2653 scoped_refptr
<SiteInstance
> instance(
2654 SiteInstance::Create(browser_context()));
2656 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2658 scoped_ptr
<TestWebContents
> contents(
2659 TestWebContents::Create(browser_context(), instance
.get()));
2660 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2662 // Navigate to a URL.
2663 contents
->NavigateAndCommit(GURL("http://a.com"));
2664 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2666 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2667 contents
->GetController().LoadURL(
2668 GURL(kTestWebUIUrl
), Referrer(), PAGE_TRANSITION_TYPED
, std::string());
2669 EXPECT_TRUE(contents
->cross_navigation_pending());
2670 scoped_refptr
<SiteInstance
> instance_webui(
2671 contents
->GetPendingMainFrame()->GetSiteInstance());
2672 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2674 // At this point, contents still counts for the old BrowsingInstance.
2675 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2676 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2678 // Commit and contents counts for the new one.
2679 contents
->CommitPendingNavigation();
2680 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2681 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2684 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2685 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2688 } // namespace content