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/frame_host/render_frame_proxy_host.h"
13 #include "content/browser/media/audio_state_provider.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/browser/site_instance_impl.h"
16 #include "content/browser/webui/content_web_ui_controller_factory.h"
17 #include "content/browser/webui/web_ui_controller_factory_registry.h"
18 #include "content/common/frame_messages.h"
19 #include "content/common/input/synthetic_web_input_event_builders.h"
20 #include "content/common/view_messages.h"
21 #include "content/public/browser/global_request_id.h"
22 #include "content/public/browser/interstitial_page_delegate.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/notification_details.h"
25 #include "content/public/browser/notification_source.h"
26 #include "content/public/browser/render_widget_host_view.h"
27 #include "content/public/browser/web_contents_delegate.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/browser/web_ui_controller.h"
30 #include "content/public/common/bindings_policy.h"
31 #include "content/public/common/content_constants.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/url_constants.h"
34 #include "content/public/common/url_utils.h"
35 #include "content/public/test/browser_test_utils.h"
36 #include "content/public/test/mock_render_process_host.h"
37 #include "content/public/test/test_utils.h"
38 #include "content/test/test_content_browser_client.h"
39 #include "content/test/test_content_client.h"
40 #include "content/test/test_render_frame_host.h"
41 #include "content/test/test_render_view_host.h"
42 #include "content/test/test_web_contents.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 #include "third_party/skia/include/core/SkColor.h"
49 class TestInterstitialPage
;
51 class TestInterstitialPageDelegate
: public InterstitialPageDelegate
{
53 explicit TestInterstitialPageDelegate(TestInterstitialPage
* interstitial_page
)
54 : interstitial_page_(interstitial_page
) {}
55 void CommandReceived(const std::string
& command
) override
;
56 std::string
GetHTMLContents() override
{ return std::string(); }
57 void OnDontProceed() override
;
58 void OnProceed() override
;
61 TestInterstitialPage
* interstitial_page_
;
64 class TestInterstitialPage
: public InterstitialPageImpl
{
66 enum InterstitialState
{
67 INVALID
= 0, // Hasn't yet been initialized.
68 UNDECIDED
, // Initialized, but no decision taken yet.
69 OKED
, // Proceed was called.
70 CANCELED
// DontProceed was called.
75 virtual void TestInterstitialPageDeleted(
76 TestInterstitialPage
* interstitial
) = 0;
79 virtual ~Delegate() {}
82 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
83 // |deleted| (like all interstitial related tests do at this point), make sure
84 // to create an instance of the TestInterstitialPageStateGuard class on the
85 // stack in your test. This will ensure that the TestInterstitialPage states
86 // are cleared when the test finishes.
87 // Not doing so will cause stack trashing if your test does not hide the
88 // interstitial, as in such a case it will be destroyed in the test TearDown
89 // method and will dereference the |deleted| local variable which by then is
91 TestInterstitialPage(WebContentsImpl
* contents
,
94 InterstitialState
* state
,
96 : InterstitialPageImpl(
98 static_cast<RenderWidgetHostDelegate
*>(contents
),
99 new_navigation
, url
, new TestInterstitialPageDelegate(this)),
102 command_received_count_(0),
108 ~TestInterstitialPage() override
{
112 delegate_
->TestInterstitialPageDeleted(this);
115 void OnDontProceed() {
124 int command_received_count() const {
125 return command_received_count_
;
128 void TestDomOperationResponse(const std::string
& json_string
) {
133 void TestDidNavigate(int page_id
,
135 bool did_create_new_entry
,
137 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
138 InitNavigateParams(¶ms
, page_id
, nav_entry_id
, did_create_new_entry
,
139 url
, ui::PAGE_TRANSITION_TYPED
);
140 DidNavigate(GetMainFrame()->GetRenderViewHost(), params
);
143 void TestRenderViewTerminated(base::TerminationStatus status
,
145 RenderViewTerminated(GetMainFrame()->GetRenderViewHost(), status
,
149 bool is_showing() const {
150 return static_cast<TestRenderWidgetHostView
*>(
151 GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
160 void CommandReceived() {
161 command_received_count_
++;
164 void set_delegate(Delegate
* delegate
) {
165 delegate_
= delegate
;
169 WebContentsView
* CreateWebContentsView() override
{ return nullptr; }
172 InterstitialState
* state_
;
174 int command_received_count_
;
178 void TestInterstitialPageDelegate::CommandReceived(const std::string
& command
) {
179 interstitial_page_
->CommandReceived();
182 void TestInterstitialPageDelegate::OnDontProceed() {
183 interstitial_page_
->OnDontProceed();
186 void TestInterstitialPageDelegate::OnProceed() {
187 interstitial_page_
->OnProceed();
190 class TestInterstitialPageStateGuard
: public TestInterstitialPage::Delegate
{
192 explicit TestInterstitialPageStateGuard(
193 TestInterstitialPage
* interstitial_page
)
194 : interstitial_page_(interstitial_page
) {
195 DCHECK(interstitial_page_
);
196 interstitial_page_
->set_delegate(this);
198 ~TestInterstitialPageStateGuard() override
{
199 if (interstitial_page_
)
200 interstitial_page_
->ClearStates();
203 void TestInterstitialPageDeleted(
204 TestInterstitialPage
* interstitial
) override
{
205 DCHECK(interstitial_page_
== interstitial
);
206 interstitial_page_
= nullptr;
210 TestInterstitialPage
* interstitial_page_
;
213 class WebContentsImplTestBrowserClient
: public TestContentBrowserClient
{
215 WebContentsImplTestBrowserClient()
216 : assign_site_for_url_(false) {}
218 ~WebContentsImplTestBrowserClient() override
{}
220 bool ShouldAssignSiteForURL(const GURL
& url
) override
{
221 return assign_site_for_url_
;
224 void set_assign_site_for_url(bool assign
) {
225 assign_site_for_url_
= assign
;
229 bool assign_site_for_url_
;
232 class WebContentsImplTest
: public RenderViewHostImplTestHarness
{
234 void SetUp() override
{
235 RenderViewHostImplTestHarness::SetUp();
236 WebUIControllerFactory::RegisterFactory(
237 ContentWebUIControllerFactory::GetInstance());
240 void TearDown() override
{
241 WebUIControllerFactory::UnregisterFactoryForTesting(
242 ContentWebUIControllerFactory::GetInstance());
243 RenderViewHostImplTestHarness::TearDown();
247 class TestWebContentsObserver
: public WebContentsObserver
{
249 explicit TestWebContentsObserver(WebContents
* contents
)
250 : WebContentsObserver(contents
),
251 last_theme_color_(SK_ColorTRANSPARENT
) {
253 ~TestWebContentsObserver() override
{}
255 void DidFinishLoad(RenderFrameHost
* render_frame_host
,
256 const GURL
& validated_url
) override
{
257 last_url_
= validated_url
;
259 void DidFailLoad(RenderFrameHost
* render_frame_host
,
260 const GURL
& validated_url
,
262 const base::string16
& error_description
,
263 bool was_ignored_by_handler
) override
{
264 last_url_
= validated_url
;
267 void DidChangeThemeColor(SkColor theme_color
) override
{
268 last_theme_color_
= theme_color
;
271 const GURL
& last_url() const { return last_url_
; }
272 SkColor
last_theme_color() const { return last_theme_color_
; }
276 SkColor last_theme_color_
;
278 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver
);
281 // Pretends to be a normal browser that receives toggles and transitions to/from
282 // a fullscreened state.
283 class FakeFullscreenDelegate
: public WebContentsDelegate
{
285 FakeFullscreenDelegate() : fullscreened_contents_(nullptr) {}
286 ~FakeFullscreenDelegate() override
{}
288 void EnterFullscreenModeForTab(WebContents
* web_contents
,
289 const GURL
& origin
) override
{
290 fullscreened_contents_
= web_contents
;
293 void ExitFullscreenModeForTab(WebContents
* web_contents
) override
{
294 fullscreened_contents_
= nullptr;
297 bool IsFullscreenForTabOrPending(
298 const WebContents
* web_contents
) const override
{
299 return fullscreened_contents_
&& web_contents
== fullscreened_contents_
;
303 WebContents
* fullscreened_contents_
;
305 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate
);
308 class FakeValidationMessageDelegate
: public WebContentsDelegate
{
310 FakeValidationMessageDelegate()
311 : hide_validation_message_was_called_(false) {}
312 ~FakeValidationMessageDelegate() override
{}
314 void HideValidationMessage(WebContents
* web_contents
) override
{
315 hide_validation_message_was_called_
= true;
318 bool hide_validation_message_was_called() const {
319 return hide_validation_message_was_called_
;
323 bool hide_validation_message_was_called_
;
325 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate
);
330 // Test to make sure that title updates get stripped of whitespace.
331 TEST_F(WebContentsImplTest
, UpdateTitle
) {
332 NavigationControllerImpl
& cont
=
333 static_cast<NavigationControllerImpl
&>(controller());
334 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
335 InitNavigateParams(¶ms
, 0, 0, true, GURL(url::kAboutBlankURL
),
336 ui::PAGE_TRANSITION_TYPED
);
338 LoadCommittedDetails details
;
339 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
341 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
342 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
343 base::i18n::LEFT_TO_RIGHT
);
344 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
347 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
348 const GURL
kGURL("chrome://blah");
349 controller().LoadURL(
350 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
351 EXPECT_EQ(base::string16(), contents()->GetTitle());
354 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
355 const GURL
kGURL("chrome://blah");
356 const base::string16 title
= base::ASCIIToUTF16("My Title");
357 controller().LoadURL(
358 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
360 NavigationEntry
* entry
= controller().GetVisibleEntry();
361 ASSERT_EQ(kGURL
, entry
->GetURL());
362 entry
->SetTitle(title
);
364 EXPECT_EQ(title
, contents()->GetTitle());
367 // Test view source mode for a webui page.
368 TEST_F(WebContentsImplTest
, NTPViewSource
) {
369 NavigationControllerImpl
& cont
=
370 static_cast<NavigationControllerImpl
&>(controller());
371 const char kUrl
[] = "view-source:chrome://blah";
372 const GURL
kGURL(kUrl
);
374 process()->sink().ClearMessages();
377 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
378 int entry_id
= cont
.GetPendingEntry()->GetUniqueID();
379 rvh()->GetDelegate()->RenderViewCreated(rvh());
380 // Did we get the expected message?
381 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
382 ViewMsg_EnableViewSourceMode::ID
));
384 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
385 InitNavigateParams(¶ms
, 0, entry_id
, true, kGURL
,
386 ui::PAGE_TRANSITION_TYPED
);
387 LoadCommittedDetails details
;
388 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
389 // Also check title and url.
390 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
393 // Test to ensure UpdateMaxPageID is working properly.
394 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
395 SiteInstance
* instance1
= contents()->GetSiteInstance();
396 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(nullptr));
399 EXPECT_EQ(-1, contents()->GetMaxPageID());
400 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
401 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
403 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
404 contents()->UpdateMaxPageID(3);
405 contents()->UpdateMaxPageID(1);
406 EXPECT_EQ(3, contents()->GetMaxPageID());
407 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
408 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
410 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
411 EXPECT_EQ(3, contents()->GetMaxPageID());
412 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
413 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
416 // Test simple same-SiteInstance navigation.
417 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
418 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
419 SiteInstance
* instance1
= contents()->GetSiteInstance();
420 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
423 const GURL
url("http://www.google.com");
424 controller().LoadURL(
425 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
426 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
427 main_test_rfh()->PrepareForCommit();
428 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
429 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
430 // Controller's pending entry will have a null site instance until we assign
431 // it in DidNavigate.
434 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
437 // DidNavigate from the page
438 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
439 ui::PAGE_TRANSITION_TYPED
);
440 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
441 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
442 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
443 // Controller's entry should now have the SiteInstance, or else we won't be
444 // able to find it later.
447 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
451 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
452 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
453 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
454 const GURL
url(std::string("http://example.org/").append(
455 GetMaxURLChars() + 1, 'a'));
457 controller().LoadURL(
458 url
, Referrer(), ui::PAGE_TRANSITION_GENERATED
, std::string());
459 EXPECT_EQ(nullptr, controller().GetVisibleEntry());
462 // Test that navigating across a site boundary creates a new RenderViewHost
463 // with a new SiteInstance. Going back should do the same.
464 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
465 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
466 int orig_rvh_delete_count
= 0;
467 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
468 SiteInstance
* instance1
= contents()->GetSiteInstance();
470 // Navigate to URL. First URL should use first RenderViewHost.
471 const GURL
url("http://www.google.com");
472 controller().LoadURL(
473 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
474 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
475 orig_rfh
->PrepareForCommit();
476 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
477 ui::PAGE_TRANSITION_TYPED
);
479 // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
480 // that orig_rfh doesn't get deleted when it gets swapped out.
481 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
483 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
484 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
485 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
486 EXPECT_EQ(url
, contents()->GetVisibleURL());
488 // Navigate to new site
489 const GURL
url2("http://www.yahoo.com");
490 controller().LoadURL(
491 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
492 entry_id
= controller().GetPendingEntry()->GetUniqueID();
493 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
494 switches::kEnableBrowserSideNavigation
)) {
495 orig_rfh
->PrepareForCommit();
497 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
498 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
499 EXPECT_EQ(url2
, contents()->GetVisibleURL());
500 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
501 int pending_rvh_delete_count
= 0;
502 pending_rfh
->GetRenderViewHost()->set_delete_counter(
503 &pending_rvh_delete_count
);
505 // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
506 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
507 switches::kEnableBrowserSideNavigation
)) {
508 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
509 orig_rfh
->SendBeforeUnloadACK(true);
510 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
513 // DidNavigate from the pending page
514 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
515 ui::PAGE_TRANSITION_TYPED
);
516 SiteInstance
* instance2
= contents()->GetSiteInstance();
518 // Keep the number of active frames in pending_rfh's SiteInstance
519 // non-zero so that orig_rfh doesn't get deleted when it gets
521 pending_rfh
->GetSiteInstance()->increment_active_frame_count();
523 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
524 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
525 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
526 EXPECT_EQ(url2
, contents()->GetVisibleURL());
527 EXPECT_NE(instance1
, instance2
);
528 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
529 // We keep a proxy for the original RFH's SiteInstance.
530 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
531 orig_rfh
->GetSiteInstance()));
532 EXPECT_EQ(orig_rvh_delete_count
, 0);
534 // Going back should switch SiteInstances again. The first SiteInstance is
535 // stored in the NavigationEntry, so it should be the same as at the start.
536 // We should use the same RFH as before, swapping it back in.
537 controller().GoBack();
538 entry_id
= controller().GetPendingEntry()->GetUniqueID();
539 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
540 switches::kEnableBrowserSideNavigation
)) {
541 contents()->GetMainFrame()->PrepareForCommit();
543 TestRenderFrameHost
* goback_rfh
= contents()->GetPendingMainFrame();
544 if (!RenderFrameHostManager::IsSwappedOutStateForbidden()) {
545 // Recycling the rfh is a behavior specific to swappedout://
546 EXPECT_EQ(orig_rfh
, goback_rfh
);
548 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
550 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
551 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
552 switches::kEnableBrowserSideNavigation
)) {
553 EXPECT_TRUE(goback_rfh
->are_navigations_suspended());
554 pending_rfh
->SendBeforeUnloadACK(true);
555 EXPECT_FALSE(goback_rfh
->are_navigations_suspended());
558 // DidNavigate from the back action
559 contents()->TestDidNavigate(goback_rfh
, 1, entry_id
, false, url2
,
560 ui::PAGE_TRANSITION_TYPED
);
561 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
562 EXPECT_EQ(goback_rfh
, contents()->GetMainFrame());
563 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
564 // There should be a proxy for the pending RFH SiteInstance.
565 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
566 GetRenderFrameProxyHost(pending_rfh
->GetSiteInstance()));
567 EXPECT_EQ(pending_rvh_delete_count
, 0);
568 pending_rfh
->OnSwappedOut();
570 // Close contents and ensure RVHs are deleted.
572 EXPECT_EQ(orig_rvh_delete_count
, 1);
573 EXPECT_EQ(pending_rvh_delete_count
, 1);
576 // Test that navigating across a site boundary after a crash creates a new
577 // RFH without requiring a cross-site transition (i.e., PENDING state).
578 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
579 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
581 int orig_rvh_delete_count
= 0;
582 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
583 SiteInstance
* instance1
= contents()->GetSiteInstance();
585 // Navigate to URL. First URL should use first RenderViewHost.
586 const GURL
url("http://www.google.com");
587 controller().LoadURL(
588 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
589 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
590 contents()->GetMainFrame()->PrepareForCommit();
591 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
592 ui::PAGE_TRANSITION_TYPED
);
594 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
595 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
597 // Simulate a renderer crash.
598 EXPECT_TRUE(orig_rfh
->IsRenderFrameLive());
599 orig_rfh
->GetProcess()->SimulateCrash();
600 EXPECT_FALSE(orig_rfh
->IsRenderFrameLive());
602 // Navigate to new site. We should not go into PENDING.
603 const GURL
url2("http://www.yahoo.com");
604 controller().LoadURL(
605 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
606 entry_id
= controller().GetPendingEntry()->GetUniqueID();
607 contents()->GetMainFrame()->PrepareForCommit();
608 TestRenderFrameHost
* new_rfh
= contents()->GetMainFrame();
609 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
610 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
611 EXPECT_NE(orig_rfh
, new_rfh
);
612 EXPECT_EQ(orig_rvh_delete_count
, 1);
614 // DidNavigate from the new page
615 contents()->TestDidNavigate(new_rfh
, 1, entry_id
, true, url2
,
616 ui::PAGE_TRANSITION_TYPED
);
617 SiteInstance
* instance2
= contents()->GetSiteInstance();
619 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
620 EXPECT_EQ(new_rfh
, main_rfh());
621 EXPECT_NE(instance1
, instance2
);
622 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
624 // Close contents and ensure RVHs are deleted.
626 EXPECT_EQ(orig_rvh_delete_count
, 1);
629 // Test that opening a new contents in the same SiteInstance and then navigating
630 // both contentses to a new site will place both contentses in a single
632 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
633 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
634 SiteInstance
* instance1
= contents()->GetSiteInstance();
636 // Navigate to URL. First URL should use first RenderViewHost.
637 const GURL
url("http://www.google.com");
638 controller().LoadURL(
639 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
640 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
641 contents()->GetMainFrame()->PrepareForCommit();
642 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
643 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 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
652 contents2
->GetMainFrame()->PrepareForCommit();
653 // Need this page id to be 2 since the site instance is the same (which is the
654 // scope of page IDs) and we want to consider this a new page.
655 contents2
->TestDidNavigate(contents2
->GetMainFrame(), 2, entry_id
, true, url
,
656 ui::PAGE_TRANSITION_TYPED
);
658 // Navigate first contents to a new site.
659 const GURL
url2a("http://www.yahoo.com");
660 controller().LoadURL(
661 url2a
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
662 entry_id
= controller().GetPendingEntry()->GetUniqueID();
663 orig_rfh
->PrepareForCommit();
664 TestRenderFrameHost
* pending_rfh_a
= contents()->GetPendingMainFrame();
665 contents()->TestDidNavigate(pending_rfh_a
, 1, entry_id
, true, url2a
,
666 ui::PAGE_TRANSITION_TYPED
);
667 SiteInstance
* instance2a
= contents()->GetSiteInstance();
668 EXPECT_NE(instance1
, instance2a
);
670 // Navigate second contents to the same site as the first tab.
671 const GURL
url2b("http://mail.yahoo.com");
672 contents2
->GetController().LoadURL(url2b
, Referrer(),
673 ui::PAGE_TRANSITION_TYPED
,
675 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
676 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
677 rfh2
->PrepareForCommit();
678 TestRenderFrameHost
* pending_rfh_b
= contents2
->GetPendingMainFrame();
679 EXPECT_NE(nullptr, pending_rfh_b
);
680 EXPECT_TRUE(contents2
->CrossProcessNavigationPending());
682 // NOTE(creis): We used to be in danger of showing a crash page here if the
683 // second contents hadn't navigated somewhere first (bug 1145430). That case
684 // is now covered by the CrossSiteBoundariesAfterCrash test.
685 contents2
->TestDidNavigate(pending_rfh_b
, 2, entry_id
, true, url2b
,
686 ui::PAGE_TRANSITION_TYPED
);
687 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
688 EXPECT_NE(instance1
, instance2b
);
690 // Both contentses should now be in the same SiteInstance.
691 EXPECT_EQ(instance2a
, instance2b
);
694 // The embedder can request sites for certain urls not be be assigned to the
695 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
696 // allowing to reuse the renderer backing certain chrome urls for subsequent
697 // navigation. The test verifies that the override is honored.
698 TEST_F(WebContentsImplTest
, NavigateFromSitelessUrl
) {
699 WebContentsImplTestBrowserClient browser_client
;
700 SetBrowserClientForTesting(&browser_client
);
702 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
703 int orig_rvh_delete_count
= 0;
704 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
705 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
707 browser_client
.set_assign_site_for_url(false);
708 // Navigate to an URL that will not assign a new SiteInstance.
709 const GURL
native_url("non-site-url://stuffandthings");
710 controller().LoadURL(
711 native_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
712 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
713 contents()->GetMainFrame()->PrepareForCommit();
714 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, native_url
,
715 ui::PAGE_TRANSITION_TYPED
);
717 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
718 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
719 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
720 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
721 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
722 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
723 EXPECT_FALSE(orig_instance
->HasSite());
725 browser_client
.set_assign_site_for_url(true);
726 // Navigate to new site (should keep same site instance).
727 const GURL
url("http://www.google.com");
728 controller().LoadURL(
729 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
730 entry_id
= controller().GetPendingEntry()->GetUniqueID();
731 contents()->GetMainFrame()->PrepareForCommit();
732 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
733 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
734 EXPECT_EQ(url
, contents()->GetVisibleURL());
735 EXPECT_FALSE(contents()->GetPendingMainFrame());
736 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url
,
737 ui::PAGE_TRANSITION_TYPED
);
739 // Keep the number of active frames in orig_rfh's SiteInstance
740 // non-zero so that orig_rfh doesn't get deleted when it gets
742 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
744 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
746 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
747 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
749 // Navigate to another new site (should create a new site instance).
750 const GURL
url2("http://www.yahoo.com");
751 controller().LoadURL(
752 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
753 entry_id
= controller().GetPendingEntry()->GetUniqueID();
754 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
755 switches::kEnableBrowserSideNavigation
)) {
756 orig_rfh
->PrepareForCommit();
758 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
759 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
760 EXPECT_EQ(url2
, contents()->GetVisibleURL());
761 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
762 int pending_rvh_delete_count
= 0;
763 pending_rfh
->GetRenderViewHost()->set_delete_counter(
764 &pending_rvh_delete_count
);
766 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
767 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
768 switches::kEnableBrowserSideNavigation
)) {
769 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
770 orig_rfh
->SendBeforeUnloadACK(true);
771 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
774 // DidNavigate from the pending page.
775 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
776 ui::PAGE_TRANSITION_TYPED
);
777 SiteInstance
* new_instance
= contents()->GetSiteInstance();
779 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
780 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
781 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
782 EXPECT_EQ(url2
, contents()->GetVisibleURL());
783 EXPECT_NE(new_instance
, orig_instance
);
784 EXPECT_FALSE(contents()->GetPendingMainFrame());
785 // We keep a proxy for the original RFH's SiteInstance.
786 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
787 orig_rfh
->GetSiteInstance()));
788 EXPECT_EQ(orig_rvh_delete_count
, 0);
789 orig_rfh
->OnSwappedOut();
791 // Close contents and ensure RVHs are deleted.
793 EXPECT_EQ(orig_rvh_delete_count
, 1);
794 EXPECT_EQ(pending_rvh_delete_count
, 1);
797 // Regression test for http://crbug.com/386542 - variation of
798 // NavigateFromSitelessUrl in which the original navigation is a session
800 TEST_F(WebContentsImplTest
, NavigateFromRestoredSitelessUrl
) {
801 WebContentsImplTestBrowserClient browser_client
;
802 SetBrowserClientForTesting(&browser_client
);
803 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
804 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
806 // Restore a navigation entry for URL that should not assign site to the
808 browser_client
.set_assign_site_for_url(false);
809 const GURL
native_url("non-site-url://stuffandthings");
810 ScopedVector
<NavigationEntry
> entries
;
811 scoped_ptr
<NavigationEntry
> new_entry
=
812 NavigationControllerImpl::CreateNavigationEntry(
813 native_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false,
814 std::string(), browser_context());
815 new_entry
->SetPageID(0);
816 entries
.push_back(new_entry
.Pass());
817 controller().Restore(
819 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
821 ASSERT_EQ(0u, entries
.size());
822 ASSERT_EQ(1, controller().GetEntryCount());
824 controller().GoToIndex(0);
825 NavigationEntry
* entry
= controller().GetPendingEntry();
826 orig_rfh
->PrepareForCommit();
827 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
828 native_url
, ui::PAGE_TRANSITION_RELOAD
);
829 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
830 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
831 EXPECT_FALSE(orig_instance
->HasSite());
833 // Navigate to a regular site and verify that the SiteInstance was kept.
834 browser_client
.set_assign_site_for_url(true);
835 const GURL
url("http://www.google.com");
836 controller().LoadURL(
837 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
838 entry
= controller().GetPendingEntry();
839 orig_rfh
->PrepareForCommit();
840 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, url
,
841 ui::PAGE_TRANSITION_TYPED
);
842 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
848 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
849 // tab is restored, the SiteInstance will change upon navigation.
850 TEST_F(WebContentsImplTest
, NavigateFromRestoredRegularUrl
) {
851 WebContentsImplTestBrowserClient browser_client
;
852 SetBrowserClientForTesting(&browser_client
);
853 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
854 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
856 // Restore a navigation entry for a regular URL ensuring that the embedder
857 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
858 browser_client
.set_assign_site_for_url(true);
859 const GURL
regular_url("http://www.yahoo.com");
860 ScopedVector
<NavigationEntry
> entries
;
861 scoped_ptr
<NavigationEntry
> new_entry
=
862 NavigationControllerImpl::CreateNavigationEntry(
863 regular_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false,
864 std::string(), browser_context());
865 new_entry
->SetPageID(0);
866 entries
.push_back(new_entry
.Pass());
867 controller().Restore(
869 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
871 ASSERT_EQ(0u, entries
.size());
873 ASSERT_EQ(1, controller().GetEntryCount());
874 controller().GoToIndex(0);
875 NavigationEntry
* entry
= controller().GetPendingEntry();
876 orig_rfh
->PrepareForCommit();
877 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
878 regular_url
, ui::PAGE_TRANSITION_RELOAD
);
879 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
880 EXPECT_TRUE(orig_instance
->HasSite());
882 // Navigate to another site and verify that a new SiteInstance was created.
883 const GURL
url("http://www.google.com");
884 controller().LoadURL(
885 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
886 entry
= controller().GetPendingEntry();
887 orig_rfh
->PrepareForCommit();
888 contents()->TestDidNavigate(contents()->GetPendingMainFrame(), 2,
889 entry
->GetUniqueID(), true, url
,
890 ui::PAGE_TRANSITION_TYPED
);
891 EXPECT_NE(orig_instance
, contents()->GetSiteInstance());
897 // Test that we can find an opener RVH even if it's pending.
898 // http://crbug.com/176252.
899 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
900 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
902 // Navigate to a URL.
903 const GURL
url("http://www.google.com");
904 controller().LoadURL(
905 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
906 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
907 orig_rfh
->PrepareForCommit();
908 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
909 ui::PAGE_TRANSITION_TYPED
);
911 // Start to navigate first tab to a new site, so that it has a pending RVH.
912 const GURL
url2("http://www.yahoo.com");
913 controller().LoadURL(
914 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
915 orig_rfh
->PrepareForCommit();
916 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
917 SiteInstance
* instance
= pending_rfh
->GetSiteInstance();
919 // While it is still pending, simulate opening a new tab with the first tab
920 // as its opener. This will call CreateOpenerProxies on the opener to ensure
921 // that an RVH exists.
922 scoped_ptr
<TestWebContents
> popup(
923 TestWebContents::Create(browser_context(), instance
));
924 popup
->SetOpener(contents());
925 contents()->GetRenderManager()->CreateOpenerProxies(instance
);
927 // If swapped out is forbidden, a new proxy should be created for the opener
928 // in |instance|, and we should ensure that its routing ID is returned here.
929 // Otherwise, we should find the pending RFH and not create a new proxy.
930 int opener_frame_routing_id
=
931 popup
->GetRenderManager()->GetOpenerRoutingID(instance
);
932 RenderFrameProxyHost
* proxy
=
933 contents()->GetRenderManager()->GetRenderFrameProxyHost(instance
);
934 if (RenderFrameHostManager::IsSwappedOutStateForbidden()) {
936 EXPECT_EQ(proxy
->GetRoutingID(), opener_frame_routing_id
);
938 // Ensure that committing the navigation removes the proxy.
939 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
940 contents()->TestDidNavigate(pending_rfh
, 2, entry_id
, true, url2
,
941 ui::PAGE_TRANSITION_TYPED
);
943 contents()->GetRenderManager()->GetRenderFrameProxyHost(instance
));
946 EXPECT_EQ(pending_rfh
->GetRoutingID(), opener_frame_routing_id
);
950 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
951 // to determine whether a navigation is cross-site.
952 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
953 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
954 SiteInstance
* instance1
= contents()->GetSiteInstance();
957 const GURL
url("http://www.google.com");
958 controller().LoadURL(
959 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
960 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
961 contents()->GetMainFrame()->PrepareForCommit();
962 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
963 ui::PAGE_TRANSITION_TYPED
);
965 // Open a related contents to a second site.
966 scoped_ptr
<TestWebContents
> contents2(
967 TestWebContents::Create(browser_context(), instance1
));
968 const GURL
url2("http://www.yahoo.com");
969 contents2
->GetController().LoadURL(url2
, Referrer(),
970 ui::PAGE_TRANSITION_TYPED
,
972 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
973 contents2
->GetMainFrame()->PrepareForCommit();
975 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
977 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
978 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
979 contents2
->TestDidNavigate(rfh2
, 2, entry_id
, true, url2
,
980 ui::PAGE_TRANSITION_TYPED
);
981 SiteInstance
* instance2
= contents2
->GetSiteInstance();
982 EXPECT_NE(instance1
, instance2
);
983 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
985 // Simulate a link click in first contents to second site. Doesn't switch
986 // SiteInstances, because we don't intercept Blink navigations.
987 orig_rfh
->SendRendererInitiatedNavigationRequest(url2
, true);
988 orig_rfh
->PrepareForCommit();
989 contents()->TestDidNavigate(orig_rfh
, 2, 0, true, url2
,
990 ui::PAGE_TRANSITION_TYPED
);
991 SiteInstance
* instance3
= contents()->GetSiteInstance();
992 EXPECT_EQ(instance1
, instance3
);
993 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
995 // Navigate to the new site. Doesn't switch SiteInstancees, because we
996 // compare against the current URL, not the SiteInstance's site.
997 const GURL
url3("http://mail.yahoo.com");
998 controller().LoadURL(
999 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1000 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1001 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1002 contents()->GetMainFrame()->PrepareForCommit();
1003 contents()->TestDidNavigate(orig_rfh
, 3, entry_id
, true, url3
,
1004 ui::PAGE_TRANSITION_TYPED
);
1005 SiteInstance
* instance4
= contents()->GetSiteInstance();
1006 EXPECT_EQ(instance1
, instance4
);
1009 // Test that the onbeforeunload and onunload handlers run when navigating
1010 // across site boundaries.
1011 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
1012 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1013 SiteInstance
* instance1
= contents()->GetSiteInstance();
1015 // Navigate to URL. First URL should use first RenderViewHost.
1016 const GURL
url("http://www.google.com");
1017 controller().LoadURL(
1018 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1019 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1020 contents()->GetMainFrame()->PrepareForCommit();
1021 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1022 ui::PAGE_TRANSITION_TYPED
);
1023 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1024 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1026 // Navigate to new site, but simulate an onbeforeunload denial.
1027 const GURL
url2("http://www.yahoo.com");
1028 controller().LoadURL(
1029 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1030 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1031 base::TimeTicks now
= base::TimeTicks::Now();
1032 orig_rfh
->OnMessageReceived(
1033 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
1034 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1035 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1036 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1038 // Navigate again, but simulate an onbeforeunload approval.
1039 controller().LoadURL(
1040 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1041 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1042 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1043 now
= base::TimeTicks::Now();
1044 orig_rfh
->PrepareForCommit();
1045 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1046 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1047 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1049 // We won't hear DidNavigate until the onunload handler has finished running.
1051 // DidNavigate from the pending page.
1052 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1053 ui::PAGE_TRANSITION_TYPED
);
1054 SiteInstance
* instance2
= contents()->GetSiteInstance();
1055 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1056 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1057 EXPECT_NE(instance1
, instance2
);
1058 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1061 // Test that during a slow cross-site navigation, the original renderer can
1062 // navigate to a different URL and have it displayed, canceling the slow
1064 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
1065 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1066 SiteInstance
* instance1
= contents()->GetSiteInstance();
1068 // Navigate to URL. First URL should use first RenderFrameHost.
1069 const GURL
url("http://www.google.com");
1070 controller().LoadURL(
1071 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1072 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1073 contents()->GetMainFrame()->PrepareForCommit();
1074 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1075 ui::PAGE_TRANSITION_TYPED
);
1076 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1077 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1079 // Navigate to new site, simulating an onbeforeunload approval.
1080 const GURL
url2("http://www.yahoo.com");
1081 controller().LoadURL(
1082 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1083 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1084 orig_rfh
->PrepareForCommit();
1085 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1087 // Suppose the original renderer navigates before the new one is ready.
1088 orig_rfh
->SendNavigate(2, 0, true, GURL("http://www.google.com/foo"));
1090 // Verify that the pending navigation is cancelled.
1091 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1092 SiteInstance
* instance2
= contents()->GetSiteInstance();
1093 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1094 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1095 EXPECT_EQ(instance1
, instance2
);
1096 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1099 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1100 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1101 const GURL
url1("chrome://gpu");
1102 controller().LoadURL(
1103 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1104 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1105 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
1106 ntp_rfh
->PrepareForCommit();
1107 contents()->TestDidNavigate(ntp_rfh
, 1, entry_id
, true, url1
,
1108 ui::PAGE_TRANSITION_TYPED
);
1109 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1110 SiteInstance
* instance1
= contents()->GetSiteInstance();
1112 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1113 EXPECT_EQ(ntp_rfh
, contents()->GetMainFrame());
1114 EXPECT_EQ(url1
, entry1
->GetURL());
1115 EXPECT_EQ(instance1
,
1116 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1117 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1118 BINDINGS_POLICY_WEB_UI
);
1120 // Navigate to new site.
1121 const GURL
url2("http://www.google.com");
1122 controller().LoadURL(
1123 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1124 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1125 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1126 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1128 // Simulate beforeunload approval.
1129 EXPECT_TRUE(ntp_rfh
->is_waiting_for_beforeunload_ack());
1130 base::TimeTicks now
= base::TimeTicks::Now();
1131 ntp_rfh
->PrepareForCommit();
1133 // DidNavigate from the pending page.
1134 contents()->TestDidNavigate(google_rfh
, 1, entry_id
, true, url2
,
1135 ui::PAGE_TRANSITION_TYPED
);
1136 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1137 SiteInstance
* instance2
= contents()->GetSiteInstance();
1139 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1140 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1141 EXPECT_NE(instance1
, instance2
);
1142 EXPECT_FALSE(contents()->GetPendingMainFrame());
1143 EXPECT_EQ(url2
, entry2
->GetURL());
1144 EXPECT_EQ(instance2
,
1145 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1146 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1147 BINDINGS_POLICY_WEB_UI
);
1149 // Navigate to third page on same site.
1150 const GURL
url3("http://news.google.com");
1151 controller().LoadURL(
1152 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1153 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1154 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1155 contents()->GetMainFrame()->PrepareForCommit();
1156 contents()->TestDidNavigate(google_rfh
, 2, entry_id
, true, url3
,
1157 ui::PAGE_TRANSITION_TYPED
);
1158 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1159 SiteInstance
* instance3
= contents()->GetSiteInstance();
1161 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1162 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1163 EXPECT_EQ(instance2
, instance3
);
1164 EXPECT_FALSE(contents()->GetPendingMainFrame());
1165 EXPECT_EQ(url3
, entry3
->GetURL());
1166 EXPECT_EQ(instance3
,
1167 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1169 // Go back within the site.
1170 controller().GoBack();
1171 NavigationEntry
* goback_entry
= controller().GetPendingEntry();
1172 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1173 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1175 // Before that commits, go back again.
1176 controller().GoBack();
1177 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1178 EXPECT_TRUE(contents()->GetPendingMainFrame());
1179 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1181 // Simulate beforeunload approval.
1182 EXPECT_TRUE(google_rfh
->is_waiting_for_beforeunload_ack());
1183 now
= base::TimeTicks::Now();
1184 google_rfh
->PrepareForCommit();
1185 google_rfh
->OnMessageReceived(
1186 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1188 // DidNavigate from the first back. This aborts the second back's pending RFH.
1189 contents()->TestDidNavigate(google_rfh
, 1, goback_entry
->GetUniqueID(), false,
1190 url2
, ui::PAGE_TRANSITION_TYPED
);
1192 // We should commit this page and forget about the second back.
1193 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1194 EXPECT_FALSE(controller().GetPendingEntry());
1195 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1196 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1198 // We should not have corrupted the NTP entry.
1199 EXPECT_EQ(instance3
,
1200 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1201 EXPECT_EQ(instance2
,
1202 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1203 EXPECT_EQ(instance1
,
1204 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1205 EXPECT_EQ(url1
, entry1
->GetURL());
1208 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1209 // original renderer will not cancel the slow navigation (bug 42029).
1210 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1211 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1213 // Navigate to URL. First URL should use the original RenderFrameHost.
1214 const GURL
url("http://www.google.com");
1215 controller().LoadURL(
1216 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1217 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1218 contents()->GetMainFrame()->PrepareForCommit();
1219 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1220 ui::PAGE_TRANSITION_TYPED
);
1221 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1222 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1224 // Start navigating to new site.
1225 const GURL
url2("http://www.yahoo.com");
1226 controller().LoadURL(
1227 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1229 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1230 // waiting for a before unload response.
1231 TestRenderFrameHost
* child_rfh
= orig_rfh
->AppendChild("subframe");
1232 child_rfh
->SendNavigateWithTransition(1, 0, false,
1233 GURL("http://google.com/frame"),
1234 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
1235 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1237 // Now simulate the onbeforeunload approval and verify the navigation is
1239 orig_rfh
->PrepareForCommit();
1240 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1241 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1245 void SetAsNonUserGesture(FrameHostMsg_DidCommitProvisionalLoad_Params
* params
) {
1246 params
->gesture
= NavigationGestureAuto
;
1250 // Test that a cross-site navigation is not preempted if the previous
1251 // renderer sends a FrameNavigate message just before being told to stop.
1252 // We should only preempt the cross-site navigation if the previous renderer
1253 // has started a new navigation. See http://crbug.com/79176.
1254 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1255 // Navigate to WebUI URL.
1256 const GURL
url("chrome://gpu");
1257 controller().LoadURL(
1258 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1259 int entry1_id
= controller().GetPendingEntry()->GetUniqueID();
1260 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1261 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1263 // Navigate to new site, with the beforeunload request in flight.
1264 const GURL
url2("http://www.yahoo.com");
1265 controller().LoadURL(
1266 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1267 int entry2_id
= controller().GetPendingEntry()->GetUniqueID();
1268 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1269 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1270 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1271 EXPECT_NE(orig_rfh
, pending_rfh
);
1273 // Suppose the first navigation tries to commit now, with a
1274 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1275 // but it should act as if the beforeunload ack arrived.
1276 orig_rfh
->SendNavigateWithModificationCallback(
1277 1, entry1_id
, true, url
, base::Bind(SetAsNonUserGesture
));
1278 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1279 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1280 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1281 // It should commit.
1282 ASSERT_EQ(1, controller().GetEntryCount());
1283 EXPECT_EQ(url
, controller().GetLastCommittedEntry()->GetURL());
1285 // The pending navigation should be able to commit successfully.
1286 contents()->TestDidNavigate(pending_rfh
, 1, entry2_id
, true, url2
,
1287 ui::PAGE_TRANSITION_TYPED
);
1288 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1289 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1290 EXPECT_EQ(2, controller().GetEntryCount());
1293 // Test that NavigationEntries have the correct page state after going
1294 // forward and back. Prevents regression for bug 1116137.
1295 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1296 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1298 // Navigate to URL. There should be no committed entry yet.
1299 const GURL
url("http://www.google.com");
1300 controller().LoadURL(
1301 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1302 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1303 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1304 EXPECT_EQ(nullptr, entry
);
1306 // Committed entry should have page state after DidNavigate.
1307 orig_rfh
->PrepareForCommit();
1308 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1309 ui::PAGE_TRANSITION_TYPED
);
1310 entry
= controller().GetLastCommittedEntry();
1311 EXPECT_TRUE(entry
->GetPageState().IsValid());
1313 // Navigate to same site.
1314 const GURL
url2("http://images.google.com");
1315 controller().LoadURL(
1316 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1317 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1318 entry
= controller().GetLastCommittedEntry();
1319 EXPECT_TRUE(entry
->GetPageState().IsValid());
1321 // Committed entry should have page state after DidNavigate.
1322 orig_rfh
->PrepareForCommit();
1323 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1324 ui::PAGE_TRANSITION_TYPED
);
1325 entry
= controller().GetLastCommittedEntry();
1326 EXPECT_TRUE(entry
->GetPageState().IsValid());
1328 // Now go back. Committed entry should still have page state.
1329 controller().GoBack();
1330 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1331 orig_rfh
->PrepareForCommit();
1332 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, false, url
,
1333 ui::PAGE_TRANSITION_TYPED
);
1334 entry
= controller().GetLastCommittedEntry();
1335 EXPECT_TRUE(entry
->GetPageState().IsValid());
1338 // Test that NavigationEntries have the correct page state and SiteInstance
1339 // state after opening a new window to about:blank. Prevents regression for
1340 // bugs b/1116137 and http://crbug.com/111975.
1341 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1342 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1344 // Navigate to about:blank.
1345 const GURL
url(url::kAboutBlankURL
);
1346 orig_rfh
->SendRendererInitiatedNavigationRequest(url
, false);
1347 contents()->TestDidNavigate(orig_rfh
, 1, 0, true, url
,
1348 ui::PAGE_TRANSITION_TYPED
);
1350 // Should have a page state here.
1351 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1352 EXPECT_TRUE(entry
->GetPageState().IsValid());
1354 // The SiteInstance should be available for other navigations to use.
1355 NavigationEntryImpl
* entry_impl
=
1356 NavigationEntryImpl::FromNavigationEntry(entry
);
1357 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1358 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1360 // Navigating to a normal page should not cause a process swap.
1361 const GURL
new_url("http://www.google.com");
1362 controller().LoadURL(new_url
, Referrer(),
1363 ui::PAGE_TRANSITION_TYPED
, std::string());
1364 entry
= controller().GetPendingEntry();
1365 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1366 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1367 orig_rfh
->PrepareForCommit();
1368 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, new_url
,
1369 ui::PAGE_TRANSITION_TYPED
);
1370 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1371 controller().GetLastCommittedEntry());
1372 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1373 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1376 // Tests that fullscreen is exited throughout the object hierarchy when
1377 // navigating to a new page.
1378 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1379 FakeFullscreenDelegate fake_delegate
;
1380 contents()->SetDelegate(&fake_delegate
);
1381 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1382 TestRenderViewHost
* orig_rvh
= orig_rfh
->GetRenderViewHost();
1384 // Navigate to a site.
1385 const GURL
url("http://www.google.com");
1386 controller().LoadURL(
1387 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1388 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1389 contents()->GetMainFrame()->PrepareForCommit();
1390 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1391 ui::PAGE_TRANSITION_TYPED
);
1392 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1394 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1395 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1396 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1397 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1398 orig_rfh
->OnMessageReceived(
1399 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1400 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1401 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1402 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1404 // Navigate to a new site.
1405 const GURL
url2("http://www.yahoo.com");
1406 controller().LoadURL(
1407 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1408 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1409 contents()->GetMainFrame()->PrepareForCommit();
1410 TestRenderFrameHost
* const pending_rfh
= contents()->GetPendingMainFrame();
1411 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1412 ui::PAGE_TRANSITION_TYPED
);
1414 // Confirm fullscreen has exited.
1415 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1416 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1417 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1419 contents()->SetDelegate(nullptr);
1422 // Tests that fullscreen is exited throughout the object hierarchy when
1423 // instructing NavigationController to GoBack() or GoForward().
1424 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1425 FakeFullscreenDelegate fake_delegate
;
1426 contents()->SetDelegate(&fake_delegate
);
1427 TestRenderFrameHost
* const orig_rfh
= contents()->GetMainFrame();
1428 TestRenderViewHost
* const orig_rvh
= orig_rfh
->GetRenderViewHost();
1430 // Navigate to a site.
1431 const GURL
url("http://www.google.com");
1432 controller().LoadURL(
1433 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1434 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1435 orig_rfh
->PrepareForCommit();
1436 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1437 ui::PAGE_TRANSITION_TYPED
);
1438 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1440 // Now, navigate to another page on the same site.
1441 const GURL
url2("http://www.google.com/search?q=kittens");
1442 controller().LoadURL(
1443 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1444 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1445 orig_rfh
->PrepareForCommit();
1446 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1447 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1448 ui::PAGE_TRANSITION_TYPED
);
1449 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1451 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1452 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1453 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1454 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1456 for (int i
= 0; i
< 2; ++i
) {
1457 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1458 orig_rfh
->OnMessageReceived(
1459 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1460 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1461 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1462 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1464 // Navigate backward (or forward).
1466 controller().GoBack();
1468 controller().GoForward();
1469 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1470 orig_rfh
->PrepareForCommit();
1471 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1472 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1473 contents()->TestDidNavigate(orig_rfh
, i
+ 1, entry_id
, false, url
,
1474 ui::PAGE_TRANSITION_FORWARD_BACK
);
1476 // Confirm fullscreen has exited.
1477 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1478 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1479 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1482 contents()->SetDelegate(nullptr);
1485 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1486 FakeValidationMessageDelegate fake_delegate
;
1487 contents()->SetDelegate(&fake_delegate
);
1488 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1490 // Initialize the RenderFrame and then simulate crashing the renderer
1492 contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
1493 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1495 // Confirm HideValidationMessage was called.
1496 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1498 contents()->SetDelegate(nullptr);
1501 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1503 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1504 FakeFullscreenDelegate fake_delegate
;
1505 contents()->SetDelegate(&fake_delegate
);
1507 // Navigate to a site.
1508 const GURL
url("http://www.google.com");
1509 controller().LoadURL(
1510 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1511 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1512 main_test_rfh()->PrepareForCommit();
1513 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
1514 url
, ui::PAGE_TRANSITION_TYPED
);
1516 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1517 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1518 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1519 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1520 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1521 contents()->GetMainFrame()->GetRoutingID(), true));
1522 EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
1523 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1524 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1526 // Crash the renderer.
1527 main_test_rfh()->GetProcess()->SimulateCrash();
1529 // Confirm fullscreen has exited.
1530 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1531 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1532 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1534 contents()->SetDelegate(nullptr);
1537 ////////////////////////////////////////////////////////////////////////////////
1538 // Interstitial Tests
1539 ////////////////////////////////////////////////////////////////////////////////
1541 // Test navigating to a page (with the navigation initiated from the browser,
1542 // as when a URL is typed in the location bar) that shows an interstitial and
1543 // creates a new navigation entry, then hiding it without proceeding.
1544 TEST_F(WebContentsImplTest
,
1545 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1546 // Navigate to a page.
1547 GURL
url1("http://www.google.com");
1548 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1549 EXPECT_EQ(1, controller().GetEntryCount());
1551 // Initiate a browser navigation that will trigger the interstitial.
1552 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1553 ui::PAGE_TRANSITION_TYPED
, std::string());
1554 NavigationEntry
* entry
= controller().GetPendingEntry();
1556 // Show an interstitial.
1557 TestInterstitialPage::InterstitialState state
=
1558 TestInterstitialPage::INVALID
;
1559 bool deleted
= false;
1560 GURL
url2("http://interstitial");
1561 TestInterstitialPage
* interstitial
=
1562 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1563 TestInterstitialPageStateGuard
state_guard(interstitial
);
1564 interstitial
->Show();
1565 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1566 // The interstitial should not show until its navigation has committed.
1567 EXPECT_FALSE(interstitial
->is_showing());
1568 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1569 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1570 // Let's commit the interstitial navigation.
1571 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1572 EXPECT_TRUE(interstitial
->is_showing());
1573 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1574 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1575 entry
= controller().GetVisibleEntry();
1576 ASSERT_NE(nullptr, entry
);
1577 EXPECT_TRUE(entry
->GetURL() == url2
);
1579 // Now don't proceed.
1580 interstitial
->DontProceed();
1581 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1582 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1583 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1584 entry
= controller().GetVisibleEntry();
1585 ASSERT_NE(nullptr, entry
);
1586 EXPECT_TRUE(entry
->GetURL() == url1
);
1587 EXPECT_EQ(1, controller().GetEntryCount());
1589 RunAllPendingInMessageLoop();
1590 EXPECT_TRUE(deleted
);
1593 // Test navigating to a page (with the navigation initiated from the renderer,
1594 // as when clicking on a link in the page) that shows an interstitial and
1595 // creates a new navigation entry, then hiding it without proceeding.
1596 TEST_F(WebContentsImplTest
,
1597 ShowInterstitialFromRendererWithNewNavigationDontProceed
) {
1598 // Navigate to a page.
1599 GURL
url1("http://www.google.com");
1600 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1601 EXPECT_EQ(1, controller().GetEntryCount());
1603 // Show an interstitial (no pending entry, the interstitial would have been
1604 // triggered by clicking on a link).
1605 TestInterstitialPage::InterstitialState state
=
1606 TestInterstitialPage::INVALID
;
1607 bool deleted
= false;
1608 GURL
url2("http://interstitial");
1609 TestInterstitialPage
* interstitial
=
1610 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1611 TestInterstitialPageStateGuard
state_guard(interstitial
);
1612 interstitial
->Show();
1613 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1614 // The interstitial should not show until its navigation has committed.
1615 EXPECT_FALSE(interstitial
->is_showing());
1616 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1617 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1618 // Let's commit the interstitial navigation.
1619 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1620 EXPECT_TRUE(interstitial
->is_showing());
1621 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1622 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1623 NavigationEntry
* entry
= controller().GetVisibleEntry();
1624 ASSERT_NE(nullptr, entry
);
1625 EXPECT_TRUE(entry
->GetURL() == url2
);
1627 // Now don't proceed.
1628 interstitial
->DontProceed();
1629 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1630 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1631 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1632 entry
= controller().GetVisibleEntry();
1633 ASSERT_NE(nullptr, entry
);
1634 EXPECT_TRUE(entry
->GetURL() == url1
);
1635 EXPECT_EQ(1, controller().GetEntryCount());
1637 RunAllPendingInMessageLoop();
1638 EXPECT_TRUE(deleted
);
1641 // Test navigating to a page that shows an interstitial without creating a new
1642 // navigation entry (this happens when the interstitial is triggered by a
1643 // sub-resource in the page), then hiding it without proceeding.
1644 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1645 // Navigate to a page.
1646 GURL
url1("http://www.google.com");
1647 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1648 EXPECT_EQ(1, controller().GetEntryCount());
1650 // Show an interstitial.
1651 TestInterstitialPage::InterstitialState state
=
1652 TestInterstitialPage::INVALID
;
1653 bool deleted
= false;
1654 GURL
url2("http://interstitial");
1655 TestInterstitialPage
* interstitial
=
1656 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1657 TestInterstitialPageStateGuard
state_guard(interstitial
);
1658 interstitial
->Show();
1659 // The interstitial should not show until its navigation has committed.
1660 EXPECT_FALSE(interstitial
->is_showing());
1661 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1662 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1663 // Let's commit the interstitial navigation.
1664 interstitial
->TestDidNavigate(1, 0, true, url2
);
1665 EXPECT_TRUE(interstitial
->is_showing());
1666 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1667 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1668 NavigationEntry
* entry
= controller().GetVisibleEntry();
1669 ASSERT_NE(nullptr, entry
);
1670 // The URL specified to the interstitial should have been ignored.
1671 EXPECT_TRUE(entry
->GetURL() == url1
);
1673 // Now don't proceed.
1674 interstitial
->DontProceed();
1675 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1676 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1677 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1678 entry
= controller().GetVisibleEntry();
1679 ASSERT_NE(nullptr, entry
);
1680 EXPECT_TRUE(entry
->GetURL() == url1
);
1681 EXPECT_EQ(1, controller().GetEntryCount());
1683 RunAllPendingInMessageLoop();
1684 EXPECT_TRUE(deleted
);
1687 // Test navigating to a page (with the navigation initiated from the browser,
1688 // as when a URL is typed in the location bar) that shows an interstitial and
1689 // creates a new navigation entry, then proceeding.
1690 TEST_F(WebContentsImplTest
,
1691 ShowInterstitialFromBrowserNewNavigationProceed
) {
1692 // Navigate to a page.
1693 GURL
url1("http://www.google.com");
1694 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1695 EXPECT_EQ(1, controller().GetEntryCount());
1697 // Initiate a browser navigation that will trigger the interstitial
1698 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1699 ui::PAGE_TRANSITION_TYPED
, std::string());
1701 // Show an interstitial.
1702 TestInterstitialPage::InterstitialState state
=
1703 TestInterstitialPage::INVALID
;
1704 bool deleted
= false;
1705 GURL
url2("http://interstitial");
1706 TestInterstitialPage
* interstitial
=
1707 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1708 TestInterstitialPageStateGuard
state_guard(interstitial
);
1709 interstitial
->Show();
1710 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1711 // The interstitial should not show until its navigation has committed.
1712 EXPECT_FALSE(interstitial
->is_showing());
1713 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1714 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1715 // Let's commit the interstitial navigation.
1716 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1717 EXPECT_TRUE(interstitial
->is_showing());
1718 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1719 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1720 NavigationEntry
* entry
= controller().GetVisibleEntry();
1721 ASSERT_NE(nullptr, entry
);
1722 EXPECT_TRUE(entry
->GetURL() == url2
);
1725 interstitial
->Proceed();
1726 // The interstitial should show until the new navigation commits.
1727 RunAllPendingInMessageLoop();
1728 ASSERT_FALSE(deleted
);
1729 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1730 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1731 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1733 // Simulate the navigation to the page, that's when the interstitial gets
1735 GURL
url3("http://www.thepage.com");
1736 contents()->GetMainFrame()->PrepareForCommit();
1737 contents()->GetMainFrame()->SendNavigate(2, 0, true, url3
);
1739 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1740 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1741 entry
= controller().GetVisibleEntry();
1742 ASSERT_NE(nullptr, entry
);
1743 EXPECT_TRUE(entry
->GetURL() == url3
);
1745 EXPECT_EQ(2, controller().GetEntryCount());
1747 RunAllPendingInMessageLoop();
1748 EXPECT_TRUE(deleted
);
1751 // Test navigating to a page (with the navigation initiated from the renderer,
1752 // as when clicking on a link in the page) that shows an interstitial and
1753 // creates a new navigation entry, then proceeding.
1754 TEST_F(WebContentsImplTest
,
1755 ShowInterstitialFromRendererNewNavigationProceed
) {
1756 // Navigate to a page.
1757 GURL
url1("http://www.google.com");
1758 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1759 EXPECT_EQ(1, controller().GetEntryCount());
1761 // Show an interstitial.
1762 TestInterstitialPage::InterstitialState state
=
1763 TestInterstitialPage::INVALID
;
1764 bool deleted
= false;
1765 GURL
url2("http://interstitial");
1766 TestInterstitialPage
* interstitial
=
1767 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1768 TestInterstitialPageStateGuard
state_guard(interstitial
);
1769 interstitial
->Show();
1770 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1771 // The interstitial should not show until its navigation has committed.
1772 EXPECT_FALSE(interstitial
->is_showing());
1773 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1774 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1775 // Let's commit the interstitial navigation.
1776 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1777 EXPECT_TRUE(interstitial
->is_showing());
1778 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1779 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1780 NavigationEntry
* entry
= controller().GetVisibleEntry();
1781 ASSERT_NE(nullptr, entry
);
1782 EXPECT_TRUE(entry
->GetURL() == url2
);
1785 interstitial
->Proceed();
1786 // The interstitial should show until the new navigation commits.
1787 RunAllPendingInMessageLoop();
1788 ASSERT_FALSE(deleted
);
1789 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1790 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1791 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1793 // Simulate the navigation to the page, that's when the interstitial gets
1795 GURL
url3("http://www.thepage.com");
1796 main_test_rfh()->NavigateAndCommitRendererInitiated(2, true, url3
);
1798 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1799 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1800 entry
= controller().GetVisibleEntry();
1801 ASSERT_NE(nullptr, entry
);
1802 EXPECT_TRUE(entry
->GetURL() == url3
);
1804 EXPECT_EQ(2, controller().GetEntryCount());
1806 RunAllPendingInMessageLoop();
1807 EXPECT_TRUE(deleted
);
1810 // Test navigating to a page that shows an interstitial without creating a new
1811 // navigation entry (this happens when the interstitial is triggered by a
1812 // sub-resource in the page), then proceeding.
1813 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1814 // Navigate to a page so we have a navigation entry in the controller.
1815 GURL
url1("http://www.google.com");
1816 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1817 EXPECT_EQ(1, controller().GetEntryCount());
1819 // Show an interstitial.
1820 TestInterstitialPage::InterstitialState state
=
1821 TestInterstitialPage::INVALID
;
1822 bool deleted
= false;
1823 GURL
url2("http://interstitial");
1824 TestInterstitialPage
* interstitial
=
1825 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1826 TestInterstitialPageStateGuard
state_guard(interstitial
);
1827 interstitial
->Show();
1828 // The interstitial should not show until its navigation has committed.
1829 EXPECT_FALSE(interstitial
->is_showing());
1830 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1831 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1832 // Let's commit the interstitial navigation.
1833 interstitial
->TestDidNavigate(1, 0, true, url2
);
1834 EXPECT_TRUE(interstitial
->is_showing());
1835 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1836 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1837 NavigationEntry
* entry
= controller().GetVisibleEntry();
1838 ASSERT_NE(nullptr, entry
);
1839 // The URL specified to the interstitial should have been ignored.
1840 EXPECT_TRUE(entry
->GetURL() == url1
);
1843 interstitial
->Proceed();
1844 // Since this is not a new navigation, the previous page is dismissed right
1845 // away and shows the original page.
1846 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1847 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1848 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1849 entry
= controller().GetVisibleEntry();
1850 ASSERT_NE(nullptr, entry
);
1851 EXPECT_TRUE(entry
->GetURL() == url1
);
1853 EXPECT_EQ(1, controller().GetEntryCount());
1855 RunAllPendingInMessageLoop();
1856 EXPECT_TRUE(deleted
);
1859 // Test navigating to a page that shows an interstitial, then navigating away.
1860 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1861 // Show interstitial.
1862 TestInterstitialPage::InterstitialState state
=
1863 TestInterstitialPage::INVALID
;
1864 bool deleted
= false;
1865 GURL
url("http://interstitial");
1866 TestInterstitialPage
* interstitial
=
1867 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1868 TestInterstitialPageStateGuard
state_guard(interstitial
);
1869 interstitial
->Show();
1870 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1871 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
1873 // While interstitial showing, navigate to a new URL.
1874 const GURL
url2("http://www.yahoo.com");
1875 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2
);
1877 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1879 RunAllPendingInMessageLoop();
1880 EXPECT_TRUE(deleted
);
1883 // Test navigating to a page that shows an interstitial, then going back.
1884 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1885 // Navigate to a page so we have a navigation entry in the controller.
1886 GURL
url1("http://www.google.com");
1887 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1888 EXPECT_EQ(1, controller().GetEntryCount());
1890 // Show interstitial.
1891 TestInterstitialPage::InterstitialState state
=
1892 TestInterstitialPage::INVALID
;
1893 bool deleted
= false;
1894 GURL
interstitial_url("http://interstitial");
1895 TestInterstitialPage
* interstitial
=
1896 new TestInterstitialPage(contents(), true, interstitial_url
,
1898 TestInterstitialPageStateGuard
state_guard(interstitial
);
1899 interstitial
->Show();
1900 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1901 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1903 EXPECT_EQ(2, controller().GetEntryCount());
1905 // While the interstitial is showing, go back. This will dismiss the
1906 // interstitial and not initiate a navigation, but just show the existing
1908 controller().GoBack();
1910 // Make sure we are back to the original page and that the interstitial is
1912 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1913 NavigationEntry
* entry
= controller().GetVisibleEntry();
1915 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1916 EXPECT_EQ(1, controller().GetEntryCount());
1918 RunAllPendingInMessageLoop();
1919 EXPECT_TRUE(deleted
);
1922 // Test navigating to a page that shows an interstitial, has a renderer crash,
1923 // and then goes back.
1924 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1925 // Navigate to a page so we have a navigation entry in the controller.
1926 GURL
url1("http://www.google.com");
1927 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1928 EXPECT_EQ(1, controller().GetEntryCount());
1929 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1931 // Show interstitial.
1932 TestInterstitialPage::InterstitialState state
=
1933 TestInterstitialPage::INVALID
;
1934 bool deleted
= false;
1935 GURL
interstitial_url("http://interstitial");
1936 TestInterstitialPage
* interstitial
=
1937 new TestInterstitialPage(contents(), true, interstitial_url
,
1939 TestInterstitialPageStateGuard
state_guard(interstitial
);
1940 interstitial
->Show();
1941 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1942 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1945 // Crash the renderer
1946 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1948 // While the interstitial is showing, go back. This will dismiss the
1949 // interstitial and not initiate a navigation, but just show the existing
1951 controller().GoBack();
1953 // Make sure we are back to the original page and that the interstitial is
1955 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1956 entry
= controller().GetVisibleEntry();
1958 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1960 RunAllPendingInMessageLoop();
1961 EXPECT_TRUE(deleted
);
1964 // Test navigating to a page that shows an interstitial, has the renderer crash,
1965 // and then navigates to the interstitial.
1966 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1967 // Navigate to a page so we have a navigation entry in the controller.
1968 GURL
url1("http://www.google.com");
1969 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1970 EXPECT_EQ(1, controller().GetEntryCount());
1972 // Show interstitial.
1973 TestInterstitialPage::InterstitialState state
=
1974 TestInterstitialPage::INVALID
;
1975 bool deleted
= false;
1976 GURL
interstitial_url("http://interstitial");
1977 TestInterstitialPage
* interstitial
=
1978 new TestInterstitialPage(contents(), true, interstitial_url
,
1980 TestInterstitialPageStateGuard
state_guard(interstitial
);
1981 interstitial
->Show();
1982 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1984 // Crash the renderer
1985 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1987 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1991 // Test navigating to a page that shows an interstitial, then close the
1993 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1994 // Show interstitial.
1995 TestInterstitialPage::InterstitialState state
=
1996 TestInterstitialPage::INVALID
;
1997 bool deleted
= false;
1998 GURL
url("http://interstitial");
1999 TestInterstitialPage
* interstitial
=
2000 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2001 TestInterstitialPageStateGuard
state_guard(interstitial
);
2002 interstitial
->Show();
2003 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2004 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2006 // Now close the contents.
2008 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2010 RunAllPendingInMessageLoop();
2011 EXPECT_TRUE(deleted
);
2014 // Test navigating to a page that shows an interstitial, then close the
2016 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
2017 // Show interstitial.
2018 TestInterstitialPage::InterstitialState state
=
2019 TestInterstitialPage::INVALID
;
2020 bool deleted
= false;
2021 GURL
url("http://interstitial");
2022 TestInterstitialPage
* interstitial
=
2023 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2024 TestInterstitialPageStateGuard
state_guard(interstitial
);
2025 interstitial
->Show();
2026 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2027 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2028 TestRenderFrameHost
* rfh
=
2029 static_cast<TestRenderFrameHost
*>(interstitial
->GetMainFrame());
2031 // Now close the contents.
2033 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2035 // Before the interstitial has a chance to process its shutdown task,
2036 // simulate quitting the browser. This goes through all processes and
2037 // tells them to destruct.
2038 rfh
->GetProcess()->SimulateCrash();
2040 RunAllPendingInMessageLoop();
2041 EXPECT_TRUE(deleted
);
2044 // Test that after Proceed is called and an interstitial is still shown, no more
2045 // commands get executed.
2046 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
2047 // Navigate to a page so we have a navigation entry in the controller.
2048 GURL
url1("http://www.google.com");
2049 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2050 EXPECT_EQ(1, controller().GetEntryCount());
2052 // Show an interstitial.
2053 TestInterstitialPage::InterstitialState state
=
2054 TestInterstitialPage::INVALID
;
2055 bool deleted
= false;
2056 GURL
url2("http://interstitial");
2057 TestInterstitialPage
* interstitial
=
2058 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2059 TestInterstitialPageStateGuard
state_guard(interstitial
);
2060 interstitial
->Show();
2061 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2062 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2065 EXPECT_EQ(0, interstitial
->command_received_count());
2066 interstitial
->TestDomOperationResponse("toto");
2067 EXPECT_EQ(1, interstitial
->command_received_count());
2070 interstitial
->Proceed();
2071 RunAllPendingInMessageLoop();
2072 ASSERT_FALSE(deleted
);
2074 // While the navigation to the new page is pending, send other commands, they
2075 // should be ignored.
2076 interstitial
->TestDomOperationResponse("hello");
2077 interstitial
->TestDomOperationResponse("hi");
2078 EXPECT_EQ(1, interstitial
->command_received_count());
2081 // Test showing an interstitial while another interstitial is already showing.
2082 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
2083 // Navigate to a page so we have a navigation entry in the controller.
2084 GURL
start_url("http://www.google.com");
2085 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2086 EXPECT_EQ(1, controller().GetEntryCount());
2088 // Show an interstitial.
2089 TestInterstitialPage::InterstitialState state1
=
2090 TestInterstitialPage::INVALID
;
2091 bool deleted1
= false;
2092 GURL
url1("http://interstitial1");
2093 TestInterstitialPage
* interstitial1
=
2094 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2095 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2096 interstitial1
->Show();
2097 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2098 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2100 // Now show another interstitial.
2101 TestInterstitialPage::InterstitialState state2
=
2102 TestInterstitialPage::INVALID
;
2103 bool deleted2
= false;
2104 GURL
url2("http://interstitial2");
2105 TestInterstitialPage
* interstitial2
=
2106 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2107 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2108 interstitial2
->Show();
2109 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2110 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2112 // Showing interstitial2 should have caused interstitial1 to go away.
2113 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2114 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2116 RunAllPendingInMessageLoop();
2117 EXPECT_TRUE(deleted1
);
2118 ASSERT_FALSE(deleted2
);
2120 // Let's make sure interstitial2 is working as intended.
2121 interstitial2
->Proceed();
2122 GURL
landing_url("http://www.thepage.com");
2123 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2125 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2126 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2127 NavigationEntry
* entry
= controller().GetVisibleEntry();
2128 ASSERT_NE(nullptr, entry
);
2129 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2130 EXPECT_EQ(2, controller().GetEntryCount());
2131 RunAllPendingInMessageLoop();
2132 EXPECT_TRUE(deleted2
);
2135 // Test showing an interstitial, proceeding and then navigating to another
2137 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2138 // Navigate to a page so we have a navigation entry in the controller.
2139 GURL
start_url("http://www.google.com");
2140 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2141 EXPECT_EQ(1, controller().GetEntryCount());
2143 // Show an interstitial.
2144 TestInterstitialPage::InterstitialState state1
=
2145 TestInterstitialPage::INVALID
;
2146 bool deleted1
= false;
2147 GURL
url1("http://interstitial1");
2148 TestInterstitialPage
* interstitial1
=
2149 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2150 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2151 interstitial1
->Show();
2152 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2153 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2155 // Take action. The interstitial won't be hidden until the navigation is
2157 interstitial1
->Proceed();
2158 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2160 // Now show another interstitial (simulating the navigation causing another
2162 TestInterstitialPage::InterstitialState state2
=
2163 TestInterstitialPage::INVALID
;
2164 bool deleted2
= false;
2165 GURL
url2("http://interstitial2");
2166 TestInterstitialPage
* interstitial2
=
2167 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2168 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2169 interstitial2
->Show();
2170 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2171 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2173 // Showing interstitial2 should have caused interstitial1 to go away.
2174 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2175 RunAllPendingInMessageLoop();
2176 EXPECT_TRUE(deleted1
);
2177 ASSERT_FALSE(deleted2
);
2179 // Let's make sure interstitial2 is working as intended.
2180 interstitial2
->Proceed();
2181 GURL
landing_url("http://www.thepage.com");
2182 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2184 RunAllPendingInMessageLoop();
2185 EXPECT_TRUE(deleted2
);
2186 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2187 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2188 NavigationEntry
* entry
= controller().GetVisibleEntry();
2189 ASSERT_NE(nullptr, entry
);
2190 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2191 EXPECT_EQ(2, controller().GetEntryCount());
2194 // Test that navigating away from an interstitial while it's loading cause it
2196 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2197 // Show an interstitial.
2198 TestInterstitialPage::InterstitialState state
=
2199 TestInterstitialPage::INVALID
;
2200 bool deleted
= false;
2201 GURL
interstitial_url("http://interstitial");
2202 TestInterstitialPage
* interstitial
=
2203 new TestInterstitialPage(contents(), true, interstitial_url
,
2205 TestInterstitialPageStateGuard
state_guard(interstitial
);
2206 interstitial
->Show();
2207 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2209 // Let's simulate a navigation initiated from the browser before the
2210 // interstitial finishes loading.
2211 const GURL
url("http://www.google.com");
2212 controller().LoadURL(
2213 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2214 EXPECT_FALSE(interstitial
->is_showing());
2215 RunAllPendingInMessageLoop();
2216 ASSERT_FALSE(deleted
);
2218 // Now let's make the interstitial navigation commit.
2219 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true,
2222 // After it loaded the interstitial should be gone.
2223 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2225 RunAllPendingInMessageLoop();
2226 EXPECT_TRUE(deleted
);
2229 // Test that a new request to show an interstitial while an interstitial is
2230 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2231 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2232 GURL
interstitial_url("http://interstitial");
2234 // Show a first interstitial.
2235 TestInterstitialPage::InterstitialState state1
=
2236 TestInterstitialPage::INVALID
;
2237 bool deleted1
= false;
2238 TestInterstitialPage
* interstitial1
=
2239 new TestInterstitialPage(contents(), true, interstitial_url
,
2240 &state1
, &deleted1
);
2241 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2242 interstitial1
->Show();
2244 // Show another interstitial on that same contents before the first one had
2246 TestInterstitialPage::InterstitialState state2
=
2247 TestInterstitialPage::INVALID
;
2248 bool deleted2
= false;
2249 TestInterstitialPage
* interstitial2
=
2250 new TestInterstitialPage(contents(), true, interstitial_url
,
2251 &state2
, &deleted2
);
2252 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2253 interstitial2
->Show();
2254 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2256 // The first interstitial should have been closed and deleted.
2257 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2258 // The 2nd one should still be OK.
2259 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2261 RunAllPendingInMessageLoop();
2262 EXPECT_TRUE(deleted1
);
2263 ASSERT_FALSE(deleted2
);
2265 // Make the interstitial navigation commit it should be showing.
2266 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true,
2268 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2271 // Test showing an interstitial and have its renderer crash.
2272 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2273 // Show an interstitial.
2274 TestInterstitialPage::InterstitialState state
=
2275 TestInterstitialPage::INVALID
;
2276 bool deleted
= false;
2277 GURL
url("http://interstitial");
2278 TestInterstitialPage
* interstitial
=
2279 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2280 TestInterstitialPageStateGuard
state_guard(interstitial
);
2281 interstitial
->Show();
2282 // Simulate a renderer crash before the interstitial is shown.
2283 interstitial
->TestRenderViewTerminated(
2284 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2285 // The interstitial should have been dismissed.
2286 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2287 RunAllPendingInMessageLoop();
2288 EXPECT_TRUE(deleted
);
2290 // Now try again but this time crash the intersitial after it was shown.
2292 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2293 interstitial
->Show();
2294 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2295 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2296 // Simulate a renderer crash.
2297 interstitial
->TestRenderViewTerminated(
2298 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2299 // The interstitial should have been dismissed.
2300 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2301 RunAllPendingInMessageLoop();
2302 EXPECT_TRUE(deleted
);
2305 // Tests that showing an interstitial as a result of a browser initiated
2306 // navigation while an interstitial is showing does not remove the pending
2307 // entry (see http://crbug.com/9791).
2308 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2309 const char kUrl
[] = "http://www.badguys.com/";
2310 const GURL
kGURL(kUrl
);
2312 // Start a navigation to a page
2313 contents()->GetController().LoadURL(
2314 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2316 // Simulate that navigation triggering an interstitial.
2317 TestInterstitialPage::InterstitialState state
=
2318 TestInterstitialPage::INVALID
;
2319 bool deleted
= false;
2320 TestInterstitialPage
* interstitial
=
2321 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2322 TestInterstitialPageStateGuard
state_guard(interstitial
);
2323 interstitial
->Show();
2324 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2325 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2327 // Initiate a new navigation from the browser that also triggers an
2329 contents()->GetController().LoadURL(
2330 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2331 TestInterstitialPage::InterstitialState state2
=
2332 TestInterstitialPage::INVALID
;
2333 bool deleted2
= false;
2334 TestInterstitialPage
* interstitial2
=
2335 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2336 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2337 interstitial2
->Show();
2338 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2339 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2341 // Make sure we still have an entry.
2342 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2344 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2346 // And that the first interstitial is gone, but not the second.
2347 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2348 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2349 RunAllPendingInMessageLoop();
2350 EXPECT_TRUE(deleted
);
2351 EXPECT_FALSE(deleted2
);
2354 // Tests that Javascript messages are not shown while an interstitial is
2356 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2357 const char kUrl
[] = "http://www.badguys.com/";
2358 const GURL
kGURL(kUrl
);
2360 // Start a navigation to a page
2361 contents()->GetController().LoadURL(
2362 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2363 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2364 main_test_rfh()->PrepareForCommit();
2365 // DidNavigate from the page
2366 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
2367 kGURL
, ui::PAGE_TRANSITION_TYPED
);
2369 // Simulate showing an interstitial while the page is showing.
2370 TestInterstitialPage::InterstitialState state
=
2371 TestInterstitialPage::INVALID
;
2372 bool deleted
= false;
2373 TestInterstitialPage
* interstitial
=
2374 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2375 TestInterstitialPageStateGuard
state_guard(interstitial
);
2376 interstitial
->Show();
2377 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2378 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2380 // While the interstitial is showing, let's simulate the hidden page
2381 // attempting to show a JS message.
2382 IPC::Message
* dummy_message
= new IPC::Message
;
2383 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2384 base::ASCIIToUTF16("This is an informative message"),
2385 base::ASCIIToUTF16("OK"),
2386 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2387 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2390 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2391 // interstitial it isn't copied over to the destination.
2392 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2393 // Navigate to a page.
2394 GURL
url1("http://www.google.com");
2395 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2396 EXPECT_EQ(1, controller().GetEntryCount());
2398 // Initiate a browser navigation that will trigger the interstitial
2399 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2400 ui::PAGE_TRANSITION_TYPED
, std::string());
2402 // Show an interstitial.
2403 TestInterstitialPage::InterstitialState state
=
2404 TestInterstitialPage::INVALID
;
2405 bool deleted
= false;
2406 GURL
url2("http://interstitial");
2407 TestInterstitialPage
* interstitial
=
2408 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2409 TestInterstitialPageStateGuard
state_guard(interstitial
);
2410 interstitial
->Show();
2411 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2412 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2413 EXPECT_TRUE(interstitial
->is_showing());
2414 EXPECT_EQ(2, controller().GetEntryCount());
2416 // Create another NavigationController.
2417 GURL
url3("http://foo2");
2418 scoped_ptr
<TestWebContents
> other_contents(
2419 static_cast<TestWebContents
*>(CreateTestWebContents()));
2420 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2421 other_contents
->NavigateAndCommit(url3
);
2422 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
2423 other_controller
.CopyStateFromAndPrune(&controller(), false);
2425 // The merged controller should only have two entries: url1 and url2.
2426 ASSERT_EQ(2, other_controller
.GetEntryCount());
2427 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2428 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2429 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2431 // And the merged controller shouldn't be showing an interstitial.
2432 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2435 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2436 // showing an interstitial.
2437 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2438 // Navigate to a page.
2439 GURL
url1("http://www.google.com");
2440 contents()->NavigateAndCommit(url1
);
2442 // Create another NavigationController.
2443 scoped_ptr
<TestWebContents
> other_contents(
2444 static_cast<TestWebContents
*>(CreateTestWebContents()));
2445 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2447 // Navigate it to url2.
2448 GURL
url2("http://foo2");
2449 other_contents
->NavigateAndCommit(url2
);
2451 // Show an interstitial.
2452 TestInterstitialPage::InterstitialState state
=
2453 TestInterstitialPage::INVALID
;
2454 bool deleted
= false;
2455 GURL
url3("http://interstitial");
2456 TestInterstitialPage
* interstitial
=
2457 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2459 TestInterstitialPageStateGuard
state_guard(interstitial
);
2460 interstitial
->Show();
2461 int interstitial_entry_id
=
2462 other_controller
.GetTransientEntry()->GetUniqueID();
2463 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url3
);
2464 EXPECT_TRUE(interstitial
->is_showing());
2465 EXPECT_EQ(2, other_controller
.GetEntryCount());
2467 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2468 // interstitial is showing in the target.
2469 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2472 // Regression test for http://crbug.com/168611 - the URLs passed by the
2473 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2474 TEST_F(WebContentsImplTest
, FilterURLs
) {
2475 TestWebContentsObserver
observer(contents());
2477 // A navigation to about:whatever should always look like a navigation to
2479 GURL
url_normalized(url::kAboutBlankURL
);
2480 GURL
url_from_ipc("about:whatever");
2482 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2483 // will use the given URL to create the NavigationEntry as well, and that
2484 // entry should contain the filtered URL.
2485 contents()->NavigateAndCommit(url_normalized
);
2487 // Check that an IPC with about:whatever is correctly normalized.
2488 contents()->TestDidFinishLoad(url_from_ipc
);
2490 EXPECT_EQ(url_normalized
, observer
.last_url());
2492 // Create and navigate another WebContents.
2493 scoped_ptr
<TestWebContents
> other_contents(
2494 static_cast<TestWebContents
*>(CreateTestWebContents()));
2495 TestWebContentsObserver
other_observer(other_contents
.get());
2496 other_contents
->NavigateAndCommit(url_normalized
);
2498 // Check that an IPC with about:whatever is correctly normalized.
2499 other_contents
->TestDidFailLoadWithError(
2500 url_from_ipc
, 1, base::string16(), false);
2501 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2504 // Test that if a pending contents is deleted before it is shown, we don't
2506 TEST_F(WebContentsImplTest
, PendingContents
) {
2507 scoped_ptr
<TestWebContents
> other_contents(
2508 static_cast<TestWebContents
*>(CreateTestWebContents()));
2509 contents()->AddPendingContents(other_contents
.get());
2510 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2511 other_contents
.reset();
2512 EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id
));
2515 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2516 const gfx::Size
original_preferred_size(1024, 768);
2517 contents()->UpdatePreferredSize(original_preferred_size
);
2519 // With no capturers, expect the preferred size to be the one propagated into
2520 // WebContentsImpl via the RenderViewHostDelegate interface.
2521 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2522 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2524 // Increment capturer count, but without specifying a capture size. Expect
2525 // a "not set" preferred size.
2526 contents()->IncrementCapturerCount(gfx::Size());
2527 EXPECT_EQ(1, contents()->GetCapturerCount());
2528 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2530 // Increment capturer count again, but with an overriding capture size.
2531 // Expect preferred size to now be overridden to the capture size.
2532 const gfx::Size
capture_size(1280, 720);
2533 contents()->IncrementCapturerCount(capture_size
);
2534 EXPECT_EQ(2, contents()->GetCapturerCount());
2535 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2537 // Increment capturer count a third time, but the expect that the preferred
2538 // size is still the first capture size.
2539 const gfx::Size
another_capture_size(720, 480);
2540 contents()->IncrementCapturerCount(another_capture_size
);
2541 EXPECT_EQ(3, contents()->GetCapturerCount());
2542 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2544 // Decrement capturer count twice, but expect the preferred size to still be
2546 contents()->DecrementCapturerCount();
2547 contents()->DecrementCapturerCount();
2548 EXPECT_EQ(1, contents()->GetCapturerCount());
2549 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2551 // Decrement capturer count, and since the count has dropped to zero, the
2552 // original preferred size should be restored.
2553 contents()->DecrementCapturerCount();
2554 EXPECT_EQ(0, contents()->GetCapturerCount());
2555 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2558 TEST_F(WebContentsImplTest
, CapturerPreventsHiding
) {
2559 const gfx::Size
original_preferred_size(1024, 768);
2560 contents()->UpdatePreferredSize(original_preferred_size
);
2562 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2563 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2565 // With no capturers, setting and un-setting occlusion should change the
2566 // view's occlusion state.
2567 EXPECT_FALSE(view
->is_showing());
2568 contents()->WasShown();
2569 EXPECT_TRUE(view
->is_showing());
2570 contents()->WasHidden();
2571 EXPECT_FALSE(view
->is_showing());
2572 contents()->WasShown();
2573 EXPECT_TRUE(view
->is_showing());
2575 // Add a capturer and try to hide the contents. The view will remain visible.
2576 contents()->IncrementCapturerCount(gfx::Size());
2577 contents()->WasHidden();
2578 EXPECT_TRUE(view
->is_showing());
2580 // Remove the capturer, and the WasHidden should take effect.
2581 contents()->DecrementCapturerCount();
2582 EXPECT_FALSE(view
->is_showing());
2585 TEST_F(WebContentsImplTest
, CapturerPreventsOcclusion
) {
2586 const gfx::Size
original_preferred_size(1024, 768);
2587 contents()->UpdatePreferredSize(original_preferred_size
);
2589 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2590 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2592 // With no capturers, setting and un-setting occlusion should change the
2593 // view's occlusion state.
2594 EXPECT_FALSE(view
->is_occluded());
2595 contents()->WasOccluded();
2596 EXPECT_TRUE(view
->is_occluded());
2597 contents()->WasUnOccluded();
2598 EXPECT_FALSE(view
->is_occluded());
2599 contents()->WasOccluded();
2600 EXPECT_TRUE(view
->is_occluded());
2602 // Add a capturer. This should cause the view to be un-occluded.
2603 contents()->IncrementCapturerCount(gfx::Size());
2604 EXPECT_FALSE(view
->is_occluded());
2606 // Try to occlude the view. This will fail to propagate because of the
2608 contents()->WasOccluded();
2609 EXPECT_FALSE(view
->is_occluded());
2611 // Remove the capturer and try again.
2612 contents()->DecrementCapturerCount();
2613 EXPECT_FALSE(view
->is_occluded());
2614 contents()->WasOccluded();
2615 EXPECT_TRUE(view
->is_occluded());
2618 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2620 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2621 // The WebContents starts with a valid creation time.
2622 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2624 // Reset the last active time to a known-bad value.
2625 contents()->last_active_time_
= base::TimeTicks();
2626 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2628 // Simulate activating the WebContents. The active time should update.
2629 contents()->WasShown();
2630 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2633 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2635 ContentsZoomChangedDelegate() :
2636 contents_zoom_changed_call_count_(0),
2637 last_zoom_in_(false) {
2640 int GetAndResetContentsZoomChangedCallCount() {
2641 int count
= contents_zoom_changed_call_count_
;
2642 contents_zoom_changed_call_count_
= 0;
2646 bool last_zoom_in() const {
2647 return last_zoom_in_
;
2650 // WebContentsDelegate:
2651 void ContentsZoomChange(bool zoom_in
) override
{
2652 contents_zoom_changed_call_count_
++;
2653 last_zoom_in_
= zoom_in
;
2657 int contents_zoom_changed_call_count_
;
2660 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2663 // Tests that some mouseehweel events get turned into browser zoom requests.
2664 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2665 using blink::WebInputEvent
;
2667 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2668 new ContentsZoomChangedDelegate());
2669 contents()->SetDelegate(delegate
.get());
2672 // Verify that normal mouse wheel events do nothing to change the zoom level.
2673 blink::WebMouseWheelEvent event
=
2674 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2675 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2676 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2678 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
|
2679 WebInputEvent::ControlKey
;
2680 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2681 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2682 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2684 // But whenever the ctrl modifier is applied with canScroll=false, they can
2685 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2687 modifiers
= WebInputEvent::ControlKey
;
2688 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2689 event
.canScroll
= false;
2690 bool handled
= contents()->HandleWheelEvent(event
);
2691 #if defined(OS_MACOSX)
2692 EXPECT_FALSE(handled
);
2693 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2695 EXPECT_TRUE(handled
);
2696 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2697 EXPECT_TRUE(delegate
->last_zoom_in());
2700 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2701 WebInputEvent::AltKey
;
2702 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2703 event
.canScroll
= false;
2704 handled
= contents()->HandleWheelEvent(event
);
2705 #if defined(OS_MACOSX)
2706 EXPECT_FALSE(handled
);
2707 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2709 EXPECT_TRUE(handled
);
2710 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2711 EXPECT_FALSE(delegate
->last_zoom_in());
2714 // Unless there is no vertical movement.
2715 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2716 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2717 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2719 // Events containing precise scrolling deltas also shouldn't result in the
2720 // zoom being adjusted, to avoid accidental adjustments caused by
2721 // two-finger-scrolling on a touchpad.
2722 modifiers
= WebInputEvent::ControlKey
;
2723 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2724 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2725 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2727 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2728 contents()->SetDelegate(nullptr);
2731 // Tests that GetRelatedActiveContentsCount is shared between related
2732 // SiteInstances and includes WebContents that have not navigated yet.
2733 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2734 scoped_refptr
<SiteInstance
> instance1(
2735 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2736 scoped_refptr
<SiteInstance
> instance2(
2737 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2739 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2740 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2742 scoped_ptr
<TestWebContents
> contents1(
2743 TestWebContents::Create(browser_context(), instance1
.get()));
2744 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2745 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2747 scoped_ptr
<TestWebContents
> contents2(
2748 TestWebContents::Create(browser_context(), instance1
.get()));
2749 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2750 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2753 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2754 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2757 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2758 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2761 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2762 // same-site and cross-site navigations.
2763 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2764 scoped_refptr
<SiteInstance
> instance(
2765 SiteInstance::Create(browser_context()));
2767 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2769 scoped_ptr
<TestWebContents
> contents(
2770 TestWebContents::Create(browser_context(), instance
.get()));
2771 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2773 // Navigate to a URL.
2774 contents
->GetController().LoadURL(GURL("http://a.com/1"),
2776 ui::PAGE_TRANSITION_TYPED
,
2778 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2779 contents
->CommitPendingNavigation();
2780 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2782 // Navigate to a URL in the same site.
2783 contents
->GetController().LoadURL(GURL("http://a.com/2"),
2785 ui::PAGE_TRANSITION_TYPED
,
2787 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2788 contents
->CommitPendingNavigation();
2789 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2791 // Navigate to a URL in a different site.
2792 const GURL kUrl
= GURL("http://b.com");
2793 contents
->GetController().LoadURL(kUrl
,
2795 ui::PAGE_TRANSITION_TYPED
,
2797 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2798 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2799 switches::kEnableBrowserSideNavigation
)) {
2800 contents
->GetMainFrame()->PrepareForCommit();
2802 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2803 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2804 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kUrl
);
2805 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2808 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2811 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2813 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2814 scoped_refptr
<SiteInstance
> instance(
2815 SiteInstance::Create(browser_context()));
2817 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2819 scoped_ptr
<TestWebContents
> contents(
2820 TestWebContents::Create(browser_context(), instance
.get()));
2821 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2823 // Navigate to a URL.
2824 contents
->NavigateAndCommit(GURL("http://a.com"));
2825 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2827 // Navigate to a URL which sort of looks like a chrome:// url.
2828 contents
->NavigateAndCommit(GURL("http://gpu"));
2829 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2831 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2832 const GURL kWebUIUrl
= GURL("chrome://gpu");
2833 contents
->GetController().LoadURL(kWebUIUrl
,
2835 ui::PAGE_TRANSITION_TYPED
,
2837 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2838 contents
->GetMainFrame()->PrepareForCommit();
2839 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2840 scoped_refptr
<SiteInstance
> instance_webui(
2841 contents
->GetPendingMainFrame()->GetSiteInstance());
2842 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2844 // At this point, contents still counts for the old BrowsingInstance.
2845 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2846 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2848 // Commit and contents counts for the new one.
2849 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kWebUIUrl
);
2850 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2851 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2854 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2855 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2858 class LoadingWebContentsObserver
: public WebContentsObserver
{
2860 explicit LoadingWebContentsObserver(WebContents
* contents
)
2861 : WebContentsObserver(contents
),
2862 is_loading_(false) {
2864 ~LoadingWebContentsObserver() override
{}
2866 void DidStartLoading() override
{ is_loading_
= true; }
2867 void DidStopLoading() override
{ is_loading_
= false; }
2869 bool is_loading() const { return is_loading_
; }
2874 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver
);
2877 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2878 // interleaving cross-process navigations in multiple subframes.
2879 // See https://crbug.com/448601 for details of the underlying issue. The
2880 // sequence of events that reproduce it are as follows:
2881 // * Navigate top-level frame with one subframe.
2882 // * Subframe navigates more than once before the top-level frame has had a
2883 // chance to complete the load.
2884 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2885 // to 0, while the loading_progresses_ map is not reset.
2886 TEST_F(WebContentsImplTest
, StartStopEventsBalance
) {
2887 // The bug manifests itself in regular mode as well, but browser-initiated
2888 // navigation of subframes is only possible in --site-per-process mode within
2890 IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
2891 const GURL
initial_url("about:blank");
2892 const GURL
main_url("http://www.chromium.org");
2893 const GURL
foo_url("http://foo.chromium.org");
2894 const GURL
bar_url("http://bar.chromium.org");
2895 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
2897 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
2898 LoadingWebContentsObserver
observer(contents());
2900 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
2901 // The frame should still be loading.
2902 controller().LoadURL(
2903 main_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2904 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2905 orig_rfh
->PrepareForCommit();
2906 orig_rfh
->OnMessageReceived(
2907 FrameHostMsg_DidStartLoading(orig_rfh
->GetRoutingID(), false));
2908 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, main_url
,
2909 ui::PAGE_TRANSITION_TYPED
);
2910 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2911 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
2912 EXPECT_TRUE(contents()->IsLoading());
2913 EXPECT_TRUE(observer
.is_loading());
2915 // Create a child frame to navigate multiple times.
2916 TestRenderFrameHost
* subframe
= orig_rfh
->AppendChild("subframe");
2918 // Navigate the child frame to about:blank, which will send both
2919 // DidStartLoading and DidStopLoading messages.
2921 subframe
->SendRendererInitiatedNavigationRequest(initial_url
, false);
2922 subframe
->OnMessageReceived(
2923 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2924 subframe
->SendNavigateWithTransition(1, 0, false, initial_url
,
2925 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2926 subframe
->OnMessageReceived(
2927 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2930 // Navigate the frame to another URL, which will send again
2931 // DidStartLoading and DidStopLoading messages.
2933 subframe
->SendRendererInitiatedNavigationRequest(foo_url
, false);
2934 subframe
->PrepareForCommit();
2935 subframe
->OnMessageReceived(
2936 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2937 subframe
->SendNavigateWithTransition(1, 0, false, foo_url
,
2938 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2939 subframe
->OnMessageReceived(
2940 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2943 // Since the main frame hasn't sent any DidStopLoading messages, it is
2944 // expected that the WebContents is still in loading state.
2945 EXPECT_TRUE(contents()->IsLoading());
2946 EXPECT_TRUE(observer
.is_loading());
2948 // Navigate the frame again, this time using LoadURLWithParams. This causes
2949 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2952 NavigationController::LoadURLParams
load_params(bar_url
);
2953 load_params
.referrer
=
2954 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
2955 load_params
.transition_type
= ui::PAGE_TRANSITION_GENERATED
;
2956 load_params
.extra_headers
= "content-type: text/plain";
2957 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
2958 load_params
.is_renderer_initiated
= false;
2959 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
2960 load_params
.frame_tree_node_id
=
2961 subframe
->frame_tree_node()->frame_tree_node_id();
2962 controller().LoadURLWithParams(load_params
);
2963 entry_id
= controller().GetPendingEntry()->GetUniqueID();
2965 subframe
->OnMessageReceived(
2966 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2968 // Commit the navigation in the child frame and send the DidStopLoading
2970 subframe
->PrepareForCommit();
2971 contents()->TestDidNavigate(subframe
, 3, entry_id
, true, bar_url
,
2972 ui::PAGE_TRANSITION_MANUAL_SUBFRAME
);
2973 subframe
->OnMessageReceived(
2974 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2977 // At this point the status should still be loading, since the main frame
2978 // hasn't sent the DidstopLoading message yet.
2979 EXPECT_TRUE(contents()->IsLoading());
2980 EXPECT_TRUE(observer
.is_loading());
2982 // Send the DidStopLoading for the main frame and ensure it isn't loading
2984 orig_rfh
->OnMessageReceived(
2985 FrameHostMsg_DidStopLoading(orig_rfh
->GetRoutingID()));
2986 EXPECT_FALSE(contents()->IsLoading());
2987 EXPECT_FALSE(observer
.is_loading());
2990 // Ensure that WebContentsImpl does not stop loading too early when there still
2991 // is a pending renderer. This can happen if a same-process non user-initiated
2992 // navigation completes while there is an ongoing cross-process navigation.
2993 // TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
2994 // DidStopLoading are properly called.
2995 TEST_F(WebContentsImplTest
, NoEarlyStop
) {
2996 const GURL
kUrl1("http://www.chromium.org");
2997 const GURL
kUrl2("http://www.google.com");
2998 const GURL
kUrl3("http://www.wikipedia.org");
3000 contents()->NavigateAndCommit(kUrl1
);
3002 TestRenderFrameHost
* current_rfh
= contents()->GetMainFrame();
3004 // Start a browser-initiated cross-process navigation to |kUrl2|. There should
3005 // be a pending RenderFrameHost and the WebContents should be loading.
3006 controller().LoadURL(
3007 kUrl2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
3008 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
3009 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
3010 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
3011 ASSERT_TRUE(pending_rfh
);
3012 EXPECT_TRUE(contents()->IsLoading());
3014 // The current RenderFrameHost starts a non user-initiated render-initiated
3015 // navigation and sends a DidStartLoading IPC. The WebContents should still be
3017 current_rfh
->OnMessageReceived(
3018 FrameHostMsg_DidStartLoading(current_rfh
->GetRoutingID(), false));
3019 EXPECT_TRUE(contents()->IsLoading());
3021 // Simulate the pending RenderFrameHost DidStartLoading. There should still be
3022 // a pending RenderFrameHost and the WebContents should still be loading.
3023 pending_rfh
->PrepareForCommit();
3024 pending_rfh
->OnMessageReceived(
3025 FrameHostMsg_DidStartLoading(pending_rfh
->GetRoutingID(), false));
3026 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3027 EXPECT_TRUE(contents()->IsLoading());
3029 // Simulate the commit and DidStopLoading from the renderer-initiated
3030 // navigation in the current RenderFrameHost. There should still be a pending
3031 // RenderFrameHost and the WebContents should still be loading.
3032 current_rfh
->SendNavigateWithModificationCallback(
3033 1, 0, true, kUrl3
, base::Bind(SetAsNonUserGesture
));
3034 current_rfh
->OnMessageReceived(
3035 FrameHostMsg_DidStopLoading(current_rfh
->GetRoutingID()));
3036 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3037 EXPECT_TRUE(contents()->IsLoading());
3038 // It should commit.
3039 ASSERT_EQ(2, controller().GetEntryCount());
3040 EXPECT_EQ(kUrl3
, controller().GetLastCommittedEntry()->GetURL());
3042 // Commit the navigation. The formerly pending RenderFrameHost should now be
3043 // the current RenderFrameHost and the WebContents should still be loading.
3044 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, kUrl2
,
3045 ui::PAGE_TRANSITION_TYPED
);
3046 EXPECT_FALSE(contents()->GetPendingMainFrame());
3047 TestRenderFrameHost
* new_current_rfh
= contents()->GetMainFrame();
3048 EXPECT_EQ(new_current_rfh
, pending_rfh
);
3049 EXPECT_TRUE(contents()->IsLoading());
3050 EXPECT_EQ(3, controller().GetEntryCount());
3052 // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
3053 // should now have stopped loading.
3054 new_current_rfh
->OnMessageReceived(
3055 FrameHostMsg_DidStopLoading(new_current_rfh
->GetRoutingID()));
3056 EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh
);
3057 EXPECT_FALSE(contents()->IsLoading());
3060 TEST_F(WebContentsImplTest
, MediaPowerSaveBlocking
) {
3061 // PlayerIDs are actually pointers cast to int64, so verify that both negative
3062 // and positive player ids don't blow up.
3063 const int kPlayerAudioVideoId
= 15;
3064 const int kPlayerAudioOnlyId
= -15;
3065 const int kPlayerVideoOnlyId
= 30;
3066 const int kPlayerRemoteId
= -30;
3068 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3069 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3071 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3072 AudioStateProvider
* audio_state
= contents()->audio_state_provider();
3074 // Ensure RenderFrame is initialized before simulating events coming from it.
3075 main_test_rfh()->InitializeRenderFrameIfNeeded();
3077 // The audio power save blocker should not be based on having a media player
3078 // when audio stream monitoring is available.
3079 if (audio_state
->IsAudioStateAvailable()) {
3080 // Send a fake audio stream monitor notification. The audio power save
3081 // blocker should be created.
3082 audio_state
->set_was_recently_audible_for_testing(true);
3083 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3084 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
3086 // Send another fake notification, this time when WasRecentlyAudible() will
3087 // be false. The power save blocker should be released.
3088 audio_state
->set_was_recently_audible_for_testing(false);
3089 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3090 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3093 // Start a player with both audio and video. A video power save blocker
3094 // should be created. If audio stream monitoring is available, an audio power
3095 // save blocker should be created too.
3096 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3097 0, kPlayerAudioVideoId
, true, true, false));
3098 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3099 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3100 !audio_state
->IsAudioStateAvailable());
3102 // Upon hiding the video power save blocker should be released.
3103 contents()->WasHidden();
3104 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3106 // Start another player that only has video. There should be no change in
3107 // the power save blockers. The notification should take into account the
3108 // visibility state of the WebContents.
3109 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3110 0, kPlayerVideoOnlyId
, true, false, false));
3111 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3112 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3113 !audio_state
->IsAudioStateAvailable());
3115 // Showing the WebContents should result in the creation of the blocker.
3116 contents()->WasShown();
3117 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3119 // Start another player that only has audio. There should be no change in
3120 // the power save blockers.
3121 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3122 0, kPlayerAudioOnlyId
, false, true, false));
3123 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3124 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3125 !audio_state
->IsAudioStateAvailable());
3127 // Start a remote player. There should be no change in the power save
3129 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3130 0, kPlayerRemoteId
, true, true, true));
3131 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3132 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3133 !audio_state
->IsAudioStateAvailable());
3135 // Destroy the original audio video player. Both power save blockers should
3137 rfh
->OnMessageReceived(
3138 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId
));
3139 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3140 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3141 !audio_state
->IsAudioStateAvailable());
3143 // Destroy the audio only player. The video power save blocker should remain.
3144 rfh
->OnMessageReceived(
3145 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId
));
3146 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3147 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3149 // Destroy the video only player. No power save blockers should remain.
3150 rfh
->OnMessageReceived(
3151 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId
));
3152 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3153 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3155 // Destroy the remote player. No power save blockers should remain.
3156 rfh
->OnMessageReceived(
3157 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId
));
3158 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3159 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3161 // Start a player with both audio and video. A video power save blocker
3162 // should be created. If audio stream monitoring is available, an audio power
3163 // save blocker should be created too.
3164 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3165 0, kPlayerAudioVideoId
, true, true, false));
3166 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3167 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3168 !audio_state
->IsAudioStateAvailable());
3170 // Crash the renderer.
3171 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
3173 // Verify that all the power save blockers have been released.
3174 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3175 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3178 TEST_F(WebContentsImplTest
, ThemeColorChangeDependingOnFirstVisiblePaint
) {
3179 TestWebContentsObserver
observer(contents());
3180 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3182 SkColor transparent
= SK_ColorTRANSPARENT
;
3184 EXPECT_EQ(transparent
, contents()->GetThemeColor());
3185 EXPECT_EQ(transparent
, observer
.last_theme_color());
3187 // Theme color changes should not propagate past the WebContentsImpl before
3188 // the first visually non-empty paint has occurred.
3189 RenderViewHostTester::TestOnMessageReceived(
3191 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorRED
));
3193 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3194 EXPECT_EQ(transparent
, observer
.last_theme_color());
3196 // Simulate that the first visually non-empty paint has occurred. This will
3197 // propagate the current theme color to the delegates.
3198 RenderViewHostTester::TestOnMessageReceived(
3200 FrameHostMsg_DidFirstVisuallyNonEmptyPaint(rfh
->GetRoutingID()));
3202 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3203 EXPECT_EQ(SK_ColorRED
, observer
.last_theme_color());
3205 // Additional changes made by the web contents should propagate as well.
3206 RenderViewHostTester::TestOnMessageReceived(
3208 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorGREEN
));
3210 EXPECT_EQ(SK_ColorGREEN
, contents()->GetThemeColor());
3211 EXPECT_EQ(SK_ColorGREEN
, observer
.last_theme_color());
3214 // Test that if a renderer reports that it has loaded a resource from
3215 // memory cache with bad security info (i.e. can't be deserialized), the
3216 // renderer gets killed.
3217 TEST_F(WebContentsImplTest
, LoadResourceFromMemoryCacheWithBadSecurityInfo
) {
3218 MockRenderProcessHost
* rph
= contents()->GetMainFrame()->GetProcess();
3219 EXPECT_EQ(0, rph
->bad_msg_count());
3221 contents()->OnDidLoadResourceFromMemoryCache(
3222 GURL("http://example.test"), "not valid security info", "GET",
3223 "mime type", RESOURCE_TYPE_MAIN_FRAME
);
3224 EXPECT_EQ(1, rph
->bad_msg_count());
3227 } // namespace content