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/command_line.h"
6 #include "base/logging.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/frame_host/cross_site_transferring_request.h"
9 #include "content/browser/frame_host/interstitial_page_impl.h"
10 #include "content/browser/frame_host/navigation_entry_impl.h"
11 #include "content/browser/frame_host/render_frame_host_impl.h"
12 #include "content/browser/media/audio_state_provider.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/browser/site_instance_impl.h"
15 #include "content/browser/webui/web_ui_controller_factory_registry.h"
16 #include "content/common/frame_messages.h"
17 #include "content/common/input/synthetic_web_input_event_builders.h"
18 #include "content/common/view_messages.h"
19 #include "content/public/browser/global_request_id.h"
20 #include "content/public/browser/interstitial_page_delegate.h"
21 #include "content/public/browser/navigation_details.h"
22 #include "content/public/browser/notification_details.h"
23 #include "content/public/browser/notification_source.h"
24 #include "content/public/browser/render_widget_host_view.h"
25 #include "content/public/browser/web_contents_delegate.h"
26 #include "content/public/browser/web_contents_observer.h"
27 #include "content/public/browser/web_ui_controller.h"
28 #include "content/public/common/bindings_policy.h"
29 #include "content/public/common/content_constants.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/common/url_constants.h"
32 #include "content/public/common/url_utils.h"
33 #include "content/public/test/mock_render_process_host.h"
34 #include "content/public/test/test_utils.h"
35 #include "content/test/test_content_browser_client.h"
36 #include "content/test/test_content_client.h"
37 #include "content/test/test_render_frame_host.h"
38 #include "content/test/test_render_view_host.h"
39 #include "content/test/test_web_contents.h"
40 #include "testing/gtest/include/gtest/gtest.h"
45 const char kTestWebUIUrl
[] = "chrome://blah";
47 class WebContentsImplTestWebUIControllerFactory
48 : public WebUIControllerFactory
{
50 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
51 const GURL
& url
) const override
{
54 return new WebUIController(web_ui
);
57 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
58 const GURL
& url
) const override
{
59 return WebUI::kNoWebUI
;
62 bool UseWebUIForURL(BrowserContext
* browser_context
,
63 const GURL
& url
) const override
{
67 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
68 const GURL
& url
) const override
{
73 bool UseWebUI(const GURL
& url
) const {
74 return url
== GURL(kTestWebUIUrl
);
78 class TestInterstitialPage
;
80 class TestInterstitialPageDelegate
: public InterstitialPageDelegate
{
82 explicit TestInterstitialPageDelegate(TestInterstitialPage
* interstitial_page
)
83 : interstitial_page_(interstitial_page
) {}
84 void CommandReceived(const std::string
& command
) override
;
85 std::string
GetHTMLContents() override
{ return std::string(); }
86 void OnDontProceed() override
;
87 void OnProceed() override
;
90 TestInterstitialPage
* interstitial_page_
;
93 class TestInterstitialPage
: public InterstitialPageImpl
{
95 enum InterstitialState
{
96 INVALID
= 0, // Hasn't yet been initialized.
97 UNDECIDED
, // Initialized, but no decision taken yet.
98 OKED
, // Proceed was called.
99 CANCELED
// DontProceed was called.
104 virtual void TestInterstitialPageDeleted(
105 TestInterstitialPage
* interstitial
) = 0;
108 virtual ~Delegate() {}
111 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
112 // |deleted| (like all interstitial related tests do at this point), make sure
113 // to create an instance of the TestInterstitialPageStateGuard class on the
114 // stack in your test. This will ensure that the TestInterstitialPage states
115 // are cleared when the test finishes.
116 // Not doing so will cause stack trashing if your test does not hide the
117 // interstitial, as in such a case it will be destroyed in the test TearDown
118 // method and will dereference the |deleted| local variable which by then is
120 TestInterstitialPage(WebContentsImpl
* contents
,
123 InterstitialState
* state
,
125 : InterstitialPageImpl(
127 static_cast<RenderWidgetHostDelegate
*>(contents
),
128 new_navigation
, url
, new TestInterstitialPageDelegate(this)),
131 command_received_count_(0),
137 ~TestInterstitialPage() override
{
141 delegate_
->TestInterstitialPageDeleted(this);
144 void OnDontProceed() {
153 int command_received_count() const {
154 return command_received_count_
;
157 void TestDomOperationResponse(const std::string
& json_string
) {
162 void TestDidNavigate(int page_id
, const GURL
& url
) {
163 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
164 InitNavigateParams(¶ms
, page_id
, url
, ui::PAGE_TRANSITION_TYPED
);
165 DidNavigate(GetMainFrame()->GetRenderViewHost(), params
);
168 void TestRenderViewTerminated(base::TerminationStatus status
,
170 RenderViewTerminated(GetMainFrame()->GetRenderViewHost(), status
,
174 bool is_showing() const {
175 return static_cast<TestRenderWidgetHostView
*>(
176 GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
185 void CommandReceived() {
186 command_received_count_
++;
189 void set_delegate(Delegate
* delegate
) {
190 delegate_
= delegate
;
194 WebContentsView
* CreateWebContentsView() override
{ return nullptr; }
197 InterstitialState
* state_
;
199 int command_received_count_
;
203 void TestInterstitialPageDelegate::CommandReceived(const std::string
& command
) {
204 interstitial_page_
->CommandReceived();
207 void TestInterstitialPageDelegate::OnDontProceed() {
208 interstitial_page_
->OnDontProceed();
211 void TestInterstitialPageDelegate::OnProceed() {
212 interstitial_page_
->OnProceed();
215 class TestInterstitialPageStateGuard
: public TestInterstitialPage::Delegate
{
217 explicit TestInterstitialPageStateGuard(
218 TestInterstitialPage
* interstitial_page
)
219 : interstitial_page_(interstitial_page
) {
220 DCHECK(interstitial_page_
);
221 interstitial_page_
->set_delegate(this);
223 ~TestInterstitialPageStateGuard() override
{
224 if (interstitial_page_
)
225 interstitial_page_
->ClearStates();
228 void TestInterstitialPageDeleted(
229 TestInterstitialPage
* interstitial
) override
{
230 DCHECK(interstitial_page_
== interstitial
);
231 interstitial_page_
= nullptr;
235 TestInterstitialPage
* interstitial_page_
;
238 class WebContentsImplTestBrowserClient
: public TestContentBrowserClient
{
240 WebContentsImplTestBrowserClient()
241 : assign_site_for_url_(false) {}
243 ~WebContentsImplTestBrowserClient() override
{}
245 bool ShouldAssignSiteForURL(const GURL
& url
) override
{
246 return assign_site_for_url_
;
249 void set_assign_site_for_url(bool assign
) {
250 assign_site_for_url_
= assign
;
254 bool assign_site_for_url_
;
257 class WebContentsImplTest
: public RenderViewHostImplTestHarness
{
259 void SetUp() override
{
260 RenderViewHostImplTestHarness::SetUp();
261 WebUIControllerFactory::RegisterFactory(&factory_
);
264 void TearDown() override
{
265 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_
);
266 RenderViewHostImplTestHarness::TearDown();
270 WebContentsImplTestWebUIControllerFactory factory_
;
273 class TestWebContentsObserver
: public WebContentsObserver
{
275 explicit TestWebContentsObserver(WebContents
* contents
)
276 : WebContentsObserver(contents
) {
278 ~TestWebContentsObserver() override
{}
280 void DidFinishLoad(RenderFrameHost
* render_frame_host
,
281 const GURL
& validated_url
) override
{
282 last_url_
= validated_url
;
284 void DidFailLoad(RenderFrameHost
* render_frame_host
,
285 const GURL
& validated_url
,
287 const base::string16
& error_description
) override
{
288 last_url_
= validated_url
;
291 const GURL
& last_url() const { return last_url_
; }
296 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver
);
299 // Pretends to be a normal browser that receives toggles and transitions to/from
300 // a fullscreened state.
301 class FakeFullscreenDelegate
: public WebContentsDelegate
{
303 FakeFullscreenDelegate() : fullscreened_contents_(nullptr) {}
304 ~FakeFullscreenDelegate() override
{}
306 void EnterFullscreenModeForTab(WebContents
* web_contents
,
307 const GURL
& origin
) override
{
308 fullscreened_contents_
= web_contents
;
311 void ExitFullscreenModeForTab(WebContents
* web_contents
) override
{
312 fullscreened_contents_
= nullptr;
315 bool IsFullscreenForTabOrPending(
316 const WebContents
* web_contents
) const override
{
317 return fullscreened_contents_
&& web_contents
== fullscreened_contents_
;
321 WebContents
* fullscreened_contents_
;
323 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate
);
326 class FakeValidationMessageDelegate
: public WebContentsDelegate
{
328 FakeValidationMessageDelegate()
329 : hide_validation_message_was_called_(false) {}
330 ~FakeValidationMessageDelegate() override
{}
332 void HideValidationMessage(WebContents
* web_contents
) override
{
333 hide_validation_message_was_called_
= true;
336 bool hide_validation_message_was_called() const {
337 return hide_validation_message_was_called_
;
341 bool hide_validation_message_was_called_
;
343 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate
);
348 // Test to make sure that title updates get stripped of whitespace.
349 TEST_F(WebContentsImplTest
, UpdateTitle
) {
350 NavigationControllerImpl
& cont
=
351 static_cast<NavigationControllerImpl
&>(controller());
352 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
354 ¶ms
, 0, GURL(url::kAboutBlankURL
), ui::PAGE_TRANSITION_TYPED
);
356 LoadCommittedDetails details
;
357 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
359 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
360 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
361 base::i18n::LEFT_TO_RIGHT
);
362 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
365 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
366 const GURL
kGURL("chrome://blah");
367 controller().LoadURL(
368 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
369 EXPECT_EQ(base::string16(), contents()->GetTitle());
372 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
373 const GURL
kGURL("chrome://blah");
374 const base::string16 title
= base::ASCIIToUTF16("My Title");
375 controller().LoadURL(
376 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
378 NavigationEntry
* entry
= controller().GetVisibleEntry();
379 ASSERT_EQ(kGURL
, entry
->GetURL());
380 entry
->SetTitle(title
);
382 EXPECT_EQ(title
, contents()->GetTitle());
385 // Test view source mode for a webui page.
386 TEST_F(WebContentsImplTest
, NTPViewSource
) {
387 NavigationControllerImpl
& cont
=
388 static_cast<NavigationControllerImpl
&>(controller());
389 const char kUrl
[] = "view-source:chrome://blah";
390 const GURL
kGURL(kUrl
);
392 process()->sink().ClearMessages();
395 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
396 rvh()->GetDelegate()->RenderViewCreated(rvh());
397 // Did we get the expected message?
398 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
399 ViewMsg_EnableViewSourceMode::ID
));
401 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
402 InitNavigateParams(¶ms
, 0, kGURL
, ui::PAGE_TRANSITION_TYPED
);
403 LoadCommittedDetails details
;
404 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
405 // Also check title and url.
406 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
409 // Test to ensure UpdateMaxPageID is working properly.
410 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
411 SiteInstance
* instance1
= contents()->GetSiteInstance();
412 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(nullptr));
415 EXPECT_EQ(-1, contents()->GetMaxPageID());
416 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
417 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
419 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
420 contents()->UpdateMaxPageID(3);
421 contents()->UpdateMaxPageID(1);
422 EXPECT_EQ(3, contents()->GetMaxPageID());
423 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
424 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
426 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
427 EXPECT_EQ(3, contents()->GetMaxPageID());
428 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
429 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
432 // Test simple same-SiteInstance navigation.
433 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
434 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
435 SiteInstance
* instance1
= contents()->GetSiteInstance();
436 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
439 const GURL
url("http://www.google.com");
440 controller().LoadURL(
441 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
442 main_test_rfh()->PrepareForCommit();
443 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
444 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
445 // Controller's pending entry will have a null site instance until we assign
446 // it in DidNavigate.
449 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
452 // DidNavigate from the page
453 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
454 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
455 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
456 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
457 // Controller's entry should now have the SiteInstance, or else we won't be
458 // able to find it later.
461 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
465 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
466 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
467 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
468 const GURL
url(std::string("http://example.org/").append(
469 GetMaxURLChars() + 1, 'a'));
471 controller().LoadURL(
472 url
, Referrer(), ui::PAGE_TRANSITION_GENERATED
, std::string());
473 EXPECT_EQ(nullptr, controller().GetVisibleEntry());
476 // Test that navigating across a site boundary creates a new RenderViewHost
477 // with a new SiteInstance. Going back should do the same.
478 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
479 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
480 int orig_rvh_delete_count
= 0;
481 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
482 SiteInstance
* instance1
= contents()->GetSiteInstance();
484 // Navigate to URL. First URL should use first RenderViewHost.
485 const GURL
url("http://www.google.com");
486 controller().LoadURL(
487 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
488 orig_rfh
->PrepareForCommit();
489 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
491 // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
492 // that orig_rfh doesn't get deleted when it gets swapped out.
493 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
495 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
496 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
497 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
498 EXPECT_EQ(url
, contents()->GetVisibleURL());
500 // Navigate to new site
501 const GURL
url2("http://www.yahoo.com");
502 controller().LoadURL(
503 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
504 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
505 switches::kEnableBrowserSideNavigation
)) {
506 orig_rfh
->PrepareForCommit();
508 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
509 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
510 EXPECT_EQ(url2
, contents()->GetVisibleURL());
511 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
512 int pending_rvh_delete_count
= 0;
513 pending_rfh
->GetRenderViewHost()->set_delete_counter(
514 &pending_rvh_delete_count
);
516 // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
517 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
518 switches::kEnableBrowserSideNavigation
)) {
519 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
520 orig_rfh
->SendBeforeUnloadACK(true);
521 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
524 // DidNavigate from the pending page
525 contents()->TestDidNavigate(
526 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
527 SiteInstance
* instance2
= contents()->GetSiteInstance();
529 // Keep the number of active frames in pending_rfh's SiteInstance
530 // non-zero so that orig_rfh doesn't get deleted when it gets
532 pending_rfh
->GetSiteInstance()->increment_active_frame_count();
534 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
535 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
536 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
537 EXPECT_EQ(url2
, contents()->GetVisibleURL());
538 EXPECT_NE(instance1
, instance2
);
539 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
540 // We keep the original RFH around, swapped out.
541 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
543 EXPECT_EQ(orig_rvh_delete_count
, 0);
545 // Going back should switch SiteInstances again. The first SiteInstance is
546 // stored in the NavigationEntry, so it should be the same as at the start.
547 // We should use the same RFH as before, swapping it back in.
548 controller().GoBack();
549 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
550 switches::kEnableBrowserSideNavigation
)) {
551 contents()->GetMainFrame()->PrepareForCommit();
553 TestRenderFrameHost
* goback_rfh
= contents()->GetPendingMainFrame();
554 EXPECT_EQ(orig_rfh
, goback_rfh
);
555 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
557 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
558 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
559 switches::kEnableBrowserSideNavigation
)) {
560 EXPECT_TRUE(goback_rfh
->are_navigations_suspended());
561 pending_rfh
->SendBeforeUnloadACK(true);
562 EXPECT_FALSE(goback_rfh
->are_navigations_suspended());
565 // DidNavigate from the back action
566 contents()->TestDidNavigate(goback_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
567 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
568 EXPECT_EQ(goback_rfh
, contents()->GetMainFrame());
569 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
570 // The pending RFH should now be swapped out, not deleted.
571 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
572 IsOnSwappedOutList(pending_rfh
));
573 EXPECT_EQ(pending_rvh_delete_count
, 0);
574 pending_rfh
->OnSwappedOut();
576 // Close contents and ensure RVHs are deleted.
578 EXPECT_EQ(orig_rvh_delete_count
, 1);
579 EXPECT_EQ(pending_rvh_delete_count
, 1);
582 // Test that navigating across a site boundary after a crash creates a new
583 // RFH without requiring a cross-site transition (i.e., PENDING state).
584 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
585 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
587 int orig_rvh_delete_count
= 0;
588 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
589 SiteInstance
* instance1
= contents()->GetSiteInstance();
591 // Navigate to URL. First URL should use first RenderViewHost.
592 const GURL
url("http://www.google.com");
593 controller().LoadURL(
594 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
595 contents()->GetMainFrame()->PrepareForCommit();
596 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
598 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
599 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
601 // Simulate a renderer crash.
602 EXPECT_TRUE(orig_rfh
->IsRenderFrameLive());
603 orig_rfh
->GetProcess()->SimulateCrash();
604 EXPECT_FALSE(orig_rfh
->IsRenderFrameLive());
606 // Navigate to new site. We should not go into PENDING.
607 const GURL
url2("http://www.yahoo.com");
608 controller().LoadURL(
609 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
610 contents()->GetMainFrame()->PrepareForCommit();
611 TestRenderFrameHost
* new_rfh
= contents()->GetMainFrame();
612 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
613 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
614 EXPECT_NE(orig_rfh
, new_rfh
);
615 EXPECT_EQ(orig_rvh_delete_count
, 1);
617 // DidNavigate from the new page
618 contents()->TestDidNavigate(new_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
619 SiteInstance
* instance2
= contents()->GetSiteInstance();
621 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
622 EXPECT_EQ(new_rfh
, main_rfh());
623 EXPECT_NE(instance1
, instance2
);
624 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
626 // Close contents and ensure RVHs are deleted.
628 EXPECT_EQ(orig_rvh_delete_count
, 1);
631 // Test that opening a new contents in the same SiteInstance and then navigating
632 // both contentses to a new site will place both contentses in a single
634 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
635 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
636 SiteInstance
* instance1
= contents()->GetSiteInstance();
638 // Navigate to URL. First URL should use first RenderViewHost.
639 const GURL
url("http://www.google.com");
640 controller().LoadURL(
641 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
642 contents()->GetMainFrame()->PrepareForCommit();
643 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
645 // Open a new contents with the same SiteInstance, navigated to the same site.
646 scoped_ptr
<TestWebContents
> contents2(
647 TestWebContents::Create(browser_context(), instance1
));
648 contents2
->GetController().LoadURL(url
, Referrer(),
649 ui::PAGE_TRANSITION_TYPED
,
651 contents2
->GetMainFrame()->PrepareForCommit();
652 // Need this page id to be 2 since the site instance is the same (which is the
653 // scope of page IDs) and we want to consider this a new page.
654 contents2
->TestDidNavigate(
655 contents2
->GetMainFrame(), 2, url
, ui::PAGE_TRANSITION_TYPED
);
657 // Navigate first contents to a new site.
658 const GURL
url2a("http://www.yahoo.com");
659 controller().LoadURL(
660 url2a
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
661 orig_rfh
->PrepareForCommit();
662 TestRenderFrameHost
* pending_rfh_a
= contents()->GetPendingMainFrame();
663 contents()->TestDidNavigate(
664 pending_rfh_a
, 1, url2a
, ui::PAGE_TRANSITION_TYPED
);
665 SiteInstance
* instance2a
= contents()->GetSiteInstance();
666 EXPECT_NE(instance1
, instance2a
);
668 // Navigate second contents to the same site as the first tab.
669 const GURL
url2b("http://mail.yahoo.com");
670 contents2
->GetController().LoadURL(url2b
, Referrer(),
671 ui::PAGE_TRANSITION_TYPED
,
673 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
674 rfh2
->PrepareForCommit();
675 TestRenderFrameHost
* pending_rfh_b
= contents2
->GetPendingMainFrame();
676 EXPECT_NE(nullptr, pending_rfh_b
);
677 EXPECT_TRUE(contents2
->CrossProcessNavigationPending());
679 // NOTE(creis): We used to be in danger of showing a crash page here if the
680 // second contents hadn't navigated somewhere first (bug 1145430). That case
681 // is now covered by the CrossSiteBoundariesAfterCrash test.
682 contents2
->TestDidNavigate(
683 pending_rfh_b
, 2, url2b
, ui::PAGE_TRANSITION_TYPED
);
684 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
685 EXPECT_NE(instance1
, instance2b
);
687 // Both contentses should now be in the same SiteInstance.
688 EXPECT_EQ(instance2a
, instance2b
);
691 // The embedder can request sites for certain urls not be be assigned to the
692 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
693 // allowing to reuse the renderer backing certain chrome urls for subsequent
694 // navigation. The test verifies that the override is honored.
695 TEST_F(WebContentsImplTest
, NavigateFromSitelessUrl
) {
696 WebContentsImplTestBrowserClient browser_client
;
697 SetBrowserClientForTesting(&browser_client
);
699 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
700 int orig_rvh_delete_count
= 0;
701 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
702 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
704 browser_client
.set_assign_site_for_url(false);
705 // Navigate to an URL that will not assign a new SiteInstance.
706 const GURL
native_url("non-site-url://stuffandthings");
707 controller().LoadURL(
708 native_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
709 contents()->GetMainFrame()->PrepareForCommit();
710 contents()->TestDidNavigate(
711 orig_rfh
, 1, native_url
, ui::PAGE_TRANSITION_TYPED
);
713 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
714 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
715 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
716 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
717 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
718 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
719 EXPECT_FALSE(orig_instance
->HasSite());
721 browser_client
.set_assign_site_for_url(true);
722 // Navigate to new site (should keep same site instance).
723 const GURL
url("http://www.google.com");
724 controller().LoadURL(
725 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
726 contents()->GetMainFrame()->PrepareForCommit();
727 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
728 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
729 EXPECT_EQ(url
, contents()->GetVisibleURL());
730 EXPECT_FALSE(contents()->GetPendingMainFrame());
731 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
733 // Keep the number of active frames in orig_rfh's SiteInstance
734 // non-zero so that orig_rfh doesn't get deleted when it gets
736 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
738 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
740 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
741 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
743 // Navigate to another new site (should create a new site instance).
744 const GURL
url2("http://www.yahoo.com");
745 controller().LoadURL(
746 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
747 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
748 switches::kEnableBrowserSideNavigation
)) {
749 orig_rfh
->PrepareForCommit();
751 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
752 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
753 EXPECT_EQ(url2
, contents()->GetVisibleURL());
754 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
755 int pending_rvh_delete_count
= 0;
756 pending_rfh
->GetRenderViewHost()->set_delete_counter(
757 &pending_rvh_delete_count
);
759 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
760 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
761 switches::kEnableBrowserSideNavigation
)) {
762 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
763 orig_rfh
->SendBeforeUnloadACK(true);
764 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
767 // DidNavigate from the pending page.
768 contents()->TestDidNavigate(
769 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
770 SiteInstance
* new_instance
= contents()->GetSiteInstance();
772 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
773 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
774 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
775 EXPECT_EQ(url2
, contents()->GetVisibleURL());
776 EXPECT_NE(new_instance
, orig_instance
);
777 EXPECT_FALSE(contents()->GetPendingMainFrame());
778 // We keep the original RFH around, swapped out.
779 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
781 EXPECT_EQ(orig_rvh_delete_count
, 0);
782 orig_rfh
->OnSwappedOut();
784 // Close contents and ensure RVHs are deleted.
786 EXPECT_EQ(orig_rvh_delete_count
, 1);
787 EXPECT_EQ(pending_rvh_delete_count
, 1);
790 // Regression test for http://crbug.com/386542 - variation of
791 // NavigateFromSitelessUrl in which the original navigation is a session
793 TEST_F(WebContentsImplTest
, NavigateFromRestoredSitelessUrl
) {
794 WebContentsImplTestBrowserClient browser_client
;
795 SetBrowserClientForTesting(&browser_client
);
796 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
797 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
799 // Restore a navigation entry for URL that should not assign site to the
801 browser_client
.set_assign_site_for_url(false);
802 const GURL
native_url("non-site-url://stuffandthings");
803 std::vector
<NavigationEntry
*> entries
;
804 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
805 native_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false, std::string(),
808 entries
.push_back(entry
);
809 controller().Restore(
811 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
813 ASSERT_EQ(0u, entries
.size());
814 ASSERT_EQ(1, controller().GetEntryCount());
815 controller().GoToIndex(0);
816 orig_rfh
->PrepareForCommit();
817 contents()->TestDidNavigate(
818 orig_rfh
, 0, native_url
, ui::PAGE_TRANSITION_RELOAD
);
819 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
820 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
821 EXPECT_FALSE(orig_instance
->HasSite());
823 // Navigate to a regular site and verify that the SiteInstance was kept.
824 browser_client
.set_assign_site_for_url(true);
825 const GURL
url("http://www.google.com");
826 controller().LoadURL(
827 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
828 orig_rfh
->PrepareForCommit();
829 contents()->TestDidNavigate(orig_rfh
, 2, url
, ui::PAGE_TRANSITION_TYPED
);
830 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
836 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
837 // tab is restored, the SiteInstance will change upon navigation.
838 TEST_F(WebContentsImplTest
, NavigateFromRestoredRegularUrl
) {
839 WebContentsImplTestBrowserClient browser_client
;
840 SetBrowserClientForTesting(&browser_client
);
841 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
842 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
844 // Restore a navigation entry for a regular URL ensuring that the embedder
845 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
846 browser_client
.set_assign_site_for_url(true);
847 const GURL
regular_url("http://www.yahoo.com");
848 std::vector
<NavigationEntry
*> entries
;
849 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
850 regular_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false, std::string(),
853 entries
.push_back(entry
);
854 controller().Restore(
856 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
858 ASSERT_EQ(0u, entries
.size());
859 ASSERT_EQ(1, controller().GetEntryCount());
860 controller().GoToIndex(0);
861 orig_rfh
->PrepareForCommit();
862 contents()->TestDidNavigate(
863 orig_rfh
, 0, regular_url
, ui::PAGE_TRANSITION_RELOAD
);
864 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
865 EXPECT_TRUE(orig_instance
->HasSite());
867 // Navigate to another site and verify that a new SiteInstance was created.
868 const GURL
url("http://www.google.com");
869 controller().LoadURL(
870 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
871 orig_rfh
->PrepareForCommit();
872 contents()->TestDidNavigate(
873 contents()->GetPendingMainFrame(), 2, url
, ui::PAGE_TRANSITION_TYPED
);
874 EXPECT_NE(orig_instance
, contents()->GetSiteInstance());
880 // Test that we can find an opener RVH even if it's pending.
881 // http://crbug.com/176252.
882 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
883 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
885 // Navigate to a URL.
886 const GURL
url("http://www.google.com");
887 controller().LoadURL(
888 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
889 orig_rfh
->PrepareForCommit();
890 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
892 // Start to navigate first tab to a new site, so that it has a pending RVH.
893 const GURL
url2("http://www.yahoo.com");
894 controller().LoadURL(
895 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
896 orig_rfh
->PrepareForCommit();
897 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
899 // While it is still pending, simulate opening a new tab with the first tab
900 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
901 // on the opener to ensure that an RVH exists.
902 int opener_routing_id
=
903 contents()->CreateOpenerRenderViews(pending_rfh
->GetSiteInstance());
905 // We should find the pending RVH and not create a new one.
906 EXPECT_EQ(pending_rfh
->GetRenderViewHost()->GetRoutingID(),
910 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
911 // to determine whether a navigation is cross-site.
912 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
913 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
914 SiteInstance
* instance1
= contents()->GetSiteInstance();
917 const GURL
url("http://www.google.com");
918 controller().LoadURL(
919 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
920 contents()->GetMainFrame()->PrepareForCommit();
921 contents()->TestDidNavigate(
922 orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
924 // Open a related contents to a second site.
925 scoped_ptr
<TestWebContents
> contents2(
926 TestWebContents::Create(browser_context(), instance1
));
927 const GURL
url2("http://www.yahoo.com");
928 contents2
->GetController().LoadURL(url2
, Referrer(),
929 ui::PAGE_TRANSITION_TYPED
,
931 contents2
->GetMainFrame()->PrepareForCommit();
932 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
934 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
935 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
936 contents2
->TestDidNavigate(rfh2
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
937 SiteInstance
* instance2
= contents2
->GetSiteInstance();
938 EXPECT_NE(instance1
, instance2
);
939 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
941 // Simulate a link click in first contents to second site. Doesn't switch
942 // SiteInstances, because we don't intercept Blink navigations.
943 orig_rfh
->SendRendererInitiatedNavigationRequest(url2
, true);
944 orig_rfh
->PrepareForCommit();
945 contents()->TestDidNavigate(
946 orig_rfh
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
947 SiteInstance
* instance3
= contents()->GetSiteInstance();
948 EXPECT_EQ(instance1
, instance3
);
949 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
951 // Navigate to the new site. Doesn't switch SiteInstancees, because we
952 // compare against the current URL, not the SiteInstance's site.
953 const GURL
url3("http://mail.yahoo.com");
954 controller().LoadURL(
955 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
956 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
957 contents()->GetMainFrame()->PrepareForCommit();
958 contents()->TestDidNavigate(
959 orig_rfh
, 3, url3
, ui::PAGE_TRANSITION_TYPED
);
960 SiteInstance
* instance4
= contents()->GetSiteInstance();
961 EXPECT_EQ(instance1
, instance4
);
964 // Test that the onbeforeunload and onunload handlers run when navigating
965 // across site boundaries.
966 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
967 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
968 SiteInstance
* instance1
= contents()->GetSiteInstance();
970 // Navigate to URL. First URL should use first RenderViewHost.
971 const GURL
url("http://www.google.com");
972 controller().LoadURL(
973 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
974 contents()->GetMainFrame()->PrepareForCommit();
975 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
976 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
977 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
979 // Navigate to new site, but simulate an onbeforeunload denial.
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
->IsWaitingForBeforeUnloadACK());
984 base::TimeTicks now
= base::TimeTicks::Now();
985 orig_rfh
->OnMessageReceived(
986 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
987 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
988 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
989 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
991 // Navigate again, but simulate an onbeforeunload approval.
992 controller().LoadURL(
993 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
994 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
995 now
= base::TimeTicks::Now();
996 orig_rfh
->PrepareForCommit();
997 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
998 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
999 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1001 // We won't hear DidNavigate until the onunload handler has finished running.
1003 // DidNavigate from the pending page.
1004 contents()->TestDidNavigate(
1005 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1006 SiteInstance
* instance2
= contents()->GetSiteInstance();
1007 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1008 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1009 EXPECT_NE(instance1
, instance2
);
1010 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1013 // Test that during a slow cross-site navigation, the original renderer can
1014 // navigate to a different URL and have it displayed, canceling the slow
1016 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
1017 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1018 SiteInstance
* instance1
= contents()->GetSiteInstance();
1020 // Navigate to URL. First URL should use first RenderFrameHost.
1021 const GURL
url("http://www.google.com");
1022 controller().LoadURL(
1023 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1024 contents()->GetMainFrame()->PrepareForCommit();
1025 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1026 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1027 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1029 // Navigate to new site, simulating an onbeforeunload approval.
1030 const GURL
url2("http://www.yahoo.com");
1031 controller().LoadURL(
1032 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1033 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1034 orig_rfh
->PrepareForCommit();
1035 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1037 // Suppose the original renderer navigates before the new one is ready.
1038 orig_rfh
->SendNavigate(2, GURL("http://www.google.com/foo"));
1040 // Verify that the pending navigation is cancelled.
1041 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1042 SiteInstance
* instance2
= contents()->GetSiteInstance();
1043 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1044 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1045 EXPECT_EQ(instance1
, instance2
);
1046 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1049 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1050 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1051 const GURL
url1("chrome://blah");
1052 controller().LoadURL(
1053 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1054 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
1055 ntp_rfh
->PrepareForCommit();
1056 contents()->TestDidNavigate(ntp_rfh
, 1, url1
, ui::PAGE_TRANSITION_TYPED
);
1057 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1058 SiteInstance
* instance1
= contents()->GetSiteInstance();
1060 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1061 EXPECT_EQ(ntp_rfh
, contents()->GetMainFrame());
1062 EXPECT_EQ(url1
, entry1
->GetURL());
1063 EXPECT_EQ(instance1
,
1064 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1065 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1066 BINDINGS_POLICY_WEB_UI
);
1068 // Navigate to new site.
1069 const GURL
url2("http://www.google.com");
1070 controller().LoadURL(
1071 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1072 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1073 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1075 // Simulate beforeunload approval.
1076 EXPECT_TRUE(ntp_rfh
->IsWaitingForBeforeUnloadACK());
1077 base::TimeTicks now
= base::TimeTicks::Now();
1078 ntp_rfh
->PrepareForCommit();
1080 // DidNavigate from the pending page.
1081 contents()->TestDidNavigate(
1082 google_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1083 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1084 SiteInstance
* instance2
= contents()->GetSiteInstance();
1086 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1087 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1088 EXPECT_NE(instance1
, instance2
);
1089 EXPECT_FALSE(contents()->GetPendingMainFrame());
1090 EXPECT_EQ(url2
, entry2
->GetURL());
1091 EXPECT_EQ(instance2
,
1092 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1093 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1094 BINDINGS_POLICY_WEB_UI
);
1096 // Navigate to third page on same site.
1097 const GURL
url3("http://news.google.com");
1098 controller().LoadURL(
1099 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1100 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1101 contents()->GetMainFrame()->PrepareForCommit();
1102 contents()->TestDidNavigate(
1103 google_rfh
, 2, url3
, ui::PAGE_TRANSITION_TYPED
);
1104 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1105 SiteInstance
* instance3
= contents()->GetSiteInstance();
1107 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1108 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1109 EXPECT_EQ(instance2
, instance3
);
1110 EXPECT_FALSE(contents()->GetPendingMainFrame());
1111 EXPECT_EQ(url3
, entry3
->GetURL());
1112 EXPECT_EQ(instance3
,
1113 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1115 // Go back within the site.
1116 controller().GoBack();
1117 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1118 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1120 // Before that commits, go back again.
1121 controller().GoBack();
1122 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1123 EXPECT_TRUE(contents()->GetPendingMainFrame());
1124 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1126 // Simulate beforeunload approval.
1127 EXPECT_TRUE(google_rfh
->IsWaitingForBeforeUnloadACK());
1128 now
= base::TimeTicks::Now();
1129 google_rfh
->PrepareForCommit();
1130 google_rfh
->OnMessageReceived(
1131 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1133 // DidNavigate from the first back. This aborts the second back's pending RFH.
1134 contents()->TestDidNavigate(google_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1136 // We should commit this page and forget about the second back.
1137 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1138 EXPECT_FALSE(controller().GetPendingEntry());
1139 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1140 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1142 // We should not have corrupted the NTP entry.
1143 EXPECT_EQ(instance3
,
1144 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1145 EXPECT_EQ(instance2
,
1146 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1147 EXPECT_EQ(instance1
,
1148 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1149 EXPECT_EQ(url1
, entry1
->GetURL());
1152 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1153 // original renderer will not cancel the slow navigation (bug 42029).
1154 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1155 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1157 // Navigate to URL. First URL should use the original RenderFrameHost.
1158 const GURL
url("http://www.google.com");
1159 controller().LoadURL(
1160 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1161 contents()->GetMainFrame()->PrepareForCommit();
1162 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1163 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1164 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1166 // Start navigating to new site.
1167 const GURL
url2("http://www.yahoo.com");
1168 controller().LoadURL(
1169 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1171 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1172 // waiting for a before unload response.
1173 TestRenderFrameHost
* child_rfh
= orig_rfh
->AppendChild("subframe");
1174 child_rfh
->SendNavigateWithTransition(
1175 1, GURL("http://google.com/frame"), ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
1176 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1178 // Now simulate the onbeforeunload approval and verify the navigation is
1180 orig_rfh
->PrepareForCommit();
1181 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1182 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1185 // Test that a cross-site navigation is not preempted if the previous
1186 // renderer sends a FrameNavigate message just before being told to stop.
1187 // We should only preempt the cross-site navigation if the previous renderer
1188 // has started a new navigation. See http://crbug.com/79176.
1189 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1190 // Navigate to NTP URL.
1191 const GURL
url("chrome://blah");
1192 controller().LoadURL(
1193 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1194 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1195 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1197 // Navigate to new site, with the beforeunload request in flight.
1198 const GURL
url2("http://www.yahoo.com");
1199 controller().LoadURL(
1200 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1201 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1202 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1203 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1205 // Suppose the first navigation tries to commit now, with a
1206 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1207 // but it should act as if the beforeunload ack arrived.
1208 orig_rfh
->SendNavigate(1, GURL("chrome://blah"));
1209 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1210 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1211 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1213 // The pending navigation should be able to commit successfully.
1214 contents()->TestDidNavigate(pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1215 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1216 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1219 // Test that NavigationEntries have the correct page state after going
1220 // forward and back. Prevents regression for bug 1116137.
1221 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1222 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1224 // Navigate to URL. There should be no committed entry yet.
1225 const GURL
url("http://www.google.com");
1226 controller().LoadURL(
1227 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1228 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1229 EXPECT_EQ(nullptr, entry
);
1231 // Committed entry should have page state after DidNavigate.
1232 orig_rfh
->PrepareForCommit();
1233 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1234 entry
= controller().GetLastCommittedEntry();
1235 EXPECT_TRUE(entry
->GetPageState().IsValid());
1237 // Navigate to same site.
1238 const GURL
url2("http://images.google.com");
1239 controller().LoadURL(
1240 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1241 entry
= controller().GetLastCommittedEntry();
1242 EXPECT_TRUE(entry
->GetPageState().IsValid());
1244 // Committed entry should have page state after DidNavigate.
1245 orig_rfh
->PrepareForCommit();
1246 contents()->TestDidNavigate(orig_rfh
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
1247 entry
= controller().GetLastCommittedEntry();
1248 EXPECT_TRUE(entry
->GetPageState().IsValid());
1250 // Now go back. Committed entry should still have page state.
1251 controller().GoBack();
1252 orig_rfh
->PrepareForCommit();
1253 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1254 entry
= controller().GetLastCommittedEntry();
1255 EXPECT_TRUE(entry
->GetPageState().IsValid());
1258 // Test that NavigationEntries have the correct page state and SiteInstance
1259 // state after opening a new window to about:blank. Prevents regression for
1260 // bugs b/1116137 and http://crbug.com/111975.
1261 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1262 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1264 // When opening a new window, it is navigated to about:blank internally.
1265 // Currently, this results in two DidNavigate events.
1266 const GURL
url(url::kAboutBlankURL
);
1267 orig_rfh
->SendRendererInitiatedNavigationRequest(url
, false);
1268 orig_rfh
->PrepareForCommit();
1269 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1270 orig_rfh
->SendRendererInitiatedNavigationRequest(url
, false);
1271 orig_rfh
->PrepareForCommit();
1272 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1274 // Should have a page state here.
1275 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1276 EXPECT_TRUE(entry
->GetPageState().IsValid());
1278 // The SiteInstance should be available for other navigations to use.
1279 NavigationEntryImpl
* entry_impl
=
1280 NavigationEntryImpl::FromNavigationEntry(entry
);
1281 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1282 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1284 // Navigating to a normal page should not cause a process swap.
1285 const GURL
new_url("http://www.google.com");
1286 controller().LoadURL(new_url
, Referrer(),
1287 ui::PAGE_TRANSITION_TYPED
, std::string());
1288 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1289 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1290 orig_rfh
->PrepareForCommit();
1291 contents()->TestDidNavigate(orig_rfh
, 1, new_url
, ui::PAGE_TRANSITION_TYPED
);
1292 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1293 controller().GetLastCommittedEntry());
1294 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1295 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1298 // Tests that fullscreen is exited throughout the object hierarchy when
1299 // navigating to a new page.
1300 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1301 FakeFullscreenDelegate fake_delegate
;
1302 contents()->SetDelegate(&fake_delegate
);
1303 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1304 TestRenderViewHost
* orig_rvh
= orig_rfh
->GetRenderViewHost();
1306 // Navigate to a site.
1307 const GURL
url("http://www.google.com");
1308 controller().LoadURL(
1309 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1310 contents()->GetMainFrame()->PrepareForCommit();
1311 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1312 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1314 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1315 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1316 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1317 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1318 orig_rfh
->OnMessageReceived(
1319 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1320 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1321 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1322 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1324 // Navigate to a new site.
1325 const GURL
url2("http://www.yahoo.com");
1326 controller().LoadURL(
1327 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1328 contents()->GetMainFrame()->PrepareForCommit();
1329 TestRenderFrameHost
* const pending_rfh
= contents()->GetPendingMainFrame();
1330 contents()->TestDidNavigate(
1331 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1333 // Confirm fullscreen has exited.
1334 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1335 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1336 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1338 contents()->SetDelegate(nullptr);
1341 // Tests that fullscreen is exited throughout the object hierarchy when
1342 // instructing NavigationController to GoBack() or GoForward().
1343 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1344 FakeFullscreenDelegate fake_delegate
;
1345 contents()->SetDelegate(&fake_delegate
);
1346 TestRenderFrameHost
* const orig_rfh
= contents()->GetMainFrame();
1347 TestRenderViewHost
* const orig_rvh
= orig_rfh
->GetRenderViewHost();
1349 // Navigate to a site.
1350 const GURL
url("http://www.google.com");
1351 controller().LoadURL(
1352 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1353 orig_rfh
->PrepareForCommit();
1354 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1355 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1357 // Now, navigate to another page on the same site.
1358 const GURL
url2("http://www.google.com/search?q=kittens");
1359 controller().LoadURL(
1360 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1361 orig_rfh
->PrepareForCommit();
1362 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1363 contents()->TestDidNavigate(orig_rfh
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
1364 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1366 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1367 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1368 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1369 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1371 for (int i
= 0; i
< 2; ++i
) {
1372 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1373 orig_rfh
->OnMessageReceived(
1374 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1375 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1376 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1377 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1379 // Navigate backward (or forward).
1381 controller().GoBack();
1383 controller().GoForward();
1384 orig_rfh
->PrepareForCommit();
1385 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1386 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1387 contents()->TestDidNavigate(
1388 orig_rfh
, i
+ 1, url
, ui::PAGE_TRANSITION_FORWARD_BACK
);
1390 // Confirm fullscreen has exited.
1391 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1392 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1393 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1396 contents()->SetDelegate(nullptr);
1399 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1400 FakeValidationMessageDelegate fake_delegate
;
1401 contents()->SetDelegate(&fake_delegate
);
1402 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1404 // Crash the renderer.
1405 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1407 // Confirm HideValidationMessage was called.
1408 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1410 contents()->SetDelegate(nullptr);
1413 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1415 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1416 FakeFullscreenDelegate fake_delegate
;
1417 contents()->SetDelegate(&fake_delegate
);
1419 // Navigate to a site.
1420 const GURL
url("http://www.google.com");
1421 controller().LoadURL(
1422 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1423 main_test_rfh()->PrepareForCommit();
1424 contents()->TestDidNavigate(
1425 contents()->GetMainFrame(), 1, url
, ui::PAGE_TRANSITION_TYPED
);
1427 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1428 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1429 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1430 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1431 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1432 contents()->GetMainFrame()->GetRoutingID(), true));
1433 EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
1434 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1435 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1437 // Crash the renderer.
1438 main_test_rfh()->GetProcess()->SimulateCrash();
1440 // Confirm fullscreen has exited.
1441 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1442 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1443 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1445 contents()->SetDelegate(nullptr);
1448 ////////////////////////////////////////////////////////////////////////////////
1449 // Interstitial Tests
1450 ////////////////////////////////////////////////////////////////////////////////
1452 // Test navigating to a page (with the navigation initiated from the browser,
1453 // as when a URL is typed in the location bar) that shows an interstitial and
1454 // creates a new navigation entry, then hiding it without proceeding.
1455 TEST_F(WebContentsImplTest
,
1456 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1457 // Navigate to a page.
1458 GURL
url1("http://www.google.com");
1459 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1460 EXPECT_EQ(1, controller().GetEntryCount());
1462 // Initiate a browser navigation that will trigger the interstitial
1463 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1464 ui::PAGE_TRANSITION_TYPED
, std::string());
1466 // Show an interstitial.
1467 TestInterstitialPage::InterstitialState state
=
1468 TestInterstitialPage::INVALID
;
1469 bool deleted
= false;
1470 GURL
url2("http://interstitial");
1471 TestInterstitialPage
* interstitial
=
1472 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1473 TestInterstitialPageStateGuard
state_guard(interstitial
);
1474 interstitial
->Show();
1475 // The interstitial should not show until its navigation has committed.
1476 EXPECT_FALSE(interstitial
->is_showing());
1477 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1478 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1479 // Let's commit the interstitial navigation.
1480 interstitial
->TestDidNavigate(1, url2
);
1481 EXPECT_TRUE(interstitial
->is_showing());
1482 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1483 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1484 NavigationEntry
* entry
= controller().GetVisibleEntry();
1485 ASSERT_NE(nullptr, entry
);
1486 EXPECT_TRUE(entry
->GetURL() == url2
);
1488 // Now don't proceed.
1489 interstitial
->DontProceed();
1490 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1491 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1492 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1493 entry
= controller().GetVisibleEntry();
1494 ASSERT_NE(nullptr, entry
);
1495 EXPECT_TRUE(entry
->GetURL() == url1
);
1496 EXPECT_EQ(1, controller().GetEntryCount());
1498 RunAllPendingInMessageLoop();
1499 EXPECT_TRUE(deleted
);
1502 // Test navigating to a page (with the navigation initiated from the renderer,
1503 // as when clicking on a link in the page) that shows an interstitial and
1504 // creates a new navigation entry, then hiding it without proceeding.
1505 TEST_F(WebContentsImplTest
,
1506 ShowInterstitiaFromRendererlWithNewNavigationDontProceed
) {
1507 // Navigate to a page.
1508 GURL
url1("http://www.google.com");
1509 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1510 EXPECT_EQ(1, controller().GetEntryCount());
1512 // Show an interstitial (no pending entry, the interstitial would have been
1513 // triggered by clicking on a link).
1514 TestInterstitialPage::InterstitialState state
=
1515 TestInterstitialPage::INVALID
;
1516 bool deleted
= false;
1517 GURL
url2("http://interstitial");
1518 TestInterstitialPage
* interstitial
=
1519 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1520 TestInterstitialPageStateGuard
state_guard(interstitial
);
1521 interstitial
->Show();
1522 // The interstitial should not show until its navigation has committed.
1523 EXPECT_FALSE(interstitial
->is_showing());
1524 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1525 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1526 // Let's commit the interstitial navigation.
1527 interstitial
->TestDidNavigate(1, url2
);
1528 EXPECT_TRUE(interstitial
->is_showing());
1529 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1530 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1531 NavigationEntry
* entry
= controller().GetVisibleEntry();
1532 ASSERT_NE(nullptr, entry
);
1533 EXPECT_TRUE(entry
->GetURL() == url2
);
1535 // Now don't proceed.
1536 interstitial
->DontProceed();
1537 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1538 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1539 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1540 entry
= controller().GetVisibleEntry();
1541 ASSERT_NE(nullptr, entry
);
1542 EXPECT_TRUE(entry
->GetURL() == url1
);
1543 EXPECT_EQ(1, controller().GetEntryCount());
1545 RunAllPendingInMessageLoop();
1546 EXPECT_TRUE(deleted
);
1549 // Test navigating to a page that shows an interstitial without creating a new
1550 // navigation entry (this happens when the interstitial is triggered by a
1551 // sub-resource in the page), then hiding it without proceeding.
1552 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1553 // Navigate to a page.
1554 GURL
url1("http://www.google.com");
1555 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1556 EXPECT_EQ(1, controller().GetEntryCount());
1558 // Show an interstitial.
1559 TestInterstitialPage::InterstitialState state
=
1560 TestInterstitialPage::INVALID
;
1561 bool deleted
= false;
1562 GURL
url2("http://interstitial");
1563 TestInterstitialPage
* interstitial
=
1564 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1565 TestInterstitialPageStateGuard
state_guard(interstitial
);
1566 interstitial
->Show();
1567 // The interstitial should not show until its navigation has committed.
1568 EXPECT_FALSE(interstitial
->is_showing());
1569 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1570 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1571 // Let's commit the interstitial navigation.
1572 interstitial
->TestDidNavigate(1, url2
);
1573 EXPECT_TRUE(interstitial
->is_showing());
1574 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1575 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1576 NavigationEntry
* entry
= controller().GetVisibleEntry();
1577 ASSERT_NE(nullptr, entry
);
1578 // The URL specified to the interstitial should have been ignored.
1579 EXPECT_TRUE(entry
->GetURL() == url1
);
1581 // Now don't proceed.
1582 interstitial
->DontProceed();
1583 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1584 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1585 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1586 entry
= controller().GetVisibleEntry();
1587 ASSERT_NE(nullptr, entry
);
1588 EXPECT_TRUE(entry
->GetURL() == url1
);
1589 EXPECT_EQ(1, controller().GetEntryCount());
1591 RunAllPendingInMessageLoop();
1592 EXPECT_TRUE(deleted
);
1595 // Test navigating to a page (with the navigation initiated from the browser,
1596 // as when a URL is typed in the location bar) that shows an interstitial and
1597 // creates a new navigation entry, then proceeding.
1598 TEST_F(WebContentsImplTest
,
1599 ShowInterstitialFromBrowserNewNavigationProceed
) {
1600 // Navigate to a page.
1601 GURL
url1("http://www.google.com");
1602 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1603 EXPECT_EQ(1, controller().GetEntryCount());
1605 // Initiate a browser navigation that will trigger the interstitial
1606 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1607 ui::PAGE_TRANSITION_TYPED
, std::string());
1609 // Show an interstitial.
1610 TestInterstitialPage::InterstitialState state
=
1611 TestInterstitialPage::INVALID
;
1612 bool deleted
= false;
1613 GURL
url2("http://interstitial");
1614 TestInterstitialPage
* interstitial
=
1615 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1616 TestInterstitialPageStateGuard
state_guard(interstitial
);
1617 interstitial
->Show();
1618 // The interstitial should not show until its navigation has committed.
1619 EXPECT_FALSE(interstitial
->is_showing());
1620 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1621 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1622 // Let's commit the interstitial navigation.
1623 interstitial
->TestDidNavigate(1, url2
);
1624 EXPECT_TRUE(interstitial
->is_showing());
1625 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1626 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1627 NavigationEntry
* entry
= controller().GetVisibleEntry();
1628 ASSERT_NE(nullptr, entry
);
1629 EXPECT_TRUE(entry
->GetURL() == url2
);
1632 interstitial
->Proceed();
1633 // The interstitial should show until the new navigation commits.
1634 RunAllPendingInMessageLoop();
1635 ASSERT_FALSE(deleted
);
1636 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1637 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1638 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1640 // Simulate the navigation to the page, that's when the interstitial gets
1642 GURL
url3("http://www.thepage.com");
1643 contents()->GetMainFrame()->SendNavigate(2, url3
);
1645 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1646 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1647 entry
= controller().GetVisibleEntry();
1648 ASSERT_NE(nullptr, entry
);
1649 EXPECT_TRUE(entry
->GetURL() == url3
);
1651 EXPECT_EQ(2, controller().GetEntryCount());
1653 RunAllPendingInMessageLoop();
1654 EXPECT_TRUE(deleted
);
1657 // Test navigating to a page (with the navigation initiated from the renderer,
1658 // as when clicking on a link in the page) that shows an interstitial and
1659 // creates a new navigation entry, then proceeding.
1660 TEST_F(WebContentsImplTest
,
1661 ShowInterstitialFromRendererNewNavigationProceed
) {
1662 // Navigate to a page.
1663 GURL
url1("http://www.google.com");
1664 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1665 EXPECT_EQ(1, controller().GetEntryCount());
1667 // Show an interstitial.
1668 TestInterstitialPage::InterstitialState state
=
1669 TestInterstitialPage::INVALID
;
1670 bool deleted
= false;
1671 GURL
url2("http://interstitial");
1672 TestInterstitialPage
* interstitial
=
1673 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1674 TestInterstitialPageStateGuard
state_guard(interstitial
);
1675 interstitial
->Show();
1676 // The interstitial should not show until its navigation has committed.
1677 EXPECT_FALSE(interstitial
->is_showing());
1678 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1679 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1680 // Let's commit the interstitial navigation.
1681 interstitial
->TestDidNavigate(1, url2
);
1682 EXPECT_TRUE(interstitial
->is_showing());
1683 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1684 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1685 NavigationEntry
* entry
= controller().GetVisibleEntry();
1686 ASSERT_NE(nullptr, entry
);
1687 EXPECT_TRUE(entry
->GetURL() == url2
);
1690 interstitial
->Proceed();
1691 // The interstitial should show until the new navigation commits.
1692 RunAllPendingInMessageLoop();
1693 ASSERT_FALSE(deleted
);
1694 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1695 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1696 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1698 // Simulate the navigation to the page, that's when the interstitial gets
1700 GURL
url3("http://www.thepage.com");
1701 main_test_rfh()->NavigateAndCommitRendererInitiated(2, url3
);
1703 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1704 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1705 entry
= controller().GetVisibleEntry();
1706 ASSERT_NE(nullptr, entry
);
1707 EXPECT_TRUE(entry
->GetURL() == url3
);
1709 EXPECT_EQ(2, controller().GetEntryCount());
1711 RunAllPendingInMessageLoop();
1712 EXPECT_TRUE(deleted
);
1715 // Test navigating to a page that shows an interstitial without creating a new
1716 // navigation entry (this happens when the interstitial is triggered by a
1717 // sub-resource in the page), then proceeding.
1718 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1719 // Navigate to a page so we have a navigation entry in the controller.
1720 GURL
url1("http://www.google.com");
1721 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1722 EXPECT_EQ(1, controller().GetEntryCount());
1724 // Show an interstitial.
1725 TestInterstitialPage::InterstitialState state
=
1726 TestInterstitialPage::INVALID
;
1727 bool deleted
= false;
1728 GURL
url2("http://interstitial");
1729 TestInterstitialPage
* interstitial
=
1730 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1731 TestInterstitialPageStateGuard
state_guard(interstitial
);
1732 interstitial
->Show();
1733 // The interstitial should not show until its navigation has committed.
1734 EXPECT_FALSE(interstitial
->is_showing());
1735 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1736 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1737 // Let's commit the interstitial navigation.
1738 interstitial
->TestDidNavigate(1, url2
);
1739 EXPECT_TRUE(interstitial
->is_showing());
1740 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1741 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1742 NavigationEntry
* entry
= controller().GetVisibleEntry();
1743 ASSERT_NE(nullptr, entry
);
1744 // The URL specified to the interstitial should have been ignored.
1745 EXPECT_TRUE(entry
->GetURL() == url1
);
1748 interstitial
->Proceed();
1749 // Since this is not a new navigation, the previous page is dismissed right
1750 // away and shows the original page.
1751 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1752 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1753 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1754 entry
= controller().GetVisibleEntry();
1755 ASSERT_NE(nullptr, entry
);
1756 EXPECT_TRUE(entry
->GetURL() == url1
);
1758 EXPECT_EQ(1, controller().GetEntryCount());
1760 RunAllPendingInMessageLoop();
1761 EXPECT_TRUE(deleted
);
1764 // Test navigating to a page that shows an interstitial, then navigating away.
1765 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1766 // Show interstitial.
1767 TestInterstitialPage::InterstitialState state
=
1768 TestInterstitialPage::INVALID
;
1769 bool deleted
= false;
1770 GURL
url("http://interstitial");
1771 TestInterstitialPage
* interstitial
=
1772 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1773 TestInterstitialPageStateGuard
state_guard(interstitial
);
1774 interstitial
->Show();
1775 interstitial
->TestDidNavigate(1, url
);
1777 // While interstitial showing, navigate to a new URL.
1778 const GURL
url2("http://www.yahoo.com");
1779 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url2
);
1781 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1783 RunAllPendingInMessageLoop();
1784 EXPECT_TRUE(deleted
);
1787 // Test navigating to a page that shows an interstitial, then going back.
1788 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1789 // Navigate to a page so we have a navigation entry in the controller.
1790 GURL
url1("http://www.google.com");
1791 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1792 EXPECT_EQ(1, controller().GetEntryCount());
1794 // Show interstitial.
1795 TestInterstitialPage::InterstitialState state
=
1796 TestInterstitialPage::INVALID
;
1797 bool deleted
= false;
1798 GURL
interstitial_url("http://interstitial");
1799 TestInterstitialPage
* interstitial
=
1800 new TestInterstitialPage(contents(), true, interstitial_url
,
1802 TestInterstitialPageStateGuard
state_guard(interstitial
);
1803 interstitial
->Show();
1804 interstitial
->TestDidNavigate(2, interstitial_url
);
1806 // While the interstitial is showing, go back.
1807 controller().GoBack();
1808 main_test_rfh()->PrepareForCommit();
1809 contents()->GetMainFrame()->SendNavigate(1, url1
);
1811 // Make sure we are back to the original page and that the interstitial is
1813 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1814 NavigationEntry
* entry
= controller().GetVisibleEntry();
1816 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1818 RunAllPendingInMessageLoop();
1819 EXPECT_TRUE(deleted
);
1822 // Test navigating to a page that shows an interstitial, has a renderer crash,
1823 // and then goes back.
1824 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1825 // Navigate to a page so we have a navigation entry in the controller.
1826 GURL
url1("http://www.google.com");
1827 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1828 EXPECT_EQ(1, controller().GetEntryCount());
1830 // Show interstitial.
1831 TestInterstitialPage::InterstitialState state
=
1832 TestInterstitialPage::INVALID
;
1833 bool deleted
= false;
1834 GURL
interstitial_url("http://interstitial");
1835 TestInterstitialPage
* interstitial
=
1836 new TestInterstitialPage(contents(), true, interstitial_url
,
1838 TestInterstitialPageStateGuard
state_guard(interstitial
);
1839 interstitial
->Show();
1840 interstitial
->TestDidNavigate(2, interstitial_url
);
1842 // Crash the renderer
1843 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1845 // While the interstitial is showing, go back.
1846 controller().GoBack();
1847 main_test_rfh()->PrepareForCommit();
1848 contents()->GetMainFrame()->SendNavigate(1, url1
);
1850 // Make sure we are back to the original page and that the interstitial is
1852 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1853 NavigationEntry
* entry
= controller().GetVisibleEntry();
1855 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1857 RunAllPendingInMessageLoop();
1858 EXPECT_TRUE(deleted
);
1861 // Test navigating to a page that shows an interstitial, has the renderer crash,
1862 // and then navigates to the interstitial.
1863 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1864 // Navigate to a page so we have a navigation entry in the controller.
1865 GURL
url1("http://www.google.com");
1866 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1867 EXPECT_EQ(1, controller().GetEntryCount());
1869 // Show interstitial.
1870 TestInterstitialPage::InterstitialState state
=
1871 TestInterstitialPage::INVALID
;
1872 bool deleted
= false;
1873 GURL
interstitial_url("http://interstitial");
1874 TestInterstitialPage
* interstitial
=
1875 new TestInterstitialPage(contents(), true, interstitial_url
,
1877 TestInterstitialPageStateGuard
state_guard(interstitial
);
1878 interstitial
->Show();
1880 // Crash the renderer
1881 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1883 interstitial
->TestDidNavigate(2, interstitial_url
);
1886 // Test navigating to a page that shows an interstitial, then close the
1888 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1889 // Show interstitial.
1890 TestInterstitialPage::InterstitialState state
=
1891 TestInterstitialPage::INVALID
;
1892 bool deleted
= false;
1893 GURL
url("http://interstitial");
1894 TestInterstitialPage
* interstitial
=
1895 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1896 TestInterstitialPageStateGuard
state_guard(interstitial
);
1897 interstitial
->Show();
1898 interstitial
->TestDidNavigate(1, url
);
1900 // Now close the contents.
1902 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1904 RunAllPendingInMessageLoop();
1905 EXPECT_TRUE(deleted
);
1908 // Test navigating to a page that shows an interstitial, then close the
1910 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
1911 // Show interstitial.
1912 TestInterstitialPage::InterstitialState state
=
1913 TestInterstitialPage::INVALID
;
1914 bool deleted
= false;
1915 GURL
url("http://interstitial");
1916 TestInterstitialPage
* interstitial
=
1917 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1918 TestInterstitialPageStateGuard
state_guard(interstitial
);
1919 interstitial
->Show();
1920 interstitial
->TestDidNavigate(1, url
);
1921 TestRenderFrameHost
* rfh
=
1922 static_cast<TestRenderFrameHost
*>(interstitial
->GetMainFrame());
1924 // Now close the contents.
1926 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1928 // Before the interstitial has a chance to process its shutdown task,
1929 // simulate quitting the browser. This goes through all processes and
1930 // tells them to destruct.
1931 rfh
->GetProcess()->SimulateCrash();
1933 RunAllPendingInMessageLoop();
1934 EXPECT_TRUE(deleted
);
1937 // Test that after Proceed is called and an interstitial is still shown, no more
1938 // commands get executed.
1939 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
1940 // Navigate to a page so we have a navigation entry in the controller.
1941 GURL
url1("http://www.google.com");
1942 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
1943 EXPECT_EQ(1, controller().GetEntryCount());
1945 // Show an interstitial.
1946 TestInterstitialPage::InterstitialState state
=
1947 TestInterstitialPage::INVALID
;
1948 bool deleted
= false;
1949 GURL
url2("http://interstitial");
1950 TestInterstitialPage
* interstitial
=
1951 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1952 TestInterstitialPageStateGuard
state_guard(interstitial
);
1953 interstitial
->Show();
1954 interstitial
->TestDidNavigate(1, url2
);
1957 EXPECT_EQ(0, interstitial
->command_received_count());
1958 interstitial
->TestDomOperationResponse("toto");
1959 EXPECT_EQ(1, interstitial
->command_received_count());
1962 interstitial
->Proceed();
1963 RunAllPendingInMessageLoop();
1964 ASSERT_FALSE(deleted
);
1966 // While the navigation to the new page is pending, send other commands, they
1967 // should be ignored.
1968 interstitial
->TestDomOperationResponse("hello");
1969 interstitial
->TestDomOperationResponse("hi");
1970 EXPECT_EQ(1, interstitial
->command_received_count());
1973 // Test showing an interstitial while another interstitial is already showing.
1974 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
1975 // Navigate to a page so we have a navigation entry in the controller.
1976 GURL
start_url("http://www.google.com");
1977 main_test_rfh()->NavigateAndCommitRendererInitiated(1, start_url
);
1978 EXPECT_EQ(1, controller().GetEntryCount());
1980 // Show an interstitial.
1981 TestInterstitialPage::InterstitialState state1
=
1982 TestInterstitialPage::INVALID
;
1983 bool deleted1
= false;
1984 GURL
url1("http://interstitial1");
1985 TestInterstitialPage
* interstitial1
=
1986 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
1987 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
1988 interstitial1
->Show();
1989 interstitial1
->TestDidNavigate(1, url1
);
1991 // Now show another interstitial.
1992 TestInterstitialPage::InterstitialState state2
=
1993 TestInterstitialPage::INVALID
;
1994 bool deleted2
= false;
1995 GURL
url2("http://interstitial2");
1996 TestInterstitialPage
* interstitial2
=
1997 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
1998 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
1999 interstitial2
->Show();
2000 interstitial2
->TestDidNavigate(1, url2
);
2002 // Showing interstitial2 should have caused interstitial1 to go away.
2003 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2004 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2006 RunAllPendingInMessageLoop();
2007 EXPECT_TRUE(deleted1
);
2008 ASSERT_FALSE(deleted2
);
2010 // Let's make sure interstitial2 is working as intended.
2011 interstitial2
->Proceed();
2012 GURL
landing_url("http://www.thepage.com");
2013 contents()->GetMainFrame()->SendNavigate(2, landing_url
);
2015 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2016 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2017 NavigationEntry
* entry
= controller().GetVisibleEntry();
2018 ASSERT_NE(nullptr, entry
);
2019 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2020 EXPECT_EQ(2, controller().GetEntryCount());
2021 RunAllPendingInMessageLoop();
2022 EXPECT_TRUE(deleted2
);
2025 // Test showing an interstitial, proceeding and then navigating to another
2027 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2028 // Navigate to a page so we have a navigation entry in the controller.
2029 GURL
start_url("http://www.google.com");
2030 main_test_rfh()->NavigateAndCommitRendererInitiated(1, start_url
);
2031 EXPECT_EQ(1, controller().GetEntryCount());
2033 // Show an interstitial.
2034 TestInterstitialPage::InterstitialState state1
=
2035 TestInterstitialPage::INVALID
;
2036 bool deleted1
= false;
2037 GURL
url1("http://interstitial1");
2038 TestInterstitialPage
* interstitial1
=
2039 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2040 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2041 interstitial1
->Show();
2042 interstitial1
->TestDidNavigate(1, url1
);
2044 // Take action. The interstitial won't be hidden until the navigation is
2046 interstitial1
->Proceed();
2047 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2049 // Now show another interstitial (simulating the navigation causing another
2051 TestInterstitialPage::InterstitialState state2
=
2052 TestInterstitialPage::INVALID
;
2053 bool deleted2
= false;
2054 GURL
url2("http://interstitial2");
2055 TestInterstitialPage
* interstitial2
=
2056 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2057 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2058 interstitial2
->Show();
2059 interstitial2
->TestDidNavigate(1, url2
);
2061 // Showing interstitial2 should have caused interstitial1 to go away.
2062 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2063 RunAllPendingInMessageLoop();
2064 EXPECT_TRUE(deleted1
);
2065 ASSERT_FALSE(deleted2
);
2067 // Let's make sure interstitial2 is working as intended.
2068 interstitial2
->Proceed();
2069 GURL
landing_url("http://www.thepage.com");
2070 contents()->GetMainFrame()->SendNavigate(2, landing_url
);
2072 RunAllPendingInMessageLoop();
2073 EXPECT_TRUE(deleted2
);
2074 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2075 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2076 NavigationEntry
* entry
= controller().GetVisibleEntry();
2077 ASSERT_NE(nullptr, entry
);
2078 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2079 EXPECT_EQ(2, controller().GetEntryCount());
2082 // Test that navigating away from an interstitial while it's loading cause it
2084 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2085 // Show an interstitial.
2086 TestInterstitialPage::InterstitialState state
=
2087 TestInterstitialPage::INVALID
;
2088 bool deleted
= false;
2089 GURL
interstitial_url("http://interstitial");
2090 TestInterstitialPage
* interstitial
=
2091 new TestInterstitialPage(contents(), true, interstitial_url
,
2093 TestInterstitialPageStateGuard
state_guard(interstitial
);
2094 interstitial
->Show();
2096 // Let's simulate a navigation initiated from the browser before the
2097 // interstitial finishes loading.
2098 const GURL
url("http://www.google.com");
2099 controller().LoadURL(
2100 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2101 EXPECT_FALSE(interstitial
->is_showing());
2102 RunAllPendingInMessageLoop();
2103 ASSERT_FALSE(deleted
);
2105 // Now let's make the interstitial navigation commit.
2106 interstitial
->TestDidNavigate(1, interstitial_url
);
2108 // After it loaded the interstitial should be gone.
2109 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2111 RunAllPendingInMessageLoop();
2112 EXPECT_TRUE(deleted
);
2115 // Test that a new request to show an interstitial while an interstitial is
2116 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2117 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2118 GURL
interstitial_url("http://interstitial");
2120 // Show a first interstitial.
2121 TestInterstitialPage::InterstitialState state1
=
2122 TestInterstitialPage::INVALID
;
2123 bool deleted1
= false;
2124 TestInterstitialPage
* interstitial1
=
2125 new TestInterstitialPage(contents(), true, interstitial_url
,
2126 &state1
, &deleted1
);
2127 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2128 interstitial1
->Show();
2130 // Show another interstitial on that same contents before the first one had
2132 TestInterstitialPage::InterstitialState state2
=
2133 TestInterstitialPage::INVALID
;
2134 bool deleted2
= false;
2135 TestInterstitialPage
* interstitial2
=
2136 new TestInterstitialPage(contents(), true, interstitial_url
,
2137 &state2
, &deleted2
);
2138 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2139 interstitial2
->Show();
2141 // The first interstitial should have been closed and deleted.
2142 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2143 // The 2nd one should still be OK.
2144 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2146 RunAllPendingInMessageLoop();
2147 EXPECT_TRUE(deleted1
);
2148 ASSERT_FALSE(deleted2
);
2150 // Make the interstitial navigation commit it should be showing.
2151 interstitial2
->TestDidNavigate(1, interstitial_url
);
2152 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2155 // Test showing an interstitial and have its renderer crash.
2156 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2157 // Show an interstitial.
2158 TestInterstitialPage::InterstitialState state
=
2159 TestInterstitialPage::INVALID
;
2160 bool deleted
= false;
2161 GURL
url("http://interstitial");
2162 TestInterstitialPage
* interstitial
=
2163 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2164 TestInterstitialPageStateGuard
state_guard(interstitial
);
2165 interstitial
->Show();
2166 // Simulate a renderer crash before the interstitial is shown.
2167 interstitial
->TestRenderViewTerminated(
2168 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2169 // The interstitial should have been dismissed.
2170 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2171 RunAllPendingInMessageLoop();
2172 EXPECT_TRUE(deleted
);
2174 // Now try again but this time crash the intersitial after it was shown.
2176 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2177 interstitial
->Show();
2178 interstitial
->TestDidNavigate(1, url
);
2179 // Simulate a renderer crash.
2180 interstitial
->TestRenderViewTerminated(
2181 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2182 // The interstitial should have been dismissed.
2183 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2184 RunAllPendingInMessageLoop();
2185 EXPECT_TRUE(deleted
);
2188 // Tests that showing an interstitial as a result of a browser initiated
2189 // navigation while an interstitial is showing does not remove the pending
2190 // entry (see http://crbug.com/9791).
2191 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2192 const char kUrl
[] = "http://www.badguys.com/";
2193 const GURL
kGURL(kUrl
);
2195 // Start a navigation to a page
2196 contents()->GetController().LoadURL(
2197 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2199 // Simulate that navigation triggering an interstitial.
2200 TestInterstitialPage::InterstitialState state
=
2201 TestInterstitialPage::INVALID
;
2202 bool deleted
= false;
2203 TestInterstitialPage
* interstitial
=
2204 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2205 TestInterstitialPageStateGuard
state_guard(interstitial
);
2206 interstitial
->Show();
2207 interstitial
->TestDidNavigate(1, kGURL
);
2209 // Initiate a new navigation from the browser that also triggers an
2211 contents()->GetController().LoadURL(
2212 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2213 TestInterstitialPage::InterstitialState state2
=
2214 TestInterstitialPage::INVALID
;
2215 bool deleted2
= false;
2216 TestInterstitialPage
* interstitial2
=
2217 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2218 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2219 interstitial2
->Show();
2220 interstitial2
->TestDidNavigate(1, kGURL
);
2222 // Make sure we still have an entry.
2223 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2225 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2227 // And that the first interstitial is gone, but not the second.
2228 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2229 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2230 RunAllPendingInMessageLoop();
2231 EXPECT_TRUE(deleted
);
2232 EXPECT_FALSE(deleted2
);
2235 // Tests that Javascript messages are not shown while an interstitial is
2237 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2238 const char kUrl
[] = "http://www.badguys.com/";
2239 const GURL
kGURL(kUrl
);
2241 // Start a navigation to a page
2242 contents()->GetController().LoadURL(
2243 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2244 main_test_rfh()->PrepareForCommit();
2245 // DidNavigate from the page
2246 contents()->TestDidNavigate(
2247 contents()->GetMainFrame(), 1, kGURL
, ui::PAGE_TRANSITION_TYPED
);
2249 // Simulate showing an interstitial while the page is showing.
2250 TestInterstitialPage::InterstitialState state
=
2251 TestInterstitialPage::INVALID
;
2252 bool deleted
= false;
2253 TestInterstitialPage
* interstitial
=
2254 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2255 TestInterstitialPageStateGuard
state_guard(interstitial
);
2256 interstitial
->Show();
2257 interstitial
->TestDidNavigate(1, kGURL
);
2259 // While the interstitial is showing, let's simulate the hidden page
2260 // attempting to show a JS message.
2261 IPC::Message
* dummy_message
= new IPC::Message
;
2262 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2263 base::ASCIIToUTF16("This is an informative message"),
2264 base::ASCIIToUTF16("OK"),
2265 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2266 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2269 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2270 // interstitial it isn't copied over to the destination.
2271 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2272 // Navigate to a page.
2273 GURL
url1("http://www.google.com");
2274 main_test_rfh()->NavigateAndCommitRendererInitiated(1, url1
);
2275 EXPECT_EQ(1, controller().GetEntryCount());
2277 // Initiate a browser navigation that will trigger the interstitial
2278 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2279 ui::PAGE_TRANSITION_TYPED
, std::string());
2281 // Show an interstitial.
2282 TestInterstitialPage::InterstitialState state
=
2283 TestInterstitialPage::INVALID
;
2284 bool deleted
= false;
2285 GURL
url2("http://interstitial");
2286 TestInterstitialPage
* interstitial
=
2287 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2288 TestInterstitialPageStateGuard
state_guard(interstitial
);
2289 interstitial
->Show();
2290 interstitial
->TestDidNavigate(1, url2
);
2291 EXPECT_TRUE(interstitial
->is_showing());
2292 EXPECT_EQ(2, controller().GetEntryCount());
2294 // Create another NavigationController.
2295 GURL
url3("http://foo2");
2296 scoped_ptr
<TestWebContents
> other_contents(
2297 static_cast<TestWebContents
*>(CreateTestWebContents()));
2298 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2299 other_contents
->NavigateAndCommit(url3
);
2300 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
2301 other_controller
.CopyStateFromAndPrune(&controller(), false);
2303 // The merged controller should only have two entries: url1 and url2.
2304 ASSERT_EQ(2, other_controller
.GetEntryCount());
2305 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2306 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2307 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2309 // And the merged controller shouldn't be showing an interstitial.
2310 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2313 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2314 // showing an interstitial.
2315 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2316 // Navigate to a page.
2317 GURL
url1("http://www.google.com");
2318 contents()->NavigateAndCommit(url1
);
2320 // Create another NavigationController.
2321 scoped_ptr
<TestWebContents
> other_contents(
2322 static_cast<TestWebContents
*>(CreateTestWebContents()));
2323 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2325 // Navigate it to url2.
2326 GURL
url2("http://foo2");
2327 other_contents
->NavigateAndCommit(url2
);
2329 // Show an interstitial.
2330 TestInterstitialPage::InterstitialState state
=
2331 TestInterstitialPage::INVALID
;
2332 bool deleted
= false;
2333 GURL
url3("http://interstitial");
2334 TestInterstitialPage
* interstitial
=
2335 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2337 TestInterstitialPageStateGuard
state_guard(interstitial
);
2338 interstitial
->Show();
2339 interstitial
->TestDidNavigate(1, url3
);
2340 EXPECT_TRUE(interstitial
->is_showing());
2341 EXPECT_EQ(2, other_controller
.GetEntryCount());
2343 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2344 // interstitial is showing in the target.
2345 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2348 // Regression test for http://crbug.com/168611 - the URLs passed by the
2349 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2350 TEST_F(WebContentsImplTest
, FilterURLs
) {
2351 TestWebContentsObserver
observer(contents());
2353 // A navigation to about:whatever should always look like a navigation to
2355 GURL
url_normalized(url::kAboutBlankURL
);
2356 GURL
url_from_ipc("about:whatever");
2358 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2359 // will use the given URL to create the NavigationEntry as well, and that
2360 // entry should contain the filtered URL.
2361 contents()->NavigateAndCommit(url_normalized
);
2363 // Check that an IPC with about:whatever is correctly normalized.
2364 contents()->TestDidFinishLoad(url_from_ipc
);
2366 EXPECT_EQ(url_normalized
, observer
.last_url());
2368 // Create and navigate another WebContents.
2369 scoped_ptr
<TestWebContents
> other_contents(
2370 static_cast<TestWebContents
*>(CreateTestWebContents()));
2371 TestWebContentsObserver
other_observer(other_contents
.get());
2372 other_contents
->NavigateAndCommit(url_normalized
);
2374 // Check that an IPC with about:whatever is correctly normalized.
2375 other_contents
->TestDidFailLoadWithError(
2376 url_from_ipc
, 1, base::string16());
2377 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2380 // Test that if a pending contents is deleted before it is shown, we don't
2382 TEST_F(WebContentsImplTest
, PendingContents
) {
2383 scoped_ptr
<TestWebContents
> other_contents(
2384 static_cast<TestWebContents
*>(CreateTestWebContents()));
2385 contents()->AddPendingContents(other_contents
.get());
2386 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2387 other_contents
.reset();
2388 EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id
));
2391 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2392 const gfx::Size
original_preferred_size(1024, 768);
2393 contents()->UpdatePreferredSize(original_preferred_size
);
2395 // With no capturers, expect the preferred size to be the one propagated into
2396 // WebContentsImpl via the RenderViewHostDelegate interface.
2397 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2398 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2400 // Increment capturer count, but without specifying a capture size. Expect
2401 // a "not set" preferred size.
2402 contents()->IncrementCapturerCount(gfx::Size());
2403 EXPECT_EQ(1, contents()->GetCapturerCount());
2404 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2406 // Increment capturer count again, but with an overriding capture size.
2407 // Expect preferred size to now be overridden to the capture size.
2408 const gfx::Size
capture_size(1280, 720);
2409 contents()->IncrementCapturerCount(capture_size
);
2410 EXPECT_EQ(2, contents()->GetCapturerCount());
2411 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2413 // Increment capturer count a third time, but the expect that the preferred
2414 // size is still the first capture size.
2415 const gfx::Size
another_capture_size(720, 480);
2416 contents()->IncrementCapturerCount(another_capture_size
);
2417 EXPECT_EQ(3, contents()->GetCapturerCount());
2418 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2420 // Decrement capturer count twice, but expect the preferred size to still be
2422 contents()->DecrementCapturerCount();
2423 contents()->DecrementCapturerCount();
2424 EXPECT_EQ(1, contents()->GetCapturerCount());
2425 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2427 // Decrement capturer count, and since the count has dropped to zero, the
2428 // original preferred size should be restored.
2429 contents()->DecrementCapturerCount();
2430 EXPECT_EQ(0, contents()->GetCapturerCount());
2431 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2434 TEST_F(WebContentsImplTest
, CapturerPreventsHiding
) {
2435 const gfx::Size
original_preferred_size(1024, 768);
2436 contents()->UpdatePreferredSize(original_preferred_size
);
2438 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2439 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2441 // With no capturers, setting and un-setting occlusion should change the
2442 // view's occlusion state.
2443 EXPECT_FALSE(view
->is_showing());
2444 contents()->WasShown();
2445 EXPECT_TRUE(view
->is_showing());
2446 contents()->WasHidden();
2447 EXPECT_FALSE(view
->is_showing());
2448 contents()->WasShown();
2449 EXPECT_TRUE(view
->is_showing());
2451 // Add a capturer and try to hide the contents. The view will remain visible.
2452 contents()->IncrementCapturerCount(gfx::Size());
2453 contents()->WasHidden();
2454 EXPECT_TRUE(view
->is_showing());
2456 // Remove the capturer, and the WasHidden should take effect.
2457 contents()->DecrementCapturerCount();
2458 EXPECT_FALSE(view
->is_showing());
2461 TEST_F(WebContentsImplTest
, CapturerPreventsOcclusion
) {
2462 const gfx::Size
original_preferred_size(1024, 768);
2463 contents()->UpdatePreferredSize(original_preferred_size
);
2465 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2466 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2468 // With no capturers, setting and un-setting occlusion should change the
2469 // view's occlusion state.
2470 EXPECT_FALSE(view
->is_occluded());
2471 contents()->WasOccluded();
2472 EXPECT_TRUE(view
->is_occluded());
2473 contents()->WasUnOccluded();
2474 EXPECT_FALSE(view
->is_occluded());
2475 contents()->WasOccluded();
2476 EXPECT_TRUE(view
->is_occluded());
2478 // Add a capturer. This should cause the view to be un-occluded.
2479 contents()->IncrementCapturerCount(gfx::Size());
2480 EXPECT_FALSE(view
->is_occluded());
2482 // Try to occlude the view. This will fail to propagate because of the
2484 contents()->WasOccluded();
2485 EXPECT_FALSE(view
->is_occluded());
2487 // Remove the capturer and try again.
2488 contents()->DecrementCapturerCount();
2489 EXPECT_FALSE(view
->is_occluded());
2490 contents()->WasOccluded();
2491 EXPECT_TRUE(view
->is_occluded());
2494 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2496 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2497 // The WebContents starts with a valid creation time.
2498 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2500 // Reset the last active time to a known-bad value.
2501 contents()->last_active_time_
= base::TimeTicks();
2502 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2504 // Simulate activating the WebContents. The active time should update.
2505 contents()->WasShown();
2506 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2509 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2511 ContentsZoomChangedDelegate() :
2512 contents_zoom_changed_call_count_(0),
2513 last_zoom_in_(false) {
2516 int GetAndResetContentsZoomChangedCallCount() {
2517 int count
= contents_zoom_changed_call_count_
;
2518 contents_zoom_changed_call_count_
= 0;
2522 bool last_zoom_in() const {
2523 return last_zoom_in_
;
2526 // WebContentsDelegate:
2527 void ContentsZoomChange(bool zoom_in
) override
{
2528 contents_zoom_changed_call_count_
++;
2529 last_zoom_in_
= zoom_in
;
2533 int contents_zoom_changed_call_count_
;
2536 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2539 // Tests that some mouseehweel events get turned into browser zoom requests.
2540 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2541 using blink::WebInputEvent
;
2543 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2544 new ContentsZoomChangedDelegate());
2545 contents()->SetDelegate(delegate
.get());
2548 // Verify that normal mouse wheel events do nothing to change the zoom level.
2549 blink::WebMouseWheelEvent event
=
2550 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2551 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2552 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2554 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
|
2555 WebInputEvent::ControlKey
;
2556 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2557 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2558 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2560 // But whenever the ctrl modifier is applied with canScroll=false, they can
2561 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2563 modifiers
= WebInputEvent::ControlKey
;
2564 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2565 event
.canScroll
= false;
2566 bool handled
= contents()->HandleWheelEvent(event
);
2567 #if defined(OS_MACOSX)
2568 EXPECT_FALSE(handled
);
2569 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2571 EXPECT_TRUE(handled
);
2572 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2573 EXPECT_TRUE(delegate
->last_zoom_in());
2576 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2577 WebInputEvent::AltKey
;
2578 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2579 event
.canScroll
= false;
2580 handled
= contents()->HandleWheelEvent(event
);
2581 #if defined(OS_MACOSX)
2582 EXPECT_FALSE(handled
);
2583 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2585 EXPECT_TRUE(handled
);
2586 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2587 EXPECT_FALSE(delegate
->last_zoom_in());
2590 // Unless there is no vertical movement.
2591 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2592 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2593 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2595 // Events containing precise scrolling deltas also shouldn't result in the
2596 // zoom being adjusted, to avoid accidental adjustments caused by
2597 // two-finger-scrolling on a touchpad.
2598 modifiers
= WebInputEvent::ControlKey
;
2599 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2600 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2601 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2603 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2604 contents()->SetDelegate(nullptr);
2607 // Tests that GetRelatedActiveContentsCount is shared between related
2608 // SiteInstances and includes WebContents that have not navigated yet.
2609 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2610 scoped_refptr
<SiteInstance
> instance1(
2611 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2612 scoped_refptr
<SiteInstance
> instance2(
2613 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2615 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2616 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2618 scoped_ptr
<TestWebContents
> contents1(
2619 TestWebContents::Create(browser_context(), instance1
.get()));
2620 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2621 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2623 scoped_ptr
<TestWebContents
> contents2(
2624 TestWebContents::Create(browser_context(), instance1
.get()));
2625 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2626 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2629 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2630 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2633 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2634 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2637 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2638 // same-site and cross-site navigations.
2639 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2640 scoped_refptr
<SiteInstance
> instance(
2641 SiteInstance::Create(browser_context()));
2643 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2645 scoped_ptr
<TestWebContents
> contents(
2646 TestWebContents::Create(browser_context(), instance
.get()));
2647 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2649 // Navigate to a URL.
2650 contents
->GetController().LoadURL(GURL("http://a.com/1"),
2652 ui::PAGE_TRANSITION_TYPED
,
2654 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2655 contents
->CommitPendingNavigation();
2656 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2658 // Navigate to a URL in the same site.
2659 contents
->GetController().LoadURL(GURL("http://a.com/2"),
2661 ui::PAGE_TRANSITION_TYPED
,
2663 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2664 contents
->CommitPendingNavigation();
2665 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2667 // Navigate to a URL in a different site.
2668 const GURL kUrl
= GURL("http://b.com");
2669 contents
->GetController().LoadURL(kUrl
,
2671 ui::PAGE_TRANSITION_TYPED
,
2673 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2674 switches::kEnableBrowserSideNavigation
)) {
2675 contents
->GetMainFrame()->PrepareForCommit();
2677 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2678 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2679 contents
->GetPendingMainFrame()->SendNavigate(1, kUrl
);
2680 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2683 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2686 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2688 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2689 scoped_refptr
<SiteInstance
> instance(
2690 SiteInstance::Create(browser_context()));
2692 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2694 scoped_ptr
<TestWebContents
> contents(
2695 TestWebContents::Create(browser_context(), instance
.get()));
2696 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2698 // Navigate to a URL.
2699 contents
->NavigateAndCommit(GURL("http://a.com"));
2700 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2702 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2703 const GURL kWebUIUrl
= GURL(kTestWebUIUrl
);
2704 contents
->GetController().LoadURL(kWebUIUrl
,
2706 ui::PAGE_TRANSITION_TYPED
,
2708 contents
->GetMainFrame()->PrepareForCommit();
2709 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2710 scoped_refptr
<SiteInstance
> instance_webui(
2711 contents
->GetPendingMainFrame()->GetSiteInstance());
2712 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2714 // At this point, contents still counts for the old BrowsingInstance.
2715 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2716 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2718 // Commit and contents counts for the new one.
2719 contents
->GetPendingMainFrame()->SendNavigate(1, kWebUIUrl
);
2720 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2721 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2724 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2725 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2728 class LoadingWebContentsObserver
: public WebContentsObserver
{
2730 explicit LoadingWebContentsObserver(WebContents
* contents
)
2731 : WebContentsObserver(contents
),
2732 is_loading_(false) {
2734 ~LoadingWebContentsObserver() override
{}
2736 void DidStartLoading() override
{ is_loading_
= true; }
2737 void DidStopLoading() override
{ is_loading_
= false; }
2739 bool is_loading() const { return is_loading_
; }
2744 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver
);
2747 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2748 // interleaving cross-process navigations in multiple subframes.
2749 // See https://crbug.com/448601 for details of the underlying issue. The
2750 // sequence of events that reproduce it are as follows:
2751 // * Navigate top-level frame with one subframe.
2752 // * Subframe navigates more than once before the top-level frame has had a
2753 // chance to complete the load.
2754 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2755 // to 0, while the loading_progresses_ map is not reset.
2756 TEST_F(WebContentsImplTest
, StartStopEventsBalance
) {
2757 // The bug manifests itself in regular mode as well, but browser-initiated
2758 // navigation of subframes is only possible in --site-per-process mode within
2760 base::CommandLine::ForCurrentProcess()->AppendSwitch(
2761 switches::kSitePerProcess
);
2762 const GURL
initial_url("about:blank");
2763 const GURL
main_url("http://www.chromium.org");
2764 const GURL
foo_url("http://foo.chromium.org");
2765 const GURL
bar_url("http://bar.chromium.org");
2766 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
2768 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
2769 LoadingWebContentsObserver
observer(contents());
2771 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
2772 // The frame should still be loading.
2773 controller().LoadURL(
2774 main_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2775 orig_rfh
->PrepareForCommit();
2776 orig_rfh
->OnMessageReceived(
2777 FrameHostMsg_DidStartLoading(orig_rfh
->GetRoutingID(), false));
2778 contents()->TestDidNavigate(orig_rfh
, 1, main_url
, ui::PAGE_TRANSITION_TYPED
);
2779 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2780 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
2781 EXPECT_TRUE(contents()->IsLoading());
2782 EXPECT_TRUE(observer
.is_loading());
2784 // Create a child frame to navigate multiple times.
2785 TestRenderFrameHost
* subframe
= orig_rfh
->AppendChild("subframe");
2787 // Navigate the child frame to about:blank, which will send both
2788 // DidStartLoading and DidStopLoading messages.
2790 subframe
->SendRendererInitiatedNavigationRequest(initial_url
, false);
2791 subframe
->PrepareForCommit();
2792 subframe
->OnMessageReceived(
2793 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2794 subframe
->SendNavigateWithTransition(1, initial_url
,
2795 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2796 subframe
->OnMessageReceived(
2797 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2800 // Navigate the frame to another URL, which will send again
2801 // DidStartLoading and DidStopLoading messages.
2803 subframe
->SendRendererInitiatedNavigationRequest(foo_url
, false);
2804 subframe
->PrepareForCommit();
2805 subframe
->OnMessageReceived(
2806 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2807 subframe
->SendNavigateWithTransition(
2808 1, foo_url
, ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2809 subframe
->OnMessageReceived(
2810 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2813 // Since the main frame hasn't sent any DidStopLoading messages, it is
2814 // expected that the WebContents is still in loading state.
2815 EXPECT_TRUE(contents()->IsLoading());
2816 EXPECT_TRUE(observer
.is_loading());
2818 // Navigate the frame again, this time using LoadURLWithParams. This causes
2819 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2822 NavigationController::LoadURLParams
load_params(bar_url
);
2823 load_params
.referrer
=
2824 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
2825 load_params
.transition_type
= ui::PAGE_TRANSITION_GENERATED
;
2826 load_params
.extra_headers
= "content-type: text/plain";
2827 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
2828 load_params
.is_renderer_initiated
= false;
2829 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
2830 load_params
.frame_tree_node_id
=
2831 subframe
->frame_tree_node()->frame_tree_node_id();
2832 controller().LoadURLWithParams(load_params
);
2834 subframe
->OnMessageReceived(
2835 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2837 // Commit the navigation in the child frame and send the DidStopLoading
2839 subframe
->PrepareForCommit();
2840 contents()->TestDidNavigate(
2841 subframe
, 3, bar_url
, ui::PAGE_TRANSITION_MANUAL_SUBFRAME
);
2842 subframe
->OnMessageReceived(
2843 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2846 // At this point the status should still be loading, since the main frame
2847 // hasn't sent the DidstopLoading message yet.
2848 EXPECT_TRUE(contents()->IsLoading());
2849 EXPECT_TRUE(observer
.is_loading());
2851 // Send the DidStopLoading for the main frame and ensure it isn't loading
2853 orig_rfh
->OnMessageReceived(
2854 FrameHostMsg_DidStopLoading(orig_rfh
->GetRoutingID()));
2855 EXPECT_FALSE(contents()->IsLoading());
2856 EXPECT_FALSE(observer
.is_loading());
2859 // Ensure that WebContentsImpl does not stop loading too early when there still
2860 // is a pending renderer. This can happen if a same-process non user-initiated
2861 // navigation completes while there is an ongoing cross-process navigation.
2862 // TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
2863 // DidStopLoading are properly called.
2864 TEST_F(WebContentsImplTest
, NoEarlyStop
) {
2865 const GURL
kUrl1("http://www.chromium.org");
2866 const GURL
kUrl2("http://www.google.com");
2867 const GURL
kUrl3("http://www.wikipedia.org");
2869 contents()->NavigateAndCommit(kUrl1
);
2871 TestRenderFrameHost
* current_rfh
= contents()->GetMainFrame();
2873 // Start a browser-initiated cross-process navigation to |kUrl2|. There should
2874 // be a pending RenderFrameHost and the WebContents should be loading.
2875 controller().LoadURL(
2876 kUrl2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2877 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
2878 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
2879 ASSERT_TRUE(pending_rfh
);
2880 EXPECT_TRUE(contents()->IsLoading());
2882 // The current RenderFrameHost starts a non user-initiated render-initiated
2883 // navigation and sends a DidStartLoading IPC. The WebContents should still be
2885 current_rfh
->OnMessageReceived(
2886 FrameHostMsg_DidStartLoading(current_rfh
->GetRoutingID(), false));
2887 EXPECT_TRUE(contents()->IsLoading());
2889 // Simulate the pending RenderFrameHost DidStartLoading. There should still be
2890 // a pending RenderFrameHost and the WebContents should still be loading.
2891 pending_rfh
->PrepareForCommit();
2892 pending_rfh
->OnMessageReceived(
2893 FrameHostMsg_DidStartLoading(pending_rfh
->GetRoutingID(), false));
2894 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
2895 EXPECT_TRUE(contents()->IsLoading());
2897 // Simulate the commit and DidStopLoading from the renderer-initiated
2898 // navigation in the current RenderFrameHost. There should still be a pending
2899 // RenderFrameHost and the WebContents should still be loading.
2900 current_rfh
->SendNavigate(1, kUrl3
);
2901 current_rfh
->OnMessageReceived(
2902 FrameHostMsg_DidStopLoading(current_rfh
->GetRoutingID()));
2903 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
2904 EXPECT_TRUE(contents()->IsLoading());
2906 // Commit the navigation. The formerly pending RenderFrameHost should now be
2907 // the current RenderFrameHost and the WebContents should still be loading.
2908 contents()->TestDidNavigate(pending_rfh
, 1, kUrl2
,
2909 ui::PAGE_TRANSITION_TYPED
);
2910 EXPECT_FALSE(contents()->GetPendingMainFrame());
2911 TestRenderFrameHost
* new_current_rfh
= contents()->GetMainFrame();
2912 EXPECT_EQ(new_current_rfh
, pending_rfh
);
2913 EXPECT_TRUE(contents()->IsLoading());
2915 // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
2916 // should now have stopped loading.
2917 new_current_rfh
->OnMessageReceived(
2918 FrameHostMsg_DidStopLoading(new_current_rfh
->GetRoutingID()));
2919 EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh
);
2920 EXPECT_FALSE(contents()->IsLoading());
2923 TEST_F(WebContentsImplTest
, MediaPowerSaveBlocking
) {
2924 // PlayerIDs are actually pointers cast to int64, so verify that both negative
2925 // and positive player ids don't blow up.
2926 const int kPlayerAudioVideoId
= 15;
2927 const int kPlayerAudioOnlyId
= -15;
2928 const int kPlayerVideoOnlyId
= 30;
2929 const int kPlayerRemoteId
= -30;
2931 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2932 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2934 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
2935 AudioStateProvider
* audio_state
= contents()->audio_state_provider();
2937 // The audio power save blocker should not be based on having a media player
2938 // when audio stream monitoring is available.
2939 if (audio_state
->IsAudioStateAvailable()) {
2940 // Send a fake audio stream monitor notification. The audio power save
2941 // blocker should be created.
2942 audio_state
->set_was_recently_audible_for_testing(true);
2943 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
2944 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
2946 // Send another fake notification, this time when WasRecentlyAudible() will
2947 // be false. The power save blocker should be released.
2948 audio_state
->set_was_recently_audible_for_testing(false);
2949 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
2950 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2953 // Start a player with both audio and video. A video power save blocker
2954 // should be created. If audio stream monitoring is available, an audio power
2955 // save blocker should be created too.
2956 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2957 0, kPlayerAudioVideoId
, true, true, false));
2958 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2959 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2960 !audio_state
->IsAudioStateAvailable());
2962 // Upon hiding the video power save blocker should be released.
2963 contents()->WasHidden();
2964 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2966 // Start another player that only has video. There should be no change in
2967 // the power save blockers. The notification should take into account the
2968 // visibility state of the WebContents.
2969 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2970 0, kPlayerVideoOnlyId
, true, false, false));
2971 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2972 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2973 !audio_state
->IsAudioStateAvailable());
2975 // Showing the WebContents should result in the creation of the blocker.
2976 contents()->WasShown();
2977 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2979 // Start another player that only has audio. There should be no change in
2980 // the power save blockers.
2981 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2982 0, kPlayerAudioOnlyId
, false, true, false));
2983 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2984 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2985 !audio_state
->IsAudioStateAvailable());
2987 // Start a remote player. There should be no change in the power save
2989 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2990 0, kPlayerRemoteId
, true, true, true));
2991 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2992 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2993 !audio_state
->IsAudioStateAvailable());
2995 // Destroy the original audio video player. Both power save blockers should
2997 rfh
->OnMessageReceived(
2998 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId
));
2999 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3000 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3001 !audio_state
->IsAudioStateAvailable());
3003 // Destroy the audio only player. The video power save blocker should remain.
3004 rfh
->OnMessageReceived(
3005 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId
));
3006 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3007 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3009 // Destroy the video only player. No power save blockers should remain.
3010 rfh
->OnMessageReceived(
3011 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId
));
3012 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3013 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3015 // Destroy the remote player. No power save blockers should remain.
3016 rfh
->OnMessageReceived(
3017 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId
));
3018 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3019 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3021 // Start a player with both audio and video. A video power save blocker
3022 // should be created. If audio stream monitoring is available, an audio power
3023 // save blocker should be created too.
3024 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3025 0, kPlayerAudioVideoId
, true, true, false));
3026 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3027 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3028 !audio_state
->IsAudioStateAvailable());
3030 // Crash the renderer.
3031 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
3033 // Verify that all the power save blockers have been released.
3034 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3035 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3038 } // namespace content