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/media/audio_stream_monitor.h"
11 #include "content/browser/renderer_host/render_view_host_impl.h"
12 #include "content/browser/site_instance_impl.h"
13 #include "content/browser/webui/web_ui_controller_factory_registry.h"
14 #include "content/common/frame_messages.h"
15 #include "content/common/input/synthetic_web_input_event_builders.h"
16 #include "content/common/view_messages.h"
17 #include "content/public/browser/global_request_id.h"
18 #include "content/public/browser/interstitial_page_delegate.h"
19 #include "content/public/browser/navigation_details.h"
20 #include "content/public/browser/notification_details.h"
21 #include "content/public/browser/notification_source.h"
22 #include "content/public/browser/render_widget_host_view.h"
23 #include "content/public/browser/web_contents_delegate.h"
24 #include "content/public/browser/web_contents_observer.h"
25 #include "content/public/browser/web_ui_controller.h"
26 #include "content/public/common/bindings_policy.h"
27 #include "content/public/common/content_constants.h"
28 #include "content/public/common/url_constants.h"
29 #include "content/public/common/url_utils.h"
30 #include "content/public/test/mock_render_process_host.h"
31 #include "content/public/test/test_utils.h"
32 #include "content/test/test_content_browser_client.h"
33 #include "content/test/test_content_client.h"
34 #include "content/test/test_render_frame_host.h"
35 #include "content/test/test_render_view_host.h"
36 #include "content/test/test_web_contents.h"
37 #include "testing/gtest/include/gtest/gtest.h"
42 const char kTestWebUIUrl
[] = "chrome://blah";
44 class WebContentsImplTestWebUIControllerFactory
45 : public WebUIControllerFactory
{
47 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
48 const GURL
& url
) const override
{
51 return new WebUIController(web_ui
);
54 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
55 const GURL
& url
) const override
{
56 return WebUI::kNoWebUI
;
59 bool UseWebUIForURL(BrowserContext
* browser_context
,
60 const GURL
& url
) const override
{
64 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
65 const GURL
& url
) const override
{
70 bool UseWebUI(const GURL
& url
) const {
71 return url
== GURL(kTestWebUIUrl
);
75 class TestInterstitialPage
;
77 class TestInterstitialPageDelegate
: public InterstitialPageDelegate
{
79 explicit TestInterstitialPageDelegate(TestInterstitialPage
* interstitial_page
)
80 : interstitial_page_(interstitial_page
) {}
81 void CommandReceived(const std::string
& command
) override
;
82 std::string
GetHTMLContents() override
{ return std::string(); }
83 void OnDontProceed() override
;
84 void OnProceed() override
;
87 TestInterstitialPage
* interstitial_page_
;
90 class TestInterstitialPage
: public InterstitialPageImpl
{
92 enum InterstitialState
{
93 INVALID
= 0, // Hasn't yet been initialized.
94 UNDECIDED
, // Initialized, but no decision taken yet.
95 OKED
, // Proceed was called.
96 CANCELED
// DontProceed was called.
101 virtual void TestInterstitialPageDeleted(
102 TestInterstitialPage
* interstitial
) = 0;
105 virtual ~Delegate() {}
108 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
109 // |deleted| (like all interstitial related tests do at this point), make sure
110 // to create an instance of the TestInterstitialPageStateGuard class on the
111 // stack in your test. This will ensure that the TestInterstitialPage states
112 // are cleared when the test finishes.
113 // Not doing so will cause stack trashing if your test does not hide the
114 // interstitial, as in such a case it will be destroyed in the test TearDown
115 // method and will dereference the |deleted| local variable which by then is
117 TestInterstitialPage(WebContentsImpl
* contents
,
120 InterstitialState
* state
,
122 : InterstitialPageImpl(
124 static_cast<RenderWidgetHostDelegate
*>(contents
),
125 new_navigation
, url
, new TestInterstitialPageDelegate(this)),
128 command_received_count_(0),
134 ~TestInterstitialPage() override
{
138 delegate_
->TestInterstitialPageDeleted(this);
141 void OnDontProceed() {
150 int command_received_count() const {
151 return command_received_count_
;
154 void TestDomOperationResponse(const std::string
& json_string
) {
159 void TestDidNavigate(int page_id
, const GURL
& url
) {
160 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
161 InitNavigateParams(¶ms
, page_id
, url
, ui::PAGE_TRANSITION_TYPED
);
162 DidNavigate(GetRenderViewHostForTesting(), params
);
165 void TestRenderViewTerminated(base::TerminationStatus status
,
167 RenderViewTerminated(GetRenderViewHostForTesting(), status
, error_code
);
170 bool is_showing() const {
171 return static_cast<TestRenderWidgetHostView
*>(
172 GetRenderViewHostForTesting()->GetView())->is_showing();
181 void CommandReceived() {
182 command_received_count_
++;
185 void set_delegate(Delegate
* delegate
) {
186 delegate_
= delegate
;
190 WebContentsView
* CreateWebContentsView() override
{ return NULL
; }
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 ~TestInterstitialPageStateGuard() override
{
220 if (interstitial_page_
)
221 interstitial_page_
->ClearStates();
224 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 ~WebContentsImplTestBrowserClient() override
{}
241 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 void SetUp() override
{
256 RenderViewHostImplTestHarness::SetUp();
257 WebUIControllerFactory::RegisterFactory(&factory_
);
260 void TearDown() override
{
261 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_
);
262 RenderViewHostImplTestHarness::TearDown();
266 WebContentsImplTestWebUIControllerFactory factory_
;
269 class TestWebContentsObserver
: public WebContentsObserver
{
271 explicit TestWebContentsObserver(WebContents
* contents
)
272 : WebContentsObserver(contents
) {
274 ~TestWebContentsObserver() override
{}
276 void DidFinishLoad(RenderFrameHost
* render_frame_host
,
277 const GURL
& validated_url
) override
{
278 last_url_
= validated_url
;
280 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 ~FakeFullscreenDelegate() override
{}
302 void ToggleFullscreenModeForTab(WebContents
* web_contents
,
303 bool enter_fullscreen
) override
{
304 fullscreened_contents_
= enter_fullscreen
? web_contents
: NULL
;
307 bool IsFullscreenForTabOrPending(
308 const WebContents
* web_contents
) const override
{
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 ~FakeValidationMessageDelegate() override
{}
324 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
), ui::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(), ui::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(), ui::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(), ui::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
, ui::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(), ui::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
, ui::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(), ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
478 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
480 // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
481 // that orig_rfh doesn't get deleted when it gets swapped out.
482 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
484 EXPECT_FALSE(contents()->cross_navigation_pending());
485 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
486 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
487 EXPECT_EQ(url
, contents()->GetVisibleURL());
489 // Navigate to new site
490 const GURL
url2("http://www.yahoo.com");
491 controller().LoadURL(
492 url2
, Referrer(), ui::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
->SendBeforeUnloadACK(true);
504 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
506 // DidNavigate from the pending page
507 contents()->TestDidNavigate(
508 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
509 SiteInstance
* instance2
= contents()->GetSiteInstance();
511 // Keep the number of active frames in pending_rfh's SiteInstance
512 // non-zero so that orig_rfh doesn't get deleted when it gets
514 pending_rfh
->GetSiteInstance()->increment_active_frame_count();
516 EXPECT_FALSE(contents()->cross_navigation_pending());
517 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
518 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
519 EXPECT_EQ(url2
, contents()->GetVisibleURL());
520 EXPECT_NE(instance1
, instance2
);
521 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
522 // We keep the original RFH around, swapped out.
523 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
525 EXPECT_EQ(orig_rvh_delete_count
, 0);
527 // Going back should switch SiteInstances again. The first SiteInstance is
528 // stored in the NavigationEntry, so it should be the same as at the start.
529 // We should use the same RFH as before, swapping it back in.
530 controller().GoBack();
531 TestRenderFrameHost
* goback_rfh
= contents()->GetPendingMainFrame();
532 EXPECT_EQ(orig_rfh
, goback_rfh
);
533 EXPECT_TRUE(contents()->cross_navigation_pending());
535 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
536 EXPECT_TRUE(goback_rfh
->are_navigations_suspended());
537 pending_rfh
->SendBeforeUnloadACK(true);
538 EXPECT_FALSE(goback_rfh
->are_navigations_suspended());
540 // DidNavigate from the back action
541 contents()->TestDidNavigate(goback_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
542 EXPECT_FALSE(contents()->cross_navigation_pending());
543 EXPECT_EQ(goback_rfh
, contents()->GetMainFrame());
544 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
545 // The pending RFH should now be swapped out, not deleted.
546 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
547 IsOnSwappedOutList(pending_rfh
));
548 EXPECT_EQ(pending_rvh_delete_count
, 0);
549 pending_rfh
->OnSwappedOut();
551 // Close contents and ensure RVHs are deleted.
553 EXPECT_EQ(orig_rvh_delete_count
, 1);
554 EXPECT_EQ(pending_rvh_delete_count
, 1);
557 // Test that navigating across a site boundary after a crash creates a new
558 // RFH without requiring a cross-site transition (i.e., PENDING state).
559 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
560 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
562 int orig_rvh_delete_count
= 0;
563 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
564 SiteInstance
* instance1
= contents()->GetSiteInstance();
566 // Navigate to URL. First URL should use first RenderViewHost.
567 const GURL
url("http://www.google.com");
568 controller().LoadURL(
569 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
570 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
572 EXPECT_FALSE(contents()->cross_navigation_pending());
573 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
575 // Simulate a renderer crash.
576 orig_rfh
->GetRenderViewHost()->set_render_view_created(false);
577 orig_rfh
->set_render_frame_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(), ui::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
, ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
614 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::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 ui::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
, ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
631 orig_rfh
->SendBeforeUnloadACK(true);
632 TestRenderFrameHost
* pending_rfh_a
= contents()->GetPendingMainFrame();
633 contents()->TestDidNavigate(
634 pending_rfh_a
, 1, url2a
, ui::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 ui::PAGE_TRANSITION_TYPED
,
643 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
644 rfh2
->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(
653 pending_rfh_b
, 2, url2b
, ui::PAGE_TRANSITION_TYPED
);
654 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
655 EXPECT_NE(instance1
, instance2b
);
657 // Both contentses should now be in the same SiteInstance.
658 EXPECT_EQ(instance2a
, instance2b
);
661 // The embedder can request sites for certain urls not be be assigned to the
662 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
663 // allowing to reuse the renderer backing certain chrome urls for subsequent
664 // navigation. The test verifies that the override is honored.
665 TEST_F(WebContentsImplTest
, NavigateFromSitelessUrl
) {
666 WebContentsImplTestBrowserClient browser_client
;
667 SetBrowserClientForTesting(&browser_client
);
669 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
670 int orig_rvh_delete_count
= 0;
671 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
672 SiteInstanceImpl
* orig_instance
= 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(), ui::PAGE_TRANSITION_TYPED
, std::string());
679 contents()->TestDidNavigate(
680 orig_rfh
, 1, native_url
, ui::PAGE_TRANSITION_TYPED
);
682 EXPECT_FALSE(contents()->cross_navigation_pending());
683 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
684 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
685 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
686 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
687 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
688 EXPECT_FALSE(orig_instance
->HasSite());
690 browser_client
.set_assign_site_for_url(true);
691 // Navigate to new site (should keep same site instance).
692 const GURL
url("http://www.google.com");
693 controller().LoadURL(
694 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
695 EXPECT_FALSE(contents()->cross_navigation_pending());
696 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
697 EXPECT_EQ(url
, contents()->GetVisibleURL());
698 EXPECT_FALSE(contents()->GetPendingMainFrame());
699 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
701 // Keep the number of active frames in orig_rfh's SiteInstance
702 // non-zero so that orig_rfh doesn't get deleted when it gets
704 orig_rfh
->GetSiteInstance()->increment_active_frame_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(), ui::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
->SendBeforeUnloadACK(true);
726 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
728 // DidNavigate from the pending page.
729 contents()->TestDidNavigate(
730 pending_rfh
, 1, url2
, ui::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();
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
= contents()->GetSiteInstance();
758 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
760 // Restore a navigation entry for URL that should not assign site to the
762 browser_client
.set_assign_site_for_url(false);
763 const GURL
native_url("non-site-url://stuffandthings");
764 std::vector
<NavigationEntry
*> entries
;
765 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
766 native_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false, std::string(),
769 entries
.push_back(entry
);
770 controller().Restore(
772 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
774 ASSERT_EQ(0u, entries
.size());
775 ASSERT_EQ(1, controller().GetEntryCount());
776 controller().GoToIndex(0);
777 contents()->TestDidNavigate(
778 orig_rfh
, 0, native_url
, ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
788 contents()->TestDidNavigate(orig_rfh
, 2, url
, ui::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
= contents()->GetSiteInstance();
801 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
803 // Restore a navigation entry for a regular URL ensuring that the embedder
804 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
805 browser_client
.set_assign_site_for_url(true);
806 const GURL
regular_url("http://www.yahoo.com");
807 std::vector
<NavigationEntry
*> entries
;
808 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
809 regular_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false, std::string(),
812 entries
.push_back(entry
);
813 controller().Restore(
815 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
817 ASSERT_EQ(0u, entries
.size());
818 ASSERT_EQ(1, controller().GetEntryCount());
819 controller().GoToIndex(0);
820 contents()->TestDidNavigate(
821 orig_rfh
, 0, regular_url
, ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
829 contents()->TestDidNavigate(
830 contents()->GetPendingMainFrame(), 2, url
, ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
846 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
852 orig_rfh
->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(), ui::PAGE_TRANSITION_TYPED
, std::string());
876 contents()->TestDidNavigate(
877 orig_rfh
, 1, url
, ui::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 ui::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
, ui::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
, ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
908 EXPECT_FALSE(contents()->cross_navigation_pending());
909 contents()->TestDidNavigate(
910 orig_rfh
, 3, url3
, ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
925 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::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(), ui::PAGE_TRANSITION_TYPED
, std::string());
933 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
934 base::TimeTicks now
= base::TimeTicks::Now();
935 orig_rfh
->OnMessageReceived(
936 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
937 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
938 EXPECT_FALSE(contents()->cross_navigation_pending());
939 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
941 // Navigate again, but simulate an onbeforeunload approval.
942 controller().LoadURL(
943 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
944 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
945 now
= base::TimeTicks::Now();
946 orig_rfh
->OnMessageReceived(
947 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
948 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
949 EXPECT_TRUE(contents()->cross_navigation_pending());
950 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
952 // We won't hear DidNavigate until the onunload handler has finished running.
954 // DidNavigate from the pending page.
955 contents()->TestDidNavigate(
956 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
957 SiteInstance
* instance2
= contents()->GetSiteInstance();
958 EXPECT_FALSE(contents()->cross_navigation_pending());
959 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
960 EXPECT_NE(instance1
, instance2
);
961 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
964 // Test that during a slow cross-site navigation, the original renderer can
965 // navigate to a different URL and have it displayed, canceling the slow
967 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
968 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
969 SiteInstance
* instance1
= contents()->GetSiteInstance();
971 // Navigate to URL. First URL should use first RenderFrameHost.
972 const GURL
url("http://www.google.com");
973 controller().LoadURL(
974 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
975 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
976 EXPECT_FALSE(contents()->cross_navigation_pending());
977 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
979 // Navigate to new site, simulating an onbeforeunload approval.
980 const GURL
url2("http://www.yahoo.com");
981 controller().LoadURL(
982 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
983 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
984 base::TimeTicks now
= base::TimeTicks::Now();
985 orig_rfh
->OnMessageReceived(FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
986 EXPECT_TRUE(contents()->cross_navigation_pending());
988 // Suppose the original renderer navigates before the new one is ready.
989 orig_rfh
->SendNavigate(2, GURL("http://www.google.com/foo"));
991 // Verify that the pending navigation is cancelled.
992 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
993 SiteInstance
* instance2
= contents()->GetSiteInstance();
994 EXPECT_FALSE(contents()->cross_navigation_pending());
995 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
996 EXPECT_EQ(instance1
, instance2
);
997 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1000 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1001 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1002 const GURL
url1("chrome://blah");
1003 controller().LoadURL(
1004 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1005 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
1006 contents()->TestDidNavigate(ntp_rfh
, 1, url1
, ui::PAGE_TRANSITION_TYPED
);
1007 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1008 SiteInstance
* instance1
= contents()->GetSiteInstance();
1010 EXPECT_FALSE(contents()->cross_navigation_pending());
1011 EXPECT_EQ(ntp_rfh
, contents()->GetMainFrame());
1012 EXPECT_EQ(url1
, entry1
->GetURL());
1013 EXPECT_EQ(instance1
,
1014 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1015 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1016 BINDINGS_POLICY_WEB_UI
);
1018 // Navigate to new site.
1019 const GURL
url2("http://www.google.com");
1020 controller().LoadURL(
1021 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1022 EXPECT_TRUE(contents()->cross_navigation_pending());
1023 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1025 // Simulate beforeunload approval.
1026 EXPECT_TRUE(ntp_rfh
->is_waiting_for_beforeunload_ack());
1027 base::TimeTicks now
= base::TimeTicks::Now();
1028 ntp_rfh
->OnMessageReceived(
1029 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1031 // DidNavigate from the pending page.
1032 contents()->TestDidNavigate(
1033 google_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1034 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1035 SiteInstance
* instance2
= contents()->GetSiteInstance();
1037 EXPECT_FALSE(contents()->cross_navigation_pending());
1038 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1039 EXPECT_NE(instance1
, instance2
);
1040 EXPECT_FALSE(contents()->GetPendingMainFrame());
1041 EXPECT_EQ(url2
, entry2
->GetURL());
1042 EXPECT_EQ(instance2
,
1043 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1044 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1045 BINDINGS_POLICY_WEB_UI
);
1047 // Navigate to third page on same site.
1048 const GURL
url3("http://news.google.com");
1049 controller().LoadURL(
1050 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1051 EXPECT_FALSE(contents()->cross_navigation_pending());
1052 contents()->TestDidNavigate(
1053 google_rfh
, 2, url3
, ui::PAGE_TRANSITION_TYPED
);
1054 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1055 SiteInstance
* instance3
= contents()->GetSiteInstance();
1057 EXPECT_FALSE(contents()->cross_navigation_pending());
1058 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1059 EXPECT_EQ(instance2
, instance3
);
1060 EXPECT_FALSE(contents()->GetPendingMainFrame());
1061 EXPECT_EQ(url3
, entry3
->GetURL());
1062 EXPECT_EQ(instance3
,
1063 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1065 // Go back within the site.
1066 controller().GoBack();
1067 EXPECT_FALSE(contents()->cross_navigation_pending());
1068 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1070 // Before that commits, go back again.
1071 controller().GoBack();
1072 EXPECT_TRUE(contents()->cross_navigation_pending());
1073 EXPECT_TRUE(contents()->GetPendingMainFrame());
1074 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1076 // Simulate beforeunload approval.
1077 EXPECT_TRUE(google_rfh
->is_waiting_for_beforeunload_ack());
1078 now
= base::TimeTicks::Now();
1079 google_rfh
->OnMessageReceived(
1080 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1082 // DidNavigate from the first back. This aborts the second back's pending RFH.
1083 contents()->TestDidNavigate(google_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1085 // We should commit this page and forget about the second back.
1086 EXPECT_FALSE(contents()->cross_navigation_pending());
1087 EXPECT_FALSE(controller().GetPendingEntry());
1088 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1089 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1091 // We should not have corrupted the NTP entry.
1092 EXPECT_EQ(instance3
,
1093 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1094 EXPECT_EQ(instance2
,
1095 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1096 EXPECT_EQ(instance1
,
1097 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1098 EXPECT_EQ(url1
, entry1
->GetURL());
1101 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1102 // original renderer will not cancel the slow navigation (bug 42029).
1103 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1104 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1106 // Navigate to URL. First URL should use the original RenderFrameHost.
1107 const GURL
url("http://www.google.com");
1108 controller().LoadURL(
1109 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1110 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1111 EXPECT_FALSE(contents()->cross_navigation_pending());
1112 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1114 // Start navigating to new site.
1115 const GURL
url2("http://www.yahoo.com");
1116 controller().LoadURL(
1117 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1119 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1120 // waiting for a before unload response.
1121 TestRenderFrameHost
* child_rfh
= orig_rfh
->AppendChild("subframe");
1122 child_rfh
->SendNavigateWithTransition(
1123 1, GURL("http://google.com/frame"), ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
1124 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1126 // Now simulate the onbeforeunload approval and verify the navigation is
1128 base::TimeTicks now
= base::TimeTicks::Now();
1129 orig_rfh
->OnMessageReceived(
1130 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1131 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1132 EXPECT_TRUE(contents()->cross_navigation_pending());
1135 // Test that a cross-site navigation is not preempted if the previous
1136 // renderer sends a FrameNavigate message just before being told to stop.
1137 // We should only preempt the cross-site navigation if the previous renderer
1138 // has started a new navigation. See http://crbug.com/79176.
1139 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1140 // Navigate to NTP URL.
1141 const GURL
url("chrome://blah");
1142 controller().LoadURL(
1143 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1144 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1145 EXPECT_FALSE(contents()->cross_navigation_pending());
1147 // Navigate to new site, with the beforeunload request in flight.
1148 const GURL
url2("http://www.yahoo.com");
1149 controller().LoadURL(
1150 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1151 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1152 EXPECT_TRUE(contents()->cross_navigation_pending());
1153 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1155 // Suppose the first navigation tries to commit now, with a
1156 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1157 // but it should act as if the beforeunload ack arrived.
1158 orig_rfh
->SendNavigate(1, GURL("chrome://blah"));
1159 EXPECT_TRUE(contents()->cross_navigation_pending());
1160 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1161 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1163 // The pending navigation should be able to commit successfully.
1164 contents()->TestDidNavigate(pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1165 EXPECT_FALSE(contents()->cross_navigation_pending());
1166 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1169 // Test that a cross-site navigation that doesn't commit after the unload
1170 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1171 TEST_F(WebContentsImplTest
, CrossSiteNavigationCanceled
) {
1172 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1173 SiteInstance
* instance1
= contents()->GetSiteInstance();
1175 // Navigate to URL. First URL should use original RenderFrameHost.
1176 const GURL
url("http://www.google.com");
1177 controller().LoadURL(
1178 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1179 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1180 EXPECT_FALSE(contents()->cross_navigation_pending());
1181 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1183 // Navigate to new site, simulating an onbeforeunload approval.
1184 const GURL
url2("http://www.yahoo.com");
1185 controller().LoadURL(
1186 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1187 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1188 base::TimeTicks now
= base::TimeTicks::Now();
1189 orig_rfh
->OnMessageReceived(
1190 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1191 EXPECT_TRUE(contents()->cross_navigation_pending());
1193 // Simulate swap out message when the response arrives.
1194 orig_rfh
->OnSwappedOut();
1196 // Suppose the navigation doesn't get a chance to commit, and the user
1197 // navigates in the current RFH's SiteInstance.
1198 controller().LoadURL(
1199 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1201 // Verify that the pending navigation is cancelled and the renderer is no
1202 // longer swapped out.
1203 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1204 SiteInstance
* instance2
= contents()->GetSiteInstance();
1205 EXPECT_FALSE(contents()->cross_navigation_pending());
1206 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1207 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, orig_rfh
->rfh_state());
1208 EXPECT_EQ(instance1
, instance2
);
1209 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1212 // Test that NavigationEntries have the correct page state after going
1213 // forward and back. Prevents regression for bug 1116137.
1214 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1215 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1217 // Navigate to URL. There should be no committed entry yet.
1218 const GURL
url("http://www.google.com");
1219 controller().LoadURL(
1220 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1221 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1222 EXPECT_TRUE(entry
== NULL
);
1224 // Committed entry should have page state after DidNavigate.
1225 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1226 entry
= controller().GetLastCommittedEntry();
1227 EXPECT_TRUE(entry
->GetPageState().IsValid());
1229 // Navigate to same site.
1230 const GURL
url2("http://images.google.com");
1231 controller().LoadURL(
1232 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1233 entry
= controller().GetLastCommittedEntry();
1234 EXPECT_TRUE(entry
->GetPageState().IsValid());
1236 // Committed entry should have page state after DidNavigate.
1237 contents()->TestDidNavigate(orig_rfh
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
1238 entry
= controller().GetLastCommittedEntry();
1239 EXPECT_TRUE(entry
->GetPageState().IsValid());
1241 // Now go back. Committed entry should still have page state.
1242 controller().GoBack();
1243 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1244 entry
= controller().GetLastCommittedEntry();
1245 EXPECT_TRUE(entry
->GetPageState().IsValid());
1248 // Test that NavigationEntries have the correct page state and SiteInstance
1249 // state after opening a new window to about:blank. Prevents regression for
1250 // bugs b/1116137 and http://crbug.com/111975.
1251 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1252 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1254 // When opening a new window, it is navigated to about:blank internally.
1255 // Currently, this results in two DidNavigate events.
1256 const GURL
url(url::kAboutBlankURL
);
1257 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1258 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1260 // Should have a page state here.
1261 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1262 EXPECT_TRUE(entry
->GetPageState().IsValid());
1264 // The SiteInstance should be available for other navigations to use.
1265 NavigationEntryImpl
* entry_impl
=
1266 NavigationEntryImpl::FromNavigationEntry(entry
);
1267 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1268 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1270 // Navigating to a normal page should not cause a process swap.
1271 const GURL
new_url("http://www.google.com");
1272 controller().LoadURL(new_url
, Referrer(),
1273 ui::PAGE_TRANSITION_TYPED
, std::string());
1274 EXPECT_FALSE(contents()->cross_navigation_pending());
1275 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1276 contents()->TestDidNavigate(orig_rfh
, 1, new_url
, ui::PAGE_TRANSITION_TYPED
);
1277 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1278 controller().GetLastCommittedEntry());
1279 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1280 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1283 // Tests that fullscreen is exited throughout the object hierarchy when
1284 // navigating to a new page.
1285 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1286 FakeFullscreenDelegate fake_delegate
;
1287 contents()->SetDelegate(&fake_delegate
);
1288 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1289 TestRenderViewHost
* orig_rvh
= orig_rfh
->GetRenderViewHost();
1291 // Navigate to a site.
1292 const GURL
url("http://www.google.com");
1293 controller().LoadURL(
1294 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1295 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1296 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1298 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1299 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1300 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1301 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1302 orig_rvh
->OnMessageReceived(
1303 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1304 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1305 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1306 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1308 // Navigate to a new site.
1309 const GURL
url2("http://www.yahoo.com");
1310 controller().LoadURL(
1311 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1312 TestRenderFrameHost
* const pending_rfh
= contents()->GetPendingMainFrame();
1313 contents()->TestDidNavigate(
1314 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1316 // Confirm fullscreen has exited.
1317 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1318 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1319 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1321 contents()->SetDelegate(NULL
);
1324 // Tests that fullscreen is exited throughout the object hierarchy when
1325 // instructing NavigationController to GoBack() or GoForward().
1326 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1327 FakeFullscreenDelegate fake_delegate
;
1328 contents()->SetDelegate(&fake_delegate
);
1329 TestRenderFrameHost
* const orig_rfh
= contents()->GetMainFrame();
1330 TestRenderViewHost
* const orig_rvh
= orig_rfh
->GetRenderViewHost();
1332 // Navigate to a site.
1333 const GURL
url("http://www.google.com");
1334 controller().LoadURL(
1335 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1336 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1337 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1339 // Now, navigate to another page on the same site.
1340 const GURL
url2("http://www.google.com/search?q=kittens");
1341 controller().LoadURL(
1342 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1343 EXPECT_FALSE(contents()->cross_navigation_pending());
1344 contents()->TestDidNavigate(orig_rfh
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
1345 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1347 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1348 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1349 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1350 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1352 for (int i
= 0; i
< 2; ++i
) {
1353 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1354 orig_rvh
->OnMessageReceived(
1355 ViewHostMsg_ToggleFullscreen(orig_rvh
->GetRoutingID(), true));
1356 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1357 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1358 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1360 // Navigate backward (or forward).
1362 controller().GoBack();
1364 controller().GoForward();
1365 EXPECT_FALSE(contents()->cross_navigation_pending());
1366 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1367 contents()->TestDidNavigate(
1368 orig_rfh
, i
+ 1, url
, ui::PAGE_TRANSITION_FORWARD_BACK
);
1370 // Confirm fullscreen has exited.
1371 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1372 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1373 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1376 contents()->SetDelegate(NULL
);
1379 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1380 FakeValidationMessageDelegate fake_delegate
;
1381 contents()->SetDelegate(&fake_delegate
);
1382 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1384 // Crash the renderer.
1385 contents()->GetMainFrame()->GetRenderViewHost()->OnMessageReceived(
1386 ViewHostMsg_RenderProcessGone(
1387 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1389 // Confirm HideValidationMessage was called.
1390 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1392 contents()->SetDelegate(NULL
);
1395 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1397 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1398 FakeFullscreenDelegate fake_delegate
;
1399 contents()->SetDelegate(&fake_delegate
);
1401 // Navigate to a site.
1402 const GURL
url("http://www.google.com");
1403 controller().LoadURL(
1404 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1405 contents()->TestDidNavigate(
1406 contents()->GetMainFrame(), 1, url
, ui::PAGE_TRANSITION_TYPED
);
1408 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1409 EXPECT_FALSE(test_rvh()->IsFullscreen());
1410 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1411 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1412 test_rvh()->OnMessageReceived(
1413 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1414 EXPECT_TRUE(test_rvh()->IsFullscreen());
1415 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1416 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1418 // Crash the renderer.
1419 test_rvh()->OnMessageReceived(
1420 ViewHostMsg_RenderProcessGone(
1421 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1423 // Confirm fullscreen has exited.
1424 EXPECT_FALSE(test_rvh()->IsFullscreen());
1425 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1426 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1428 contents()->SetDelegate(NULL
);
1431 ////////////////////////////////////////////////////////////////////////////////
1432 // Interstitial Tests
1433 ////////////////////////////////////////////////////////////////////////////////
1435 // Test navigating to a page (with the navigation initiated from the browser,
1436 // as when a URL is typed in the location bar) that shows an interstitial and
1437 // creates a new navigation entry, then hiding it without proceeding.
1438 TEST_F(WebContentsImplTest
,
1439 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1440 // Navigate to a page.
1441 GURL
url1("http://www.google.com");
1442 contents()->GetMainFrame()->SendNavigate(1, url1
);
1443 EXPECT_EQ(1, controller().GetEntryCount());
1445 // Initiate a browser navigation that will trigger the interstitial
1446 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1447 ui::PAGE_TRANSITION_TYPED
, std::string());
1449 // Show an interstitial.
1450 TestInterstitialPage::InterstitialState state
=
1451 TestInterstitialPage::INVALID
;
1452 bool deleted
= false;
1453 GURL
url2("http://interstitial");
1454 TestInterstitialPage
* interstitial
=
1455 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1456 TestInterstitialPageStateGuard
state_guard(interstitial
);
1457 interstitial
->Show();
1458 // The interstitial should not show until its navigation has committed.
1459 EXPECT_FALSE(interstitial
->is_showing());
1460 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1461 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1462 // Let's commit the interstitial navigation.
1463 interstitial
->TestDidNavigate(1, url2
);
1464 EXPECT_TRUE(interstitial
->is_showing());
1465 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1466 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1467 NavigationEntry
* entry
= controller().GetVisibleEntry();
1468 ASSERT_TRUE(entry
!= NULL
);
1469 EXPECT_TRUE(entry
->GetURL() == url2
);
1471 // Now don't proceed.
1472 interstitial
->DontProceed();
1473 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1474 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1475 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1476 entry
= controller().GetVisibleEntry();
1477 ASSERT_TRUE(entry
!= NULL
);
1478 EXPECT_TRUE(entry
->GetURL() == url1
);
1479 EXPECT_EQ(1, controller().GetEntryCount());
1481 RunAllPendingInMessageLoop();
1482 EXPECT_TRUE(deleted
);
1485 // Test navigating to a page (with the navigation initiated from the renderer,
1486 // as when clicking on a link in the page) that shows an interstitial and
1487 // creates a new navigation entry, then hiding it without proceeding.
1488 TEST_F(WebContentsImplTest
,
1489 ShowInterstitiaFromRendererlWithNewNavigationDontProceed
) {
1490 // Navigate to a page.
1491 GURL
url1("http://www.google.com");
1492 contents()->GetMainFrame()->SendNavigate(1, url1
);
1493 EXPECT_EQ(1, controller().GetEntryCount());
1495 // Show an interstitial (no pending entry, the interstitial would have been
1496 // triggered by clicking on a link).
1497 TestInterstitialPage::InterstitialState state
=
1498 TestInterstitialPage::INVALID
;
1499 bool deleted
= false;
1500 GURL
url2("http://interstitial");
1501 TestInterstitialPage
* interstitial
=
1502 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1503 TestInterstitialPageStateGuard
state_guard(interstitial
);
1504 interstitial
->Show();
1505 // The interstitial should not show until its navigation has committed.
1506 EXPECT_FALSE(interstitial
->is_showing());
1507 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1508 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1509 // Let's commit the interstitial navigation.
1510 interstitial
->TestDidNavigate(1, url2
);
1511 EXPECT_TRUE(interstitial
->is_showing());
1512 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1513 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1514 NavigationEntry
* entry
= controller().GetVisibleEntry();
1515 ASSERT_TRUE(entry
!= NULL
);
1516 EXPECT_TRUE(entry
->GetURL() == url2
);
1518 // Now don't proceed.
1519 interstitial
->DontProceed();
1520 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1521 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1522 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1523 entry
= controller().GetVisibleEntry();
1524 ASSERT_TRUE(entry
!= NULL
);
1525 EXPECT_TRUE(entry
->GetURL() == url1
);
1526 EXPECT_EQ(1, controller().GetEntryCount());
1528 RunAllPendingInMessageLoop();
1529 EXPECT_TRUE(deleted
);
1532 // Test navigating to a page that shows an interstitial without creating a new
1533 // navigation entry (this happens when the interstitial is triggered by a
1534 // sub-resource in the page), then hiding it without proceeding.
1535 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1536 // Navigate to a page.
1537 GURL
url1("http://www.google.com");
1538 contents()->GetMainFrame()->SendNavigate(1, url1
);
1539 EXPECT_EQ(1, controller().GetEntryCount());
1541 // Show an interstitial.
1542 TestInterstitialPage::InterstitialState state
=
1543 TestInterstitialPage::INVALID
;
1544 bool deleted
= false;
1545 GURL
url2("http://interstitial");
1546 TestInterstitialPage
* interstitial
=
1547 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1548 TestInterstitialPageStateGuard
state_guard(interstitial
);
1549 interstitial
->Show();
1550 // The interstitial should not show until its navigation has committed.
1551 EXPECT_FALSE(interstitial
->is_showing());
1552 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1553 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1554 // Let's commit the interstitial navigation.
1555 interstitial
->TestDidNavigate(1, url2
);
1556 EXPECT_TRUE(interstitial
->is_showing());
1557 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1558 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1559 NavigationEntry
* entry
= controller().GetVisibleEntry();
1560 ASSERT_TRUE(entry
!= NULL
);
1561 // The URL specified to the interstitial should have been ignored.
1562 EXPECT_TRUE(entry
->GetURL() == url1
);
1564 // Now don't proceed.
1565 interstitial
->DontProceed();
1566 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1567 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1568 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1569 entry
= controller().GetVisibleEntry();
1570 ASSERT_TRUE(entry
!= NULL
);
1571 EXPECT_TRUE(entry
->GetURL() == url1
);
1572 EXPECT_EQ(1, controller().GetEntryCount());
1574 RunAllPendingInMessageLoop();
1575 EXPECT_TRUE(deleted
);
1578 // Test navigating to a page (with the navigation initiated from the browser,
1579 // as when a URL is typed in the location bar) that shows an interstitial and
1580 // creates a new navigation entry, then proceeding.
1581 TEST_F(WebContentsImplTest
,
1582 ShowInterstitialFromBrowserNewNavigationProceed
) {
1583 // Navigate to a page.
1584 GURL
url1("http://www.google.com");
1585 contents()->GetMainFrame()->SendNavigate(1, url1
);
1586 EXPECT_EQ(1, controller().GetEntryCount());
1588 // Initiate a browser navigation that will trigger the interstitial
1589 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1590 ui::PAGE_TRANSITION_TYPED
, std::string());
1592 // Show an interstitial.
1593 TestInterstitialPage::InterstitialState state
=
1594 TestInterstitialPage::INVALID
;
1595 bool deleted
= false;
1596 GURL
url2("http://interstitial");
1597 TestInterstitialPage
* interstitial
=
1598 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1599 TestInterstitialPageStateGuard
state_guard(interstitial
);
1600 interstitial
->Show();
1601 // The interstitial should not show until its navigation has committed.
1602 EXPECT_FALSE(interstitial
->is_showing());
1603 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1604 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1605 // Let's commit the interstitial navigation.
1606 interstitial
->TestDidNavigate(1, url2
);
1607 EXPECT_TRUE(interstitial
->is_showing());
1608 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1609 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1610 NavigationEntry
* entry
= controller().GetVisibleEntry();
1611 ASSERT_TRUE(entry
!= NULL
);
1612 EXPECT_TRUE(entry
->GetURL() == url2
);
1615 interstitial
->Proceed();
1616 // The interstitial should show until the new navigation commits.
1617 RunAllPendingInMessageLoop();
1618 ASSERT_FALSE(deleted
);
1619 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1620 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1621 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1623 // Simulate the navigation to the page, that's when the interstitial gets
1625 GURL
url3("http://www.thepage.com");
1626 contents()->GetMainFrame()->SendNavigate(2, url3
);
1628 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1629 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1630 entry
= controller().GetVisibleEntry();
1631 ASSERT_TRUE(entry
!= NULL
);
1632 EXPECT_TRUE(entry
->GetURL() == url3
);
1634 EXPECT_EQ(2, controller().GetEntryCount());
1636 RunAllPendingInMessageLoop();
1637 EXPECT_TRUE(deleted
);
1640 // Test navigating to a page (with the navigation initiated from the renderer,
1641 // as when clicking on a link in the page) that shows an interstitial and
1642 // creates a new navigation entry, then proceeding.
1643 TEST_F(WebContentsImplTest
,
1644 ShowInterstitialFromRendererNewNavigationProceed
) {
1645 // Navigate to a page.
1646 GURL
url1("http://www.google.com");
1647 contents()->GetMainFrame()->SendNavigate(1, url1
);
1648 EXPECT_EQ(1, controller().GetEntryCount());
1650 // Show an interstitial.
1651 TestInterstitialPage::InterstitialState state
=
1652 TestInterstitialPage::INVALID
;
1653 bool deleted
= false;
1654 GURL
url2("http://interstitial");
1655 TestInterstitialPage
* interstitial
=
1656 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1657 TestInterstitialPageStateGuard
state_guard(interstitial
);
1658 interstitial
->Show();
1659 // The interstitial should not show until its navigation has committed.
1660 EXPECT_FALSE(interstitial
->is_showing());
1661 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1662 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1663 // Let's commit the interstitial navigation.
1664 interstitial
->TestDidNavigate(1, url2
);
1665 EXPECT_TRUE(interstitial
->is_showing());
1666 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1667 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1668 NavigationEntry
* entry
= controller().GetVisibleEntry();
1669 ASSERT_TRUE(entry
!= NULL
);
1670 EXPECT_TRUE(entry
->GetURL() == url2
);
1673 interstitial
->Proceed();
1674 // The interstitial should show until the new navigation commits.
1675 RunAllPendingInMessageLoop();
1676 ASSERT_FALSE(deleted
);
1677 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1678 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1679 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1681 // Simulate the navigation to the page, that's when the interstitial gets
1683 GURL
url3("http://www.thepage.com");
1684 contents()->GetMainFrame()->SendNavigate(2, url3
);
1686 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1687 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1688 entry
= controller().GetVisibleEntry();
1689 ASSERT_TRUE(entry
!= NULL
);
1690 EXPECT_TRUE(entry
->GetURL() == url3
);
1692 EXPECT_EQ(2, controller().GetEntryCount());
1694 RunAllPendingInMessageLoop();
1695 EXPECT_TRUE(deleted
);
1698 // Test navigating to a page that shows an interstitial without creating a new
1699 // navigation entry (this happens when the interstitial is triggered by a
1700 // sub-resource in the page), then proceeding.
1701 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1702 // Navigate to a page so we have a navigation entry in the controller.
1703 GURL
url1("http://www.google.com");
1704 contents()->GetMainFrame()->SendNavigate(1, url1
);
1705 EXPECT_EQ(1, controller().GetEntryCount());
1707 // Show an interstitial.
1708 TestInterstitialPage::InterstitialState state
=
1709 TestInterstitialPage::INVALID
;
1710 bool deleted
= false;
1711 GURL
url2("http://interstitial");
1712 TestInterstitialPage
* interstitial
=
1713 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1714 TestInterstitialPageStateGuard
state_guard(interstitial
);
1715 interstitial
->Show();
1716 // The interstitial should not show until its navigation has committed.
1717 EXPECT_FALSE(interstitial
->is_showing());
1718 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1719 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1720 // Let's commit the interstitial navigation.
1721 interstitial
->TestDidNavigate(1, url2
);
1722 EXPECT_TRUE(interstitial
->is_showing());
1723 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1724 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1725 NavigationEntry
* entry
= controller().GetVisibleEntry();
1726 ASSERT_TRUE(entry
!= NULL
);
1727 // The URL specified to the interstitial should have been ignored.
1728 EXPECT_TRUE(entry
->GetURL() == url1
);
1731 interstitial
->Proceed();
1732 // Since this is not a new navigation, the previous page is dismissed right
1733 // away and shows the original page.
1734 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1735 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1736 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1737 entry
= controller().GetVisibleEntry();
1738 ASSERT_TRUE(entry
!= NULL
);
1739 EXPECT_TRUE(entry
->GetURL() == url1
);
1741 EXPECT_EQ(1, controller().GetEntryCount());
1743 RunAllPendingInMessageLoop();
1744 EXPECT_TRUE(deleted
);
1747 // Test navigating to a page that shows an interstitial, then navigating away.
1748 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1749 // Show interstitial.
1750 TestInterstitialPage::InterstitialState state
=
1751 TestInterstitialPage::INVALID
;
1752 bool deleted
= false;
1753 GURL
url("http://interstitial");
1754 TestInterstitialPage
* interstitial
=
1755 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1756 TestInterstitialPageStateGuard
state_guard(interstitial
);
1757 interstitial
->Show();
1758 interstitial
->TestDidNavigate(1, url
);
1760 // While interstitial showing, navigate to a new URL.
1761 const GURL
url2("http://www.yahoo.com");
1762 contents()->GetMainFrame()->SendNavigate(1, url2
);
1764 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1766 RunAllPendingInMessageLoop();
1767 EXPECT_TRUE(deleted
);
1770 // Test navigating to a page that shows an interstitial, then going back.
1771 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1772 // Navigate to a page so we have a navigation entry in the controller.
1773 GURL
url1("http://www.google.com");
1774 contents()->GetMainFrame()->SendNavigate(1, url1
);
1775 EXPECT_EQ(1, controller().GetEntryCount());
1777 // Show interstitial.
1778 TestInterstitialPage::InterstitialState state
=
1779 TestInterstitialPage::INVALID
;
1780 bool deleted
= false;
1781 GURL
interstitial_url("http://interstitial");
1782 TestInterstitialPage
* interstitial
=
1783 new TestInterstitialPage(contents(), true, interstitial_url
,
1785 TestInterstitialPageStateGuard
state_guard(interstitial
);
1786 interstitial
->Show();
1787 interstitial
->TestDidNavigate(2, interstitial_url
);
1789 // While the interstitial is showing, go back.
1790 controller().GoBack();
1791 contents()->GetMainFrame()->SendNavigate(1, url1
);
1793 // Make sure we are back to the original page and that the interstitial is
1795 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1796 NavigationEntry
* entry
= controller().GetVisibleEntry();
1798 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1800 RunAllPendingInMessageLoop();
1801 EXPECT_TRUE(deleted
);
1804 // Test navigating to a page that shows an interstitial, has a renderer crash,
1805 // and then goes back.
1806 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1807 // Navigate to a page so we have a navigation entry in the controller.
1808 GURL
url1("http://www.google.com");
1809 contents()->GetMainFrame()->SendNavigate(1, url1
);
1810 EXPECT_EQ(1, controller().GetEntryCount());
1812 // Show interstitial.
1813 TestInterstitialPage::InterstitialState state
=
1814 TestInterstitialPage::INVALID
;
1815 bool deleted
= false;
1816 GURL
interstitial_url("http://interstitial");
1817 TestInterstitialPage
* interstitial
=
1818 new TestInterstitialPage(contents(), true, interstitial_url
,
1820 TestInterstitialPageStateGuard
state_guard(interstitial
);
1821 interstitial
->Show();
1822 interstitial
->TestDidNavigate(2, interstitial_url
);
1824 // Crash the renderer
1825 test_rvh()->OnMessageReceived(
1826 ViewHostMsg_RenderProcessGone(
1827 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1829 // While the interstitial is showing, go back.
1830 controller().GoBack();
1831 contents()->GetMainFrame()->SendNavigate(1, url1
);
1833 // Make sure we are back to the original page and that the interstitial is
1835 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1836 NavigationEntry
* entry
= controller().GetVisibleEntry();
1838 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1840 RunAllPendingInMessageLoop();
1841 EXPECT_TRUE(deleted
);
1844 // Test navigating to a page that shows an interstitial, has the renderer crash,
1845 // and then navigates to the interstitial.
1846 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1847 // Navigate to a page so we have a navigation entry in the controller.
1848 GURL
url1("http://www.google.com");
1849 contents()->GetMainFrame()->SendNavigate(1, url1
);
1850 EXPECT_EQ(1, controller().GetEntryCount());
1852 // Show interstitial.
1853 TestInterstitialPage::InterstitialState state
=
1854 TestInterstitialPage::INVALID
;
1855 bool deleted
= false;
1856 GURL
interstitial_url("http://interstitial");
1857 TestInterstitialPage
* interstitial
=
1858 new TestInterstitialPage(contents(), true, interstitial_url
,
1860 TestInterstitialPageStateGuard
state_guard(interstitial
);
1861 interstitial
->Show();
1863 // Crash the renderer
1864 test_rvh()->OnMessageReceived(
1865 ViewHostMsg_RenderProcessGone(
1866 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1868 interstitial
->TestDidNavigate(2, interstitial_url
);
1871 // Test navigating to a page that shows an interstitial, then close the
1873 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1874 // Show interstitial.
1875 TestInterstitialPage::InterstitialState state
=
1876 TestInterstitialPage::INVALID
;
1877 bool deleted
= false;
1878 GURL
url("http://interstitial");
1879 TestInterstitialPage
* interstitial
=
1880 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1881 TestInterstitialPageStateGuard
state_guard(interstitial
);
1882 interstitial
->Show();
1883 interstitial
->TestDidNavigate(1, url
);
1885 // Now close the contents.
1887 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1889 RunAllPendingInMessageLoop();
1890 EXPECT_TRUE(deleted
);
1893 // Test navigating to a page that shows an interstitial, then close the
1895 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
1896 // Show interstitial.
1897 TestInterstitialPage::InterstitialState state
=
1898 TestInterstitialPage::INVALID
;
1899 bool deleted
= false;
1900 GURL
url("http://interstitial");
1901 TestInterstitialPage
* interstitial
=
1902 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1903 TestInterstitialPageStateGuard
state_guard(interstitial
);
1904 interstitial
->Show();
1905 interstitial
->TestDidNavigate(1, url
);
1906 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
1907 interstitial
->GetRenderViewHostForTesting());
1909 // Now close the contents.
1911 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1913 // Before the interstitial has a chance to process its shutdown task,
1914 // simulate quitting the browser. This goes through all processes and
1915 // tells them to destruct.
1916 rvh
->OnMessageReceived(
1917 ViewHostMsg_RenderProcessGone(0, 0, 0));
1919 RunAllPendingInMessageLoop();
1920 EXPECT_TRUE(deleted
);
1923 // Test that after Proceed is called and an interstitial is still shown, no more
1924 // commands get executed.
1925 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
1926 // Navigate to a page so we have a navigation entry in the controller.
1927 GURL
url1("http://www.google.com");
1928 contents()->GetMainFrame()->SendNavigate(1, url1
);
1929 EXPECT_EQ(1, controller().GetEntryCount());
1931 // Show an interstitial.
1932 TestInterstitialPage::InterstitialState state
=
1933 TestInterstitialPage::INVALID
;
1934 bool deleted
= false;
1935 GURL
url2("http://interstitial");
1936 TestInterstitialPage
* interstitial
=
1937 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1938 TestInterstitialPageStateGuard
state_guard(interstitial
);
1939 interstitial
->Show();
1940 interstitial
->TestDidNavigate(1, url2
);
1943 EXPECT_EQ(0, interstitial
->command_received_count());
1944 interstitial
->TestDomOperationResponse("toto");
1945 EXPECT_EQ(1, interstitial
->command_received_count());
1948 interstitial
->Proceed();
1949 RunAllPendingInMessageLoop();
1950 ASSERT_FALSE(deleted
);
1952 // While the navigation to the new page is pending, send other commands, they
1953 // should be ignored.
1954 interstitial
->TestDomOperationResponse("hello");
1955 interstitial
->TestDomOperationResponse("hi");
1956 EXPECT_EQ(1, interstitial
->command_received_count());
1959 // Test showing an interstitial while another interstitial is already showing.
1960 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
1961 // Navigate to a page so we have a navigation entry in the controller.
1962 GURL
start_url("http://www.google.com");
1963 contents()->GetMainFrame()->SendNavigate(1, start_url
);
1964 EXPECT_EQ(1, controller().GetEntryCount());
1966 // Show an interstitial.
1967 TestInterstitialPage::InterstitialState state1
=
1968 TestInterstitialPage::INVALID
;
1969 bool deleted1
= false;
1970 GURL
url1("http://interstitial1");
1971 TestInterstitialPage
* interstitial1
=
1972 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
1973 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
1974 interstitial1
->Show();
1975 interstitial1
->TestDidNavigate(1, url1
);
1977 // Now show another interstitial.
1978 TestInterstitialPage::InterstitialState state2
=
1979 TestInterstitialPage::INVALID
;
1980 bool deleted2
= false;
1981 GURL
url2("http://interstitial2");
1982 TestInterstitialPage
* interstitial2
=
1983 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
1984 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
1985 interstitial2
->Show();
1986 interstitial2
->TestDidNavigate(1, url2
);
1988 // Showing interstitial2 should have caused interstitial1 to go away.
1989 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
1990 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
1992 RunAllPendingInMessageLoop();
1993 EXPECT_TRUE(deleted1
);
1994 ASSERT_FALSE(deleted2
);
1996 // Let's make sure interstitial2 is working as intended.
1997 interstitial2
->Proceed();
1998 GURL
landing_url("http://www.thepage.com");
1999 contents()->GetMainFrame()->SendNavigate(2, landing_url
);
2001 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2002 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2003 NavigationEntry
* entry
= controller().GetVisibleEntry();
2004 ASSERT_TRUE(entry
!= NULL
);
2005 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2006 EXPECT_EQ(2, controller().GetEntryCount());
2007 RunAllPendingInMessageLoop();
2008 EXPECT_TRUE(deleted2
);
2011 // Test showing an interstitial, proceeding and then navigating to another
2013 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2014 // Navigate to a page so we have a navigation entry in the controller.
2015 GURL
start_url("http://www.google.com");
2016 contents()->GetMainFrame()->SendNavigate(1, start_url
);
2017 EXPECT_EQ(1, controller().GetEntryCount());
2019 // Show an interstitial.
2020 TestInterstitialPage::InterstitialState state1
=
2021 TestInterstitialPage::INVALID
;
2022 bool deleted1
= false;
2023 GURL
url1("http://interstitial1");
2024 TestInterstitialPage
* interstitial1
=
2025 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2026 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2027 interstitial1
->Show();
2028 interstitial1
->TestDidNavigate(1, url1
);
2030 // Take action. The interstitial won't be hidden until the navigation is
2032 interstitial1
->Proceed();
2033 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2035 // Now show another interstitial (simulating the navigation causing another
2037 TestInterstitialPage::InterstitialState state2
=
2038 TestInterstitialPage::INVALID
;
2039 bool deleted2
= false;
2040 GURL
url2("http://interstitial2");
2041 TestInterstitialPage
* interstitial2
=
2042 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2043 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2044 interstitial2
->Show();
2045 interstitial2
->TestDidNavigate(1, url2
);
2047 // Showing interstitial2 should have caused interstitial1 to go away.
2048 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2049 RunAllPendingInMessageLoop();
2050 EXPECT_TRUE(deleted1
);
2051 ASSERT_FALSE(deleted2
);
2053 // Let's make sure interstitial2 is working as intended.
2054 interstitial2
->Proceed();
2055 GURL
landing_url("http://www.thepage.com");
2056 contents()->GetMainFrame()->SendNavigate(2, landing_url
);
2058 RunAllPendingInMessageLoop();
2059 EXPECT_TRUE(deleted2
);
2060 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2061 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2062 NavigationEntry
* entry
= controller().GetVisibleEntry();
2063 ASSERT_TRUE(entry
!= NULL
);
2064 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2065 EXPECT_EQ(2, controller().GetEntryCount());
2068 // Test that navigating away from an interstitial while it's loading cause it
2070 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2071 // Show an interstitial.
2072 TestInterstitialPage::InterstitialState state
=
2073 TestInterstitialPage::INVALID
;
2074 bool deleted
= false;
2075 GURL
interstitial_url("http://interstitial");
2076 TestInterstitialPage
* interstitial
=
2077 new TestInterstitialPage(contents(), true, interstitial_url
,
2079 TestInterstitialPageStateGuard
state_guard(interstitial
);
2080 interstitial
->Show();
2082 // Let's simulate a navigation initiated from the browser before the
2083 // interstitial finishes loading.
2084 const GURL
url("http://www.google.com");
2085 controller().LoadURL(
2086 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2087 EXPECT_FALSE(interstitial
->is_showing());
2088 RunAllPendingInMessageLoop();
2089 ASSERT_FALSE(deleted
);
2091 // Now let's make the interstitial navigation commit.
2092 interstitial
->TestDidNavigate(1, interstitial_url
);
2094 // After it loaded the interstitial should be gone.
2095 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2097 RunAllPendingInMessageLoop();
2098 EXPECT_TRUE(deleted
);
2101 // Test that a new request to show an interstitial while an interstitial is
2102 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2103 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2104 GURL
interstitial_url("http://interstitial");
2106 // Show a first interstitial.
2107 TestInterstitialPage::InterstitialState state1
=
2108 TestInterstitialPage::INVALID
;
2109 bool deleted1
= false;
2110 TestInterstitialPage
* interstitial1
=
2111 new TestInterstitialPage(contents(), true, interstitial_url
,
2112 &state1
, &deleted1
);
2113 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2114 interstitial1
->Show();
2116 // Show another interstitial on that same contents before the first one had
2118 TestInterstitialPage::InterstitialState state2
=
2119 TestInterstitialPage::INVALID
;
2120 bool deleted2
= false;
2121 TestInterstitialPage
* interstitial2
=
2122 new TestInterstitialPage(contents(), true, interstitial_url
,
2123 &state2
, &deleted2
);
2124 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2125 interstitial2
->Show();
2127 // The first interstitial should have been closed and deleted.
2128 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2129 // The 2nd one should still be OK.
2130 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2132 RunAllPendingInMessageLoop();
2133 EXPECT_TRUE(deleted1
);
2134 ASSERT_FALSE(deleted2
);
2136 // Make the interstitial navigation commit it should be showing.
2137 interstitial2
->TestDidNavigate(1, interstitial_url
);
2138 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2141 // Test showing an interstitial and have its renderer crash.
2142 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2143 // Show an interstitial.
2144 TestInterstitialPage::InterstitialState state
=
2145 TestInterstitialPage::INVALID
;
2146 bool deleted
= false;
2147 GURL
url("http://interstitial");
2148 TestInterstitialPage
* interstitial
=
2149 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2150 TestInterstitialPageStateGuard
state_guard(interstitial
);
2151 interstitial
->Show();
2152 // Simulate a renderer crash before the interstitial is shown.
2153 interstitial
->TestRenderViewTerminated(
2154 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2155 // The interstitial should have been dismissed.
2156 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2157 RunAllPendingInMessageLoop();
2158 EXPECT_TRUE(deleted
);
2160 // Now try again but this time crash the intersitial after it was shown.
2162 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2163 interstitial
->Show();
2164 interstitial
->TestDidNavigate(1, url
);
2165 // Simulate a renderer crash.
2166 interstitial
->TestRenderViewTerminated(
2167 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2168 // The interstitial should have been dismissed.
2169 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2170 RunAllPendingInMessageLoop();
2171 EXPECT_TRUE(deleted
);
2174 // Tests that showing an interstitial as a result of a browser initiated
2175 // navigation while an interstitial is showing does not remove the pending
2176 // entry (see http://crbug.com/9791).
2177 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2178 const char kUrl
[] = "http://www.badguys.com/";
2179 const GURL
kGURL(kUrl
);
2181 // Start a navigation to a page
2182 contents()->GetController().LoadURL(
2183 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2185 // Simulate that navigation triggering an interstitial.
2186 TestInterstitialPage::InterstitialState state
=
2187 TestInterstitialPage::INVALID
;
2188 bool deleted
= false;
2189 TestInterstitialPage
* interstitial
=
2190 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2191 TestInterstitialPageStateGuard
state_guard(interstitial
);
2192 interstitial
->Show();
2193 interstitial
->TestDidNavigate(1, kGURL
);
2195 // Initiate a new navigation from the browser that also triggers an
2197 contents()->GetController().LoadURL(
2198 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2199 TestInterstitialPage::InterstitialState state2
=
2200 TestInterstitialPage::INVALID
;
2201 bool deleted2
= false;
2202 TestInterstitialPage
* interstitial2
=
2203 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2204 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2205 interstitial2
->Show();
2206 interstitial2
->TestDidNavigate(1, kGURL
);
2208 // Make sure we still have an entry.
2209 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2211 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2213 // And that the first interstitial is gone, but not the second.
2214 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2215 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2216 RunAllPendingInMessageLoop();
2217 EXPECT_TRUE(deleted
);
2218 EXPECT_FALSE(deleted2
);
2221 // Tests that Javascript messages are not shown while an interstitial is
2223 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2224 const char kUrl
[] = "http://www.badguys.com/";
2225 const GURL
kGURL(kUrl
);
2227 // Start a navigation to a page
2228 contents()->GetController().LoadURL(
2229 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2230 // DidNavigate from the page
2231 contents()->TestDidNavigate(
2232 contents()->GetMainFrame(), 1, kGURL
, ui::PAGE_TRANSITION_TYPED
);
2234 // Simulate showing an interstitial while the page is showing.
2235 TestInterstitialPage::InterstitialState state
=
2236 TestInterstitialPage::INVALID
;
2237 bool deleted
= false;
2238 TestInterstitialPage
* interstitial
=
2239 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2240 TestInterstitialPageStateGuard
state_guard(interstitial
);
2241 interstitial
->Show();
2242 interstitial
->TestDidNavigate(1, kGURL
);
2244 // While the interstitial is showing, let's simulate the hidden page
2245 // attempting to show a JS message.
2246 IPC::Message
* dummy_message
= new IPC::Message
;
2247 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2248 base::ASCIIToUTF16("This is an informative message"),
2249 base::ASCIIToUTF16("OK"),
2250 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2251 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2254 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2255 // interstitial it isn't copied over to the destination.
2256 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2257 // Navigate to a page.
2258 GURL
url1("http://www.google.com");
2259 contents()->GetMainFrame()->SendNavigate(1, url1
);
2260 EXPECT_EQ(1, controller().GetEntryCount());
2262 // Initiate a browser navigation that will trigger the interstitial
2263 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2264 ui::PAGE_TRANSITION_TYPED
, std::string());
2266 // Show an interstitial.
2267 TestInterstitialPage::InterstitialState state
=
2268 TestInterstitialPage::INVALID
;
2269 bool deleted
= false;
2270 GURL
url2("http://interstitial");
2271 TestInterstitialPage
* interstitial
=
2272 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2273 TestInterstitialPageStateGuard
state_guard(interstitial
);
2274 interstitial
->Show();
2275 interstitial
->TestDidNavigate(1, url2
);
2276 EXPECT_TRUE(interstitial
->is_showing());
2277 EXPECT_EQ(2, controller().GetEntryCount());
2279 // Create another NavigationController.
2280 GURL
url3("http://foo2");
2281 scoped_ptr
<TestWebContents
> other_contents(
2282 static_cast<TestWebContents
*>(CreateTestWebContents()));
2283 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2284 other_contents
->NavigateAndCommit(url3
);
2285 other_contents
->ExpectSetHistoryLengthAndPrune(
2286 NavigationEntryImpl::FromNavigationEntry(
2287 other_controller
.GetEntryAtIndex(0))->site_instance(), 1,
2288 other_controller
.GetEntryAtIndex(0)->GetPageID());
2289 other_controller
.CopyStateFromAndPrune(&controller(), false);
2291 // The merged controller should only have two entries: url1 and url2.
2292 ASSERT_EQ(2, other_controller
.GetEntryCount());
2293 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2294 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2295 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2297 // And the merged controller shouldn't be showing an interstitial.
2298 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2301 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2302 // showing an interstitial.
2303 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2304 // Navigate to a page.
2305 GURL
url1("http://www.google.com");
2306 contents()->NavigateAndCommit(url1
);
2308 // Create another NavigationController.
2309 scoped_ptr
<TestWebContents
> other_contents(
2310 static_cast<TestWebContents
*>(CreateTestWebContents()));
2311 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2313 // Navigate it to url2.
2314 GURL
url2("http://foo2");
2315 other_contents
->NavigateAndCommit(url2
);
2317 // Show an interstitial.
2318 TestInterstitialPage::InterstitialState state
=
2319 TestInterstitialPage::INVALID
;
2320 bool deleted
= false;
2321 GURL
url3("http://interstitial");
2322 TestInterstitialPage
* interstitial
=
2323 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2325 TestInterstitialPageStateGuard
state_guard(interstitial
);
2326 interstitial
->Show();
2327 interstitial
->TestDidNavigate(1, url3
);
2328 EXPECT_TRUE(interstitial
->is_showing());
2329 EXPECT_EQ(2, other_controller
.GetEntryCount());
2331 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2332 // interstitial is showing in the target.
2333 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2336 // Regression test for http://crbug.com/168611 - the URLs passed by the
2337 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2338 TEST_F(WebContentsImplTest
, FilterURLs
) {
2339 TestWebContentsObserver
observer(contents());
2341 // A navigation to about:whatever should always look like a navigation to
2343 GURL
url_normalized(url::kAboutBlankURL
);
2344 GURL
url_from_ipc("about:whatever");
2346 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2347 // will use the given URL to create the NavigationEntry as well, and that
2348 // entry should contain the filtered URL.
2349 contents()->NavigateAndCommit(url_normalized
);
2351 // Check that an IPC with about:whatever is correctly normalized.
2352 contents()->TestDidFinishLoad(url_from_ipc
);
2354 EXPECT_EQ(url_normalized
, observer
.last_url());
2356 // Create and navigate another WebContents.
2357 scoped_ptr
<TestWebContents
> other_contents(
2358 static_cast<TestWebContents
*>(CreateTestWebContents()));
2359 TestWebContentsObserver
other_observer(other_contents
.get());
2360 other_contents
->NavigateAndCommit(url_normalized
);
2362 // Check that an IPC with about:whatever is correctly normalized.
2363 other_contents
->TestDidFailLoadWithError(
2364 url_from_ipc
, 1, base::string16());
2365 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2368 // Test that if a pending contents is deleted before it is shown, we don't
2370 TEST_F(WebContentsImplTest
, PendingContents
) {
2371 scoped_ptr
<TestWebContents
> other_contents(
2372 static_cast<TestWebContents
*>(CreateTestWebContents()));
2373 contents()->AddPendingContents(other_contents
.get());
2374 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2375 other_contents
.reset();
2376 EXPECT_EQ(NULL
, contents()->GetCreatedWindow(route_id
));
2379 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2380 const gfx::Size
original_preferred_size(1024, 768);
2381 contents()->UpdatePreferredSize(original_preferred_size
);
2383 // With no capturers, expect the preferred size to be the one propagated into
2384 // WebContentsImpl via the RenderViewHostDelegate interface.
2385 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2386 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2388 // Increment capturer count, but without specifying a capture size. Expect
2389 // a "not set" preferred size.
2390 contents()->IncrementCapturerCount(gfx::Size());
2391 EXPECT_EQ(1, contents()->GetCapturerCount());
2392 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2394 // Increment capturer count again, but with an overriding capture size.
2395 // Expect preferred size to now be overridden to the capture size.
2396 const gfx::Size
capture_size(1280, 720);
2397 contents()->IncrementCapturerCount(capture_size
);
2398 EXPECT_EQ(2, contents()->GetCapturerCount());
2399 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2401 // Increment capturer count a third time, but the expect that the preferred
2402 // size is still the first capture size.
2403 const gfx::Size
another_capture_size(720, 480);
2404 contents()->IncrementCapturerCount(another_capture_size
);
2405 EXPECT_EQ(3, contents()->GetCapturerCount());
2406 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2408 // Decrement capturer count twice, but expect the preferred size to still be
2410 contents()->DecrementCapturerCount();
2411 contents()->DecrementCapturerCount();
2412 EXPECT_EQ(1, contents()->GetCapturerCount());
2413 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2415 // Decrement capturer count, and since the count has dropped to zero, the
2416 // original preferred size should be restored.
2417 contents()->DecrementCapturerCount();
2418 EXPECT_EQ(0, contents()->GetCapturerCount());
2419 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2422 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2424 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2425 // The WebContents starts with a valid creation time.
2426 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2428 // Reset the last active time to a known-bad value.
2429 contents()->last_active_time_
= base::TimeTicks();
2430 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2432 // Simulate activating the WebContents. The active time should update.
2433 contents()->WasShown();
2434 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2437 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2439 ContentsZoomChangedDelegate() :
2440 contents_zoom_changed_call_count_(0),
2441 last_zoom_in_(false) {
2444 int GetAndResetContentsZoomChangedCallCount() {
2445 int count
= contents_zoom_changed_call_count_
;
2446 contents_zoom_changed_call_count_
= 0;
2450 bool last_zoom_in() const {
2451 return last_zoom_in_
;
2454 // WebContentsDelegate:
2455 void ContentsZoomChange(bool zoom_in
) override
{
2456 contents_zoom_changed_call_count_
++;
2457 last_zoom_in_
= zoom_in
;
2461 int contents_zoom_changed_call_count_
;
2464 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2467 // Tests that some mouseehweel events get turned into browser zoom requests.
2468 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2469 using blink::WebInputEvent
;
2471 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2472 new ContentsZoomChangedDelegate());
2473 contents()->SetDelegate(delegate
.get());
2476 // Verify that normal mouse wheel events do nothing to change the zoom level.
2477 blink::WebMouseWheelEvent event
=
2478 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2479 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2480 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2482 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
;
2483 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2484 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2485 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2487 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2488 // Except on MacOS where we never want to adjust zoom with mousewheel.
2489 modifiers
= WebInputEvent::ControlKey
;
2490 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2491 bool handled
= contents()->HandleWheelEvent(event
);
2492 #if defined(OS_MACOSX)
2493 EXPECT_FALSE(handled
);
2494 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2496 EXPECT_TRUE(handled
);
2497 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2498 EXPECT_TRUE(delegate
->last_zoom_in());
2501 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2502 WebInputEvent::AltKey
;
2503 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2504 handled
= contents()->HandleWheelEvent(event
);
2505 #if defined(OS_MACOSX)
2506 EXPECT_FALSE(handled
);
2507 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2509 EXPECT_TRUE(handled
);
2510 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2511 EXPECT_FALSE(delegate
->last_zoom_in());
2514 // Unless there is no vertical movement.
2515 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2516 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2517 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2519 // Events containing precise scrolling deltas also shouldn't result in the
2520 // zoom being adjusted, to avoid accidental adjustments caused by
2521 // two-finger-scrolling on a touchpad.
2522 modifiers
= WebInputEvent::ControlKey
;
2523 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2524 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2525 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2527 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2528 contents()->SetDelegate(NULL
);
2531 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2532 TEST_F(WebContentsImplTest
, HandleGestureEvent
) {
2533 using blink::WebGestureEvent
;
2534 using blink::WebInputEvent
;
2536 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2537 new ContentsZoomChangedDelegate());
2538 contents()->SetDelegate(delegate
.get());
2540 const float kZoomStepValue
= 0.6f
;
2541 blink::WebGestureEvent event
= SyntheticWebGestureEventBuilder::Build(
2542 WebInputEvent::GesturePinchUpdate
, blink::WebGestureDeviceTouchpad
);
2544 // A pinch less than the step value doesn't change the zoom level.
2545 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 0.8f
;
2546 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2547 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2549 // But repeating the event so the combined scale is greater does.
2550 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2551 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2552 EXPECT_TRUE(delegate
->last_zoom_in());
2554 // Pinching back out one step goes back to 100%.
2555 event
.data
.pinchUpdate
.scale
= 1.0f
- kZoomStepValue
;
2556 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2557 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2558 EXPECT_FALSE(delegate
->last_zoom_in());
2560 // Pinching out again doesn't zoom (step is twice as large around 100%).
2561 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2562 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2564 // And again now it zooms once per step.
2565 EXPECT_TRUE(contents()->HandleGestureEvent(event
));
2566 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2567 EXPECT_FALSE(delegate
->last_zoom_in());
2569 // No other type of gesture event is handled by WebContentsImpl (for example
2570 // a touchscreen pinch gesture).
2571 event
= SyntheticWebGestureEventBuilder::Build(
2572 WebInputEvent::GesturePinchUpdate
, blink::WebGestureDeviceTouchscreen
);
2573 event
.data
.pinchUpdate
.scale
= 1.0f
+ kZoomStepValue
* 3;
2574 EXPECT_FALSE(contents()->HandleGestureEvent(event
));
2575 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2577 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2578 contents()->SetDelegate(NULL
);
2581 // Tests that GetRelatedActiveContentsCount is shared between related
2582 // SiteInstances and includes WebContents that have not navigated yet.
2583 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2584 scoped_refptr
<SiteInstance
> instance1(
2585 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2586 scoped_refptr
<SiteInstance
> instance2(
2587 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2589 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2590 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2592 scoped_ptr
<TestWebContents
> contents1(
2593 TestWebContents::Create(browser_context(), instance1
.get()));
2594 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2595 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2597 scoped_ptr
<TestWebContents
> contents2(
2598 TestWebContents::Create(browser_context(), instance1
.get()));
2599 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2600 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2603 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2604 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2607 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2608 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2611 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2612 // same-site and cross-site navigations.
2613 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2614 scoped_refptr
<SiteInstance
> instance(
2615 SiteInstance::Create(browser_context()));
2617 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2619 scoped_ptr
<TestWebContents
> contents(
2620 TestWebContents::Create(browser_context(), instance
.get()));
2621 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2623 // Navigate to a URL.
2624 contents
->GetController().LoadURL(GURL("http://a.com/1"),
2626 ui::PAGE_TRANSITION_TYPED
,
2628 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2629 contents
->CommitPendingNavigation();
2630 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2632 // Navigate to a URL in the same site.
2633 contents
->GetController().LoadURL(GURL("http://a.com/2"),
2635 ui::PAGE_TRANSITION_TYPED
,
2637 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2638 contents
->CommitPendingNavigation();
2639 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2641 // Navigate to a URL in a different site.
2642 contents
->GetController().LoadURL(GURL("http://b.com"),
2644 ui::PAGE_TRANSITION_TYPED
,
2646 EXPECT_TRUE(contents
->cross_navigation_pending());
2647 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2648 contents
->CommitPendingNavigation();
2649 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2652 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2655 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2657 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2658 scoped_refptr
<SiteInstance
> instance(
2659 SiteInstance::Create(browser_context()));
2661 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2663 scoped_ptr
<TestWebContents
> contents(
2664 TestWebContents::Create(browser_context(), instance
.get()));
2665 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2667 // Navigate to a URL.
2668 contents
->NavigateAndCommit(GURL("http://a.com"));
2669 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2671 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2672 contents
->GetController().LoadURL(GURL(kTestWebUIUrl
),
2674 ui::PAGE_TRANSITION_TYPED
,
2676 EXPECT_TRUE(contents
->cross_navigation_pending());
2677 scoped_refptr
<SiteInstance
> instance_webui(
2678 contents
->GetPendingMainFrame()->GetSiteInstance());
2679 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2681 // At this point, contents still counts for the old BrowsingInstance.
2682 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2683 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2685 // Commit and contents counts for the new one.
2686 contents
->CommitPendingNavigation();
2687 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2688 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2691 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2692 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2695 // ChromeOS doesn't use WebContents based power save blocking.
2696 #if !defined(OS_CHROMEOS)
2697 TEST_F(WebContentsImplTest
, MediaPowerSaveBlocking
) {
2698 // PlayerIDs are actually pointers cast to int64, so verify that both negative
2699 // and positive player ids don't blow up.
2700 const int kPlayerAudioVideoId
= 15;
2701 const int kPlayerAudioOnlyId
= -15;
2702 const int kPlayerVideoOnlyId
= 30;
2703 const int kPlayerRemoteId
= -30;
2705 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2706 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2708 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
2709 AudioStreamMonitor
* monitor
= contents()->audio_stream_monitor();
2711 // The audio power save blocker should not be based on having a media player
2712 // when audio stream monitoring is available.
2713 if (AudioStreamMonitor::monitoring_available()) {
2714 // Send a fake audio stream monitor notification. The audio power save
2715 // blocker should be created.
2716 monitor
->set_was_recently_audible_for_testing(true);
2717 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
2718 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
2720 // Send another fake notification, this time when WasRecentlyAudible() will
2721 // be false. The power save blocker should be released.
2722 monitor
->set_was_recently_audible_for_testing(false);
2723 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
2724 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2727 // Start a player with both audio and video. A video power save blocker
2728 // should be created. If audio stream monitoring is available, an audio power
2729 // save blocker should be created too.
2730 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2731 0, kPlayerAudioVideoId
, true, true, false));
2732 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2733 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2734 !AudioStreamMonitor::monitoring_available());
2736 // Upon hiding the video power save blocker should be released.
2737 contents()->WasHidden();
2738 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2740 // Start another player that only has video. There should be no change in
2741 // the power save blockers. The notification should take into account the
2742 // visibility state of the WebContents.
2743 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2744 0, kPlayerVideoOnlyId
, true, false, false));
2745 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2746 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2747 !AudioStreamMonitor::monitoring_available());
2749 // Showing the WebContents should result in the creation of the blocker.
2750 contents()->WasShown();
2751 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2753 // Start another player that only has audio. There should be no change in
2754 // the power save blockers.
2755 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2756 0, kPlayerAudioOnlyId
, false, true, false));
2757 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2758 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2759 !AudioStreamMonitor::monitoring_available());
2761 // Start a remote player. There should be no change in the power save
2763 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2764 0, kPlayerRemoteId
, true, true, true));
2765 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2766 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2767 !AudioStreamMonitor::monitoring_available());
2769 // Destroy the original audio video player. Both power save blockers should
2771 rfh
->OnMessageReceived(
2772 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId
));
2773 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2774 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2775 !AudioStreamMonitor::monitoring_available());
2777 // Destroy the audio only player. The video power save blocker should remain.
2778 rfh
->OnMessageReceived(
2779 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId
));
2780 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2781 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2783 // Destroy the video only player. No power save blockers should remain.
2784 rfh
->OnMessageReceived(
2785 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId
));
2786 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2787 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2789 // Destroy the remote player. No power save blockers should remain.
2790 rfh
->OnMessageReceived(
2791 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId
));
2792 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2793 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2797 } // namespace content