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/site_isolation_policy.h"
21 #include "content/common/view_messages.h"
22 #include "content/public/browser/global_request_id.h"
23 #include "content/public/browser/interstitial_page_delegate.h"
24 #include "content/public/browser/navigation_details.h"
25 #include "content/public/browser/notification_details.h"
26 #include "content/public/browser/notification_source.h"
27 #include "content/public/browser/render_widget_host_view.h"
28 #include "content/public/browser/web_contents_delegate.h"
29 #include "content/public/browser/web_contents_observer.h"
30 #include "content/public/browser/web_ui_controller.h"
31 #include "content/public/common/bindings_policy.h"
32 #include "content/public/common/content_constants.h"
33 #include "content/public/common/content_switches.h"
34 #include "content/public/common/url_constants.h"
35 #include "content/public/common/url_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 (!SiteIsolationPolicy::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 (SiteIsolationPolicy::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
);
1475 orig_rfh
->SimulateNavigationStop();
1477 // Confirm fullscreen has exited.
1478 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1479 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1480 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1483 contents()->SetDelegate(nullptr);
1486 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1487 FakeValidationMessageDelegate fake_delegate
;
1488 contents()->SetDelegate(&fake_delegate
);
1489 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1491 // Initialize the RenderFrame and then simulate crashing the renderer
1493 contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
1494 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1496 // Confirm HideValidationMessage was called.
1497 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1499 contents()->SetDelegate(nullptr);
1502 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1504 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1505 FakeFullscreenDelegate fake_delegate
;
1506 contents()->SetDelegate(&fake_delegate
);
1508 // Navigate to a site.
1509 const GURL
url("http://www.google.com");
1510 controller().LoadURL(
1511 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1512 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1513 main_test_rfh()->PrepareForCommit();
1514 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
1515 url
, ui::PAGE_TRANSITION_TYPED
);
1517 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1518 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1519 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1520 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1521 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1522 contents()->GetMainFrame()->GetRoutingID(), true));
1523 EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
1524 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1525 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1527 // Crash the renderer.
1528 main_test_rfh()->GetProcess()->SimulateCrash();
1530 // Confirm fullscreen has exited.
1531 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1532 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1533 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1535 contents()->SetDelegate(nullptr);
1538 ////////////////////////////////////////////////////////////////////////////////
1539 // Interstitial Tests
1540 ////////////////////////////////////////////////////////////////////////////////
1542 // Test navigating to a page (with the navigation initiated from the browser,
1543 // as when a URL is typed in the location bar) that shows an interstitial and
1544 // creates a new navigation entry, then hiding it without proceeding.
1545 TEST_F(WebContentsImplTest
,
1546 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1547 // Navigate to a page.
1548 GURL
url1("http://www.google.com");
1549 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1550 EXPECT_EQ(1, controller().GetEntryCount());
1552 // Initiate a browser navigation that will trigger the interstitial.
1553 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1554 ui::PAGE_TRANSITION_TYPED
, std::string());
1555 NavigationEntry
* entry
= controller().GetPendingEntry();
1557 // Show an interstitial.
1558 TestInterstitialPage::InterstitialState state
=
1559 TestInterstitialPage::INVALID
;
1560 bool deleted
= false;
1561 GURL
url2("http://interstitial");
1562 TestInterstitialPage
* interstitial
=
1563 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1564 TestInterstitialPageStateGuard
state_guard(interstitial
);
1565 interstitial
->Show();
1566 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1567 // The interstitial should not show until its navigation has committed.
1568 EXPECT_FALSE(interstitial
->is_showing());
1569 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1570 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1571 // Let's commit the interstitial navigation.
1572 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1573 EXPECT_TRUE(interstitial
->is_showing());
1574 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1575 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1576 entry
= controller().GetVisibleEntry();
1577 ASSERT_NE(nullptr, entry
);
1578 EXPECT_TRUE(entry
->GetURL() == url2
);
1580 // Now don't proceed.
1581 interstitial
->DontProceed();
1582 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1583 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1584 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1585 entry
= controller().GetVisibleEntry();
1586 ASSERT_NE(nullptr, entry
);
1587 EXPECT_TRUE(entry
->GetURL() == url1
);
1588 EXPECT_EQ(1, controller().GetEntryCount());
1590 RunAllPendingInMessageLoop();
1591 EXPECT_TRUE(deleted
);
1594 // Test navigating to a page (with the navigation initiated from the renderer,
1595 // as when clicking on a link in the page) that shows an interstitial and
1596 // creates a new navigation entry, then hiding it without proceeding.
1597 TEST_F(WebContentsImplTest
,
1598 ShowInterstitialFromRendererWithNewNavigationDontProceed
) {
1599 // Navigate to a page.
1600 GURL
url1("http://www.google.com");
1601 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1602 EXPECT_EQ(1, controller().GetEntryCount());
1604 // Show an interstitial (no pending entry, the interstitial would have been
1605 // triggered by clicking on a link).
1606 TestInterstitialPage::InterstitialState state
=
1607 TestInterstitialPage::INVALID
;
1608 bool deleted
= false;
1609 GURL
url2("http://interstitial");
1610 TestInterstitialPage
* interstitial
=
1611 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1612 TestInterstitialPageStateGuard
state_guard(interstitial
);
1613 interstitial
->Show();
1614 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1615 // The interstitial should not show until its navigation has committed.
1616 EXPECT_FALSE(interstitial
->is_showing());
1617 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1618 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1619 // Let's commit the interstitial navigation.
1620 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1621 EXPECT_TRUE(interstitial
->is_showing());
1622 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1623 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1624 NavigationEntry
* entry
= controller().GetVisibleEntry();
1625 ASSERT_NE(nullptr, entry
);
1626 EXPECT_TRUE(entry
->GetURL() == url2
);
1628 // Now don't proceed.
1629 interstitial
->DontProceed();
1630 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1631 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1632 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1633 entry
= controller().GetVisibleEntry();
1634 ASSERT_NE(nullptr, entry
);
1635 EXPECT_TRUE(entry
->GetURL() == url1
);
1636 EXPECT_EQ(1, controller().GetEntryCount());
1638 RunAllPendingInMessageLoop();
1639 EXPECT_TRUE(deleted
);
1642 // Test navigating to a page that shows an interstitial without creating a new
1643 // navigation entry (this happens when the interstitial is triggered by a
1644 // sub-resource in the page), then hiding it without proceeding.
1645 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1646 // Navigate to a page.
1647 GURL
url1("http://www.google.com");
1648 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1649 EXPECT_EQ(1, controller().GetEntryCount());
1651 // Show an interstitial.
1652 TestInterstitialPage::InterstitialState state
=
1653 TestInterstitialPage::INVALID
;
1654 bool deleted
= false;
1655 GURL
url2("http://interstitial");
1656 TestInterstitialPage
* interstitial
=
1657 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1658 TestInterstitialPageStateGuard
state_guard(interstitial
);
1659 interstitial
->Show();
1660 // The interstitial should not show until its navigation has committed.
1661 EXPECT_FALSE(interstitial
->is_showing());
1662 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1663 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1664 // Let's commit the interstitial navigation.
1665 interstitial
->TestDidNavigate(1, 0, true, url2
);
1666 EXPECT_TRUE(interstitial
->is_showing());
1667 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1668 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1669 NavigationEntry
* entry
= controller().GetVisibleEntry();
1670 ASSERT_NE(nullptr, entry
);
1671 // The URL specified to the interstitial should have been ignored.
1672 EXPECT_TRUE(entry
->GetURL() == url1
);
1674 // Now don't proceed.
1675 interstitial
->DontProceed();
1676 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1677 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1678 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1679 entry
= controller().GetVisibleEntry();
1680 ASSERT_NE(nullptr, entry
);
1681 EXPECT_TRUE(entry
->GetURL() == url1
);
1682 EXPECT_EQ(1, controller().GetEntryCount());
1684 RunAllPendingInMessageLoop();
1685 EXPECT_TRUE(deleted
);
1688 // Test navigating to a page (with the navigation initiated from the browser,
1689 // as when a URL is typed in the location bar) that shows an interstitial and
1690 // creates a new navigation entry, then proceeding.
1691 TEST_F(WebContentsImplTest
,
1692 ShowInterstitialFromBrowserNewNavigationProceed
) {
1693 // Navigate to a page.
1694 GURL
url1("http://www.google.com");
1695 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1696 EXPECT_EQ(1, controller().GetEntryCount());
1698 // Initiate a browser navigation that will trigger the interstitial
1699 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1700 ui::PAGE_TRANSITION_TYPED
, std::string());
1702 // Show an interstitial.
1703 TestInterstitialPage::InterstitialState state
=
1704 TestInterstitialPage::INVALID
;
1705 bool deleted
= false;
1706 GURL
url2("http://interstitial");
1707 TestInterstitialPage
* interstitial
=
1708 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1709 TestInterstitialPageStateGuard
state_guard(interstitial
);
1710 interstitial
->Show();
1711 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1712 // The interstitial should not show until its navigation has committed.
1713 EXPECT_FALSE(interstitial
->is_showing());
1714 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1715 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1716 // Let's commit the interstitial navigation.
1717 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1718 EXPECT_TRUE(interstitial
->is_showing());
1719 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1720 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1721 NavigationEntry
* entry
= controller().GetVisibleEntry();
1722 ASSERT_NE(nullptr, entry
);
1723 EXPECT_TRUE(entry
->GetURL() == url2
);
1726 interstitial
->Proceed();
1727 // The interstitial should show until the new navigation commits.
1728 RunAllPendingInMessageLoop();
1729 ASSERT_FALSE(deleted
);
1730 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1731 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1732 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1734 // Simulate the navigation to the page, that's when the interstitial gets
1736 GURL
url3("http://www.thepage.com");
1737 contents()->GetMainFrame()->PrepareForCommit();
1738 contents()->GetMainFrame()->SendNavigate(2, 0, true, url3
);
1740 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1741 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1742 entry
= controller().GetVisibleEntry();
1743 ASSERT_NE(nullptr, entry
);
1744 EXPECT_TRUE(entry
->GetURL() == url3
);
1746 EXPECT_EQ(2, controller().GetEntryCount());
1748 RunAllPendingInMessageLoop();
1749 EXPECT_TRUE(deleted
);
1752 // Test navigating to a page (with the navigation initiated from the renderer,
1753 // as when clicking on a link in the page) that shows an interstitial and
1754 // creates a new navigation entry, then proceeding.
1755 TEST_F(WebContentsImplTest
,
1756 ShowInterstitialFromRendererNewNavigationProceed
) {
1757 // Navigate to a page.
1758 GURL
url1("http://www.google.com");
1759 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1760 EXPECT_EQ(1, controller().GetEntryCount());
1762 // Show an interstitial.
1763 TestInterstitialPage::InterstitialState state
=
1764 TestInterstitialPage::INVALID
;
1765 bool deleted
= false;
1766 GURL
url2("http://interstitial");
1767 TestInterstitialPage
* interstitial
=
1768 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1769 TestInterstitialPageStateGuard
state_guard(interstitial
);
1770 interstitial
->Show();
1771 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1772 // The interstitial should not show until its navigation has committed.
1773 EXPECT_FALSE(interstitial
->is_showing());
1774 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1775 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1776 // Let's commit the interstitial navigation.
1777 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1778 EXPECT_TRUE(interstitial
->is_showing());
1779 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1780 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1781 NavigationEntry
* entry
= controller().GetVisibleEntry();
1782 ASSERT_NE(nullptr, entry
);
1783 EXPECT_TRUE(entry
->GetURL() == url2
);
1786 interstitial
->Proceed();
1787 // The interstitial should show until the new navigation commits.
1788 RunAllPendingInMessageLoop();
1789 ASSERT_FALSE(deleted
);
1790 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1791 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1792 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1794 // Simulate the navigation to the page, that's when the interstitial gets
1796 GURL
url3("http://www.thepage.com");
1797 main_test_rfh()->NavigateAndCommitRendererInitiated(2, true, url3
);
1799 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1800 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1801 entry
= controller().GetVisibleEntry();
1802 ASSERT_NE(nullptr, entry
);
1803 EXPECT_TRUE(entry
->GetURL() == url3
);
1805 EXPECT_EQ(2, controller().GetEntryCount());
1807 RunAllPendingInMessageLoop();
1808 EXPECT_TRUE(deleted
);
1811 // Test navigating to a page that shows an interstitial without creating a new
1812 // navigation entry (this happens when the interstitial is triggered by a
1813 // sub-resource in the page), then proceeding.
1814 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1815 // Navigate to a page so we have a navigation entry in the controller.
1816 GURL
url1("http://www.google.com");
1817 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1818 EXPECT_EQ(1, controller().GetEntryCount());
1820 // Show an interstitial.
1821 TestInterstitialPage::InterstitialState state
=
1822 TestInterstitialPage::INVALID
;
1823 bool deleted
= false;
1824 GURL
url2("http://interstitial");
1825 TestInterstitialPage
* interstitial
=
1826 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1827 TestInterstitialPageStateGuard
state_guard(interstitial
);
1828 interstitial
->Show();
1829 // The interstitial should not show until its navigation has committed.
1830 EXPECT_FALSE(interstitial
->is_showing());
1831 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1832 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1833 // Let's commit the interstitial navigation.
1834 interstitial
->TestDidNavigate(1, 0, true, url2
);
1835 EXPECT_TRUE(interstitial
->is_showing());
1836 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1837 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1838 NavigationEntry
* entry
= controller().GetVisibleEntry();
1839 ASSERT_NE(nullptr, entry
);
1840 // The URL specified to the interstitial should have been ignored.
1841 EXPECT_TRUE(entry
->GetURL() == url1
);
1844 interstitial
->Proceed();
1845 // Since this is not a new navigation, the previous page is dismissed right
1846 // away and shows the original page.
1847 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1848 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1849 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1850 entry
= controller().GetVisibleEntry();
1851 ASSERT_NE(nullptr, entry
);
1852 EXPECT_TRUE(entry
->GetURL() == url1
);
1854 EXPECT_EQ(1, controller().GetEntryCount());
1856 RunAllPendingInMessageLoop();
1857 EXPECT_TRUE(deleted
);
1860 // Test navigating to a page that shows an interstitial, then navigating away.
1861 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1862 // Show interstitial.
1863 TestInterstitialPage::InterstitialState state
=
1864 TestInterstitialPage::INVALID
;
1865 bool deleted
= false;
1866 GURL
url("http://interstitial");
1867 TestInterstitialPage
* interstitial
=
1868 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1869 TestInterstitialPageStateGuard
state_guard(interstitial
);
1870 interstitial
->Show();
1871 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1872 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
1874 // While interstitial showing, navigate to a new URL.
1875 const GURL
url2("http://www.yahoo.com");
1876 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2
);
1878 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1880 RunAllPendingInMessageLoop();
1881 EXPECT_TRUE(deleted
);
1884 // Test navigating to a page that shows an interstitial, then going back.
1885 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1886 // Navigate to a page so we have a navigation entry in the controller.
1887 GURL
url1("http://www.google.com");
1888 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1889 EXPECT_EQ(1, controller().GetEntryCount());
1891 // Show interstitial.
1892 TestInterstitialPage::InterstitialState state
=
1893 TestInterstitialPage::INVALID
;
1894 bool deleted
= false;
1895 GURL
interstitial_url("http://interstitial");
1896 TestInterstitialPage
* interstitial
=
1897 new TestInterstitialPage(contents(), true, interstitial_url
,
1899 TestInterstitialPageStateGuard
state_guard(interstitial
);
1900 interstitial
->Show();
1901 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1902 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1904 EXPECT_EQ(2, controller().GetEntryCount());
1906 // While the interstitial is showing, go back. This will dismiss the
1907 // interstitial and not initiate a navigation, but just show the existing
1909 controller().GoBack();
1911 // Make sure we are back to the original page and that the interstitial is
1913 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1914 NavigationEntry
* entry
= controller().GetVisibleEntry();
1916 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1917 EXPECT_EQ(1, controller().GetEntryCount());
1919 RunAllPendingInMessageLoop();
1920 EXPECT_TRUE(deleted
);
1923 // Test navigating to a page that shows an interstitial, has a renderer crash,
1924 // and then goes back.
1925 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1926 // Navigate to a page so we have a navigation entry in the controller.
1927 GURL
url1("http://www.google.com");
1928 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1929 EXPECT_EQ(1, controller().GetEntryCount());
1930 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1932 // Show interstitial.
1933 TestInterstitialPage::InterstitialState state
=
1934 TestInterstitialPage::INVALID
;
1935 bool deleted
= false;
1936 GURL
interstitial_url("http://interstitial");
1937 TestInterstitialPage
* interstitial
=
1938 new TestInterstitialPage(contents(), true, interstitial_url
,
1940 TestInterstitialPageStateGuard
state_guard(interstitial
);
1941 interstitial
->Show();
1942 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1943 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1946 // Crash the renderer
1947 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1949 // While the interstitial is showing, go back. This will dismiss the
1950 // interstitial and not initiate a navigation, but just show the existing
1952 controller().GoBack();
1954 // Make sure we are back to the original page and that the interstitial is
1956 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1957 entry
= controller().GetVisibleEntry();
1959 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1961 RunAllPendingInMessageLoop();
1962 EXPECT_TRUE(deleted
);
1965 // Test navigating to a page that shows an interstitial, has the renderer crash,
1966 // and then navigates to the interstitial.
1967 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1968 // Navigate to a page so we have a navigation entry in the controller.
1969 GURL
url1("http://www.google.com");
1970 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1971 EXPECT_EQ(1, controller().GetEntryCount());
1973 // Show interstitial.
1974 TestInterstitialPage::InterstitialState state
=
1975 TestInterstitialPage::INVALID
;
1976 bool deleted
= false;
1977 GURL
interstitial_url("http://interstitial");
1978 TestInterstitialPage
* interstitial
=
1979 new TestInterstitialPage(contents(), true, interstitial_url
,
1981 TestInterstitialPageStateGuard
state_guard(interstitial
);
1982 interstitial
->Show();
1983 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1985 // Crash the renderer
1986 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1988 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1992 // Test navigating to a page that shows an interstitial, then close the
1994 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1995 // Show interstitial.
1996 TestInterstitialPage::InterstitialState state
=
1997 TestInterstitialPage::INVALID
;
1998 bool deleted
= false;
1999 GURL
url("http://interstitial");
2000 TestInterstitialPage
* interstitial
=
2001 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2002 TestInterstitialPageStateGuard
state_guard(interstitial
);
2003 interstitial
->Show();
2004 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2005 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2007 // Now close the contents.
2009 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2011 RunAllPendingInMessageLoop();
2012 EXPECT_TRUE(deleted
);
2015 // Test navigating to a page that shows an interstitial, then close the
2017 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
2018 // Show interstitial.
2019 TestInterstitialPage::InterstitialState state
=
2020 TestInterstitialPage::INVALID
;
2021 bool deleted
= false;
2022 GURL
url("http://interstitial");
2023 TestInterstitialPage
* interstitial
=
2024 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2025 TestInterstitialPageStateGuard
state_guard(interstitial
);
2026 interstitial
->Show();
2027 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2028 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2029 TestRenderFrameHost
* rfh
=
2030 static_cast<TestRenderFrameHost
*>(interstitial
->GetMainFrame());
2032 // Now close the contents.
2034 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2036 // Before the interstitial has a chance to process its shutdown task,
2037 // simulate quitting the browser. This goes through all processes and
2038 // tells them to destruct.
2039 rfh
->GetProcess()->SimulateCrash();
2041 RunAllPendingInMessageLoop();
2042 EXPECT_TRUE(deleted
);
2045 // Test that after Proceed is called and an interstitial is still shown, no more
2046 // commands get executed.
2047 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
2048 // Navigate to a page so we have a navigation entry in the controller.
2049 GURL
url1("http://www.google.com");
2050 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2051 EXPECT_EQ(1, controller().GetEntryCount());
2053 // Show an interstitial.
2054 TestInterstitialPage::InterstitialState state
=
2055 TestInterstitialPage::INVALID
;
2056 bool deleted
= false;
2057 GURL
url2("http://interstitial");
2058 TestInterstitialPage
* interstitial
=
2059 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2060 TestInterstitialPageStateGuard
state_guard(interstitial
);
2061 interstitial
->Show();
2062 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2063 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2066 EXPECT_EQ(0, interstitial
->command_received_count());
2067 interstitial
->TestDomOperationResponse("toto");
2068 EXPECT_EQ(1, interstitial
->command_received_count());
2071 interstitial
->Proceed();
2072 RunAllPendingInMessageLoop();
2073 ASSERT_FALSE(deleted
);
2075 // While the navigation to the new page is pending, send other commands, they
2076 // should be ignored.
2077 interstitial
->TestDomOperationResponse("hello");
2078 interstitial
->TestDomOperationResponse("hi");
2079 EXPECT_EQ(1, interstitial
->command_received_count());
2082 // Test showing an interstitial while another interstitial is already showing.
2083 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
2084 // Navigate to a page so we have a navigation entry in the controller.
2085 GURL
start_url("http://www.google.com");
2086 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2087 EXPECT_EQ(1, controller().GetEntryCount());
2089 // Show an interstitial.
2090 TestInterstitialPage::InterstitialState state1
=
2091 TestInterstitialPage::INVALID
;
2092 bool deleted1
= false;
2093 GURL
url1("http://interstitial1");
2094 TestInterstitialPage
* interstitial1
=
2095 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2096 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2097 interstitial1
->Show();
2098 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2099 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2101 // Now show another interstitial.
2102 TestInterstitialPage::InterstitialState state2
=
2103 TestInterstitialPage::INVALID
;
2104 bool deleted2
= false;
2105 GURL
url2("http://interstitial2");
2106 TestInterstitialPage
* interstitial2
=
2107 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2108 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2109 interstitial2
->Show();
2110 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2111 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2113 // Showing interstitial2 should have caused interstitial1 to go away.
2114 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2115 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2117 RunAllPendingInMessageLoop();
2118 EXPECT_TRUE(deleted1
);
2119 ASSERT_FALSE(deleted2
);
2121 // Let's make sure interstitial2 is working as intended.
2122 interstitial2
->Proceed();
2123 GURL
landing_url("http://www.thepage.com");
2124 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2126 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2127 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2128 NavigationEntry
* entry
= controller().GetVisibleEntry();
2129 ASSERT_NE(nullptr, entry
);
2130 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2131 EXPECT_EQ(2, controller().GetEntryCount());
2132 RunAllPendingInMessageLoop();
2133 EXPECT_TRUE(deleted2
);
2136 // Test showing an interstitial, proceeding and then navigating to another
2138 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2139 // Navigate to a page so we have a navigation entry in the controller.
2140 GURL
start_url("http://www.google.com");
2141 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2142 EXPECT_EQ(1, controller().GetEntryCount());
2144 // Show an interstitial.
2145 TestInterstitialPage::InterstitialState state1
=
2146 TestInterstitialPage::INVALID
;
2147 bool deleted1
= false;
2148 GURL
url1("http://interstitial1");
2149 TestInterstitialPage
* interstitial1
=
2150 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2151 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2152 interstitial1
->Show();
2153 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2154 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2156 // Take action. The interstitial won't be hidden until the navigation is
2158 interstitial1
->Proceed();
2159 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2161 // Now show another interstitial (simulating the navigation causing another
2163 TestInterstitialPage::InterstitialState state2
=
2164 TestInterstitialPage::INVALID
;
2165 bool deleted2
= false;
2166 GURL
url2("http://interstitial2");
2167 TestInterstitialPage
* interstitial2
=
2168 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2169 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2170 interstitial2
->Show();
2171 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2172 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2174 // Showing interstitial2 should have caused interstitial1 to go away.
2175 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2176 RunAllPendingInMessageLoop();
2177 EXPECT_TRUE(deleted1
);
2178 ASSERT_FALSE(deleted2
);
2180 // Let's make sure interstitial2 is working as intended.
2181 interstitial2
->Proceed();
2182 GURL
landing_url("http://www.thepage.com");
2183 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2185 RunAllPendingInMessageLoop();
2186 EXPECT_TRUE(deleted2
);
2187 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2188 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2189 NavigationEntry
* entry
= controller().GetVisibleEntry();
2190 ASSERT_NE(nullptr, entry
);
2191 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2192 EXPECT_EQ(2, controller().GetEntryCount());
2195 // Test that navigating away from an interstitial while it's loading cause it
2197 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2198 // Show an interstitial.
2199 TestInterstitialPage::InterstitialState state
=
2200 TestInterstitialPage::INVALID
;
2201 bool deleted
= false;
2202 GURL
interstitial_url("http://interstitial");
2203 TestInterstitialPage
* interstitial
=
2204 new TestInterstitialPage(contents(), true, interstitial_url
,
2206 TestInterstitialPageStateGuard
state_guard(interstitial
);
2207 interstitial
->Show();
2208 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2210 // Let's simulate a navigation initiated from the browser before the
2211 // interstitial finishes loading.
2212 const GURL
url("http://www.google.com");
2213 controller().LoadURL(
2214 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2215 EXPECT_FALSE(interstitial
->is_showing());
2216 RunAllPendingInMessageLoop();
2217 ASSERT_FALSE(deleted
);
2219 // Now let's make the interstitial navigation commit.
2220 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true,
2223 // After it loaded the interstitial should be gone.
2224 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2226 RunAllPendingInMessageLoop();
2227 EXPECT_TRUE(deleted
);
2230 // Test that a new request to show an interstitial while an interstitial is
2231 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2232 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2233 GURL
interstitial_url("http://interstitial");
2235 // Show a first interstitial.
2236 TestInterstitialPage::InterstitialState state1
=
2237 TestInterstitialPage::INVALID
;
2238 bool deleted1
= false;
2239 TestInterstitialPage
* interstitial1
=
2240 new TestInterstitialPage(contents(), true, interstitial_url
,
2241 &state1
, &deleted1
);
2242 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2243 interstitial1
->Show();
2245 // Show another interstitial on that same contents before the first one had
2247 TestInterstitialPage::InterstitialState state2
=
2248 TestInterstitialPage::INVALID
;
2249 bool deleted2
= false;
2250 TestInterstitialPage
* interstitial2
=
2251 new TestInterstitialPage(contents(), true, interstitial_url
,
2252 &state2
, &deleted2
);
2253 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2254 interstitial2
->Show();
2255 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2257 // The first interstitial should have been closed and deleted.
2258 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2259 // The 2nd one should still be OK.
2260 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2262 RunAllPendingInMessageLoop();
2263 EXPECT_TRUE(deleted1
);
2264 ASSERT_FALSE(deleted2
);
2266 // Make the interstitial navigation commit it should be showing.
2267 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true,
2269 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2272 // Test showing an interstitial and have its renderer crash.
2273 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2274 // Show an interstitial.
2275 TestInterstitialPage::InterstitialState state
=
2276 TestInterstitialPage::INVALID
;
2277 bool deleted
= false;
2278 GURL
url("http://interstitial");
2279 TestInterstitialPage
* interstitial
=
2280 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2281 TestInterstitialPageStateGuard
state_guard(interstitial
);
2282 interstitial
->Show();
2283 // Simulate a renderer crash before the interstitial is shown.
2284 interstitial
->TestRenderViewTerminated(
2285 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2286 // The interstitial should have been dismissed.
2287 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2288 RunAllPendingInMessageLoop();
2289 EXPECT_TRUE(deleted
);
2291 // Now try again but this time crash the intersitial after it was shown.
2293 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2294 interstitial
->Show();
2295 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2296 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2297 // Simulate a renderer crash.
2298 interstitial
->TestRenderViewTerminated(
2299 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2300 // The interstitial should have been dismissed.
2301 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2302 RunAllPendingInMessageLoop();
2303 EXPECT_TRUE(deleted
);
2306 // Tests that showing an interstitial as a result of a browser initiated
2307 // navigation while an interstitial is showing does not remove the pending
2308 // entry (see http://crbug.com/9791).
2309 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2310 const char kUrl
[] = "http://www.badguys.com/";
2311 const GURL
kGURL(kUrl
);
2313 // Start a navigation to a page
2314 contents()->GetController().LoadURL(
2315 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2317 // Simulate that navigation triggering an interstitial.
2318 TestInterstitialPage::InterstitialState state
=
2319 TestInterstitialPage::INVALID
;
2320 bool deleted
= false;
2321 TestInterstitialPage
* interstitial
=
2322 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2323 TestInterstitialPageStateGuard
state_guard(interstitial
);
2324 interstitial
->Show();
2325 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2326 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2328 // Initiate a new navigation from the browser that also triggers an
2330 contents()->GetController().LoadURL(
2331 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2332 TestInterstitialPage::InterstitialState state2
=
2333 TestInterstitialPage::INVALID
;
2334 bool deleted2
= false;
2335 TestInterstitialPage
* interstitial2
=
2336 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2337 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2338 interstitial2
->Show();
2339 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2340 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2342 // Make sure we still have an entry.
2343 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2345 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2347 // And that the first interstitial is gone, but not the second.
2348 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2349 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2350 RunAllPendingInMessageLoop();
2351 EXPECT_TRUE(deleted
);
2352 EXPECT_FALSE(deleted2
);
2355 // Tests that Javascript messages are not shown while an interstitial is
2357 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2358 const char kUrl
[] = "http://www.badguys.com/";
2359 const GURL
kGURL(kUrl
);
2361 // Start a navigation to a page
2362 contents()->GetController().LoadURL(
2363 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2364 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2365 main_test_rfh()->PrepareForCommit();
2366 // DidNavigate from the page
2367 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
2368 kGURL
, ui::PAGE_TRANSITION_TYPED
);
2370 // Simulate showing an interstitial while the page is showing.
2371 TestInterstitialPage::InterstitialState state
=
2372 TestInterstitialPage::INVALID
;
2373 bool deleted
= false;
2374 TestInterstitialPage
* interstitial
=
2375 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2376 TestInterstitialPageStateGuard
state_guard(interstitial
);
2377 interstitial
->Show();
2378 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2379 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2381 // While the interstitial is showing, let's simulate the hidden page
2382 // attempting to show a JS message.
2383 IPC::Message
* dummy_message
= new IPC::Message
;
2384 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2385 base::ASCIIToUTF16("This is an informative message"),
2386 base::ASCIIToUTF16("OK"),
2387 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2388 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2391 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2392 // interstitial it isn't copied over to the destination.
2393 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2394 // Navigate to a page.
2395 GURL
url1("http://www.google.com");
2396 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2397 EXPECT_EQ(1, controller().GetEntryCount());
2399 // Initiate a browser navigation that will trigger the interstitial
2400 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2401 ui::PAGE_TRANSITION_TYPED
, std::string());
2403 // Show an interstitial.
2404 TestInterstitialPage::InterstitialState state
=
2405 TestInterstitialPage::INVALID
;
2406 bool deleted
= false;
2407 GURL
url2("http://interstitial");
2408 TestInterstitialPage
* interstitial
=
2409 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2410 TestInterstitialPageStateGuard
state_guard(interstitial
);
2411 interstitial
->Show();
2412 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2413 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2414 EXPECT_TRUE(interstitial
->is_showing());
2415 EXPECT_EQ(2, controller().GetEntryCount());
2417 // Create another NavigationController.
2418 GURL
url3("http://foo2");
2419 scoped_ptr
<TestWebContents
> other_contents(
2420 static_cast<TestWebContents
*>(CreateTestWebContents()));
2421 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2422 other_contents
->NavigateAndCommit(url3
);
2423 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
2424 other_controller
.CopyStateFromAndPrune(&controller(), false);
2426 // The merged controller should only have two entries: url1 and url2.
2427 ASSERT_EQ(2, other_controller
.GetEntryCount());
2428 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2429 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2430 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2432 // And the merged controller shouldn't be showing an interstitial.
2433 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2436 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2437 // showing an interstitial.
2438 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2439 // Navigate to a page.
2440 GURL
url1("http://www.google.com");
2441 contents()->NavigateAndCommit(url1
);
2443 // Create another NavigationController.
2444 scoped_ptr
<TestWebContents
> other_contents(
2445 static_cast<TestWebContents
*>(CreateTestWebContents()));
2446 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2448 // Navigate it to url2.
2449 GURL
url2("http://foo2");
2450 other_contents
->NavigateAndCommit(url2
);
2452 // Show an interstitial.
2453 TestInterstitialPage::InterstitialState state
=
2454 TestInterstitialPage::INVALID
;
2455 bool deleted
= false;
2456 GURL
url3("http://interstitial");
2457 TestInterstitialPage
* interstitial
=
2458 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2460 TestInterstitialPageStateGuard
state_guard(interstitial
);
2461 interstitial
->Show();
2462 int interstitial_entry_id
=
2463 other_controller
.GetTransientEntry()->GetUniqueID();
2464 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url3
);
2465 EXPECT_TRUE(interstitial
->is_showing());
2466 EXPECT_EQ(2, other_controller
.GetEntryCount());
2468 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2469 // interstitial is showing in the target.
2470 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2473 // Regression test for http://crbug.com/168611 - the URLs passed by the
2474 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2475 TEST_F(WebContentsImplTest
, FilterURLs
) {
2476 TestWebContentsObserver
observer(contents());
2478 // A navigation to about:whatever should always look like a navigation to
2480 GURL
url_normalized(url::kAboutBlankURL
);
2481 GURL
url_from_ipc("about:whatever");
2483 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2484 // will use the given URL to create the NavigationEntry as well, and that
2485 // entry should contain the filtered URL.
2486 contents()->NavigateAndCommit(url_normalized
);
2488 // Check that an IPC with about:whatever is correctly normalized.
2489 contents()->TestDidFinishLoad(url_from_ipc
);
2491 EXPECT_EQ(url_normalized
, observer
.last_url());
2493 // Create and navigate another WebContents.
2494 scoped_ptr
<TestWebContents
> other_contents(
2495 static_cast<TestWebContents
*>(CreateTestWebContents()));
2496 TestWebContentsObserver
other_observer(other_contents
.get());
2497 other_contents
->NavigateAndCommit(url_normalized
);
2499 // Check that an IPC with about:whatever is correctly normalized.
2500 other_contents
->TestDidFailLoadWithError(
2501 url_from_ipc
, 1, base::string16(), false);
2502 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2505 // Test that if a pending contents is deleted before it is shown, we don't
2507 TEST_F(WebContentsImplTest
, PendingContents
) {
2508 scoped_ptr
<TestWebContents
> other_contents(
2509 static_cast<TestWebContents
*>(CreateTestWebContents()));
2510 contents()->AddPendingContents(other_contents
.get());
2511 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2512 other_contents
.reset();
2513 EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id
));
2516 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2517 const gfx::Size
original_preferred_size(1024, 768);
2518 contents()->UpdatePreferredSize(original_preferred_size
);
2520 // With no capturers, expect the preferred size to be the one propagated into
2521 // WebContentsImpl via the RenderViewHostDelegate interface.
2522 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2523 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2525 // Increment capturer count, but without specifying a capture size. Expect
2526 // a "not set" preferred size.
2527 contents()->IncrementCapturerCount(gfx::Size());
2528 EXPECT_EQ(1, contents()->GetCapturerCount());
2529 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2531 // Increment capturer count again, but with an overriding capture size.
2532 // Expect preferred size to now be overridden to the capture size.
2533 const gfx::Size
capture_size(1280, 720);
2534 contents()->IncrementCapturerCount(capture_size
);
2535 EXPECT_EQ(2, contents()->GetCapturerCount());
2536 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2538 // Increment capturer count a third time, but the expect that the preferred
2539 // size is still the first capture size.
2540 const gfx::Size
another_capture_size(720, 480);
2541 contents()->IncrementCapturerCount(another_capture_size
);
2542 EXPECT_EQ(3, contents()->GetCapturerCount());
2543 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2545 // Decrement capturer count twice, but expect the preferred size to still be
2547 contents()->DecrementCapturerCount();
2548 contents()->DecrementCapturerCount();
2549 EXPECT_EQ(1, contents()->GetCapturerCount());
2550 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2552 // Decrement capturer count, and since the count has dropped to zero, the
2553 // original preferred size should be restored.
2554 contents()->DecrementCapturerCount();
2555 EXPECT_EQ(0, contents()->GetCapturerCount());
2556 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2559 TEST_F(WebContentsImplTest
, CapturerPreventsHiding
) {
2560 const gfx::Size
original_preferred_size(1024, 768);
2561 contents()->UpdatePreferredSize(original_preferred_size
);
2563 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2564 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2566 // With no capturers, setting and un-setting occlusion should change the
2567 // view's occlusion state.
2568 EXPECT_FALSE(view
->is_showing());
2569 contents()->WasShown();
2570 EXPECT_TRUE(view
->is_showing());
2571 contents()->WasHidden();
2572 EXPECT_FALSE(view
->is_showing());
2573 contents()->WasShown();
2574 EXPECT_TRUE(view
->is_showing());
2576 // Add a capturer and try to hide the contents. The view will remain visible.
2577 contents()->IncrementCapturerCount(gfx::Size());
2578 contents()->WasHidden();
2579 EXPECT_TRUE(view
->is_showing());
2581 // Remove the capturer, and the WasHidden should take effect.
2582 contents()->DecrementCapturerCount();
2583 EXPECT_FALSE(view
->is_showing());
2586 TEST_F(WebContentsImplTest
, CapturerPreventsOcclusion
) {
2587 const gfx::Size
original_preferred_size(1024, 768);
2588 contents()->UpdatePreferredSize(original_preferred_size
);
2590 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2591 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2593 // With no capturers, setting and un-setting occlusion should change the
2594 // view's occlusion state.
2595 EXPECT_FALSE(view
->is_occluded());
2596 contents()->WasOccluded();
2597 EXPECT_TRUE(view
->is_occluded());
2598 contents()->WasUnOccluded();
2599 EXPECT_FALSE(view
->is_occluded());
2600 contents()->WasOccluded();
2601 EXPECT_TRUE(view
->is_occluded());
2603 // Add a capturer. This should cause the view to be un-occluded.
2604 contents()->IncrementCapturerCount(gfx::Size());
2605 EXPECT_FALSE(view
->is_occluded());
2607 // Try to occlude the view. This will fail to propagate because of the
2609 contents()->WasOccluded();
2610 EXPECT_FALSE(view
->is_occluded());
2612 // Remove the capturer and try again.
2613 contents()->DecrementCapturerCount();
2614 EXPECT_FALSE(view
->is_occluded());
2615 contents()->WasOccluded();
2616 EXPECT_TRUE(view
->is_occluded());
2619 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2621 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2622 // The WebContents starts with a valid creation time.
2623 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2625 // Reset the last active time to a known-bad value.
2626 contents()->last_active_time_
= base::TimeTicks();
2627 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2629 // Simulate activating the WebContents. The active time should update.
2630 contents()->WasShown();
2631 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2634 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2636 ContentsZoomChangedDelegate() :
2637 contents_zoom_changed_call_count_(0),
2638 last_zoom_in_(false) {
2641 int GetAndResetContentsZoomChangedCallCount() {
2642 int count
= contents_zoom_changed_call_count_
;
2643 contents_zoom_changed_call_count_
= 0;
2647 bool last_zoom_in() const {
2648 return last_zoom_in_
;
2651 // WebContentsDelegate:
2652 void ContentsZoomChange(bool zoom_in
) override
{
2653 contents_zoom_changed_call_count_
++;
2654 last_zoom_in_
= zoom_in
;
2658 int contents_zoom_changed_call_count_
;
2661 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2664 // Tests that some mouseehweel events get turned into browser zoom requests.
2665 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2666 using blink::WebInputEvent
;
2668 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2669 new ContentsZoomChangedDelegate());
2670 contents()->SetDelegate(delegate
.get());
2673 // Verify that normal mouse wheel events do nothing to change the zoom level.
2674 blink::WebMouseWheelEvent event
=
2675 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2676 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2677 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2679 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
|
2680 WebInputEvent::ControlKey
;
2681 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2682 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2683 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2685 // But whenever the ctrl modifier is applied with canScroll=false, they can
2686 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2688 modifiers
= WebInputEvent::ControlKey
;
2689 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2690 event
.canScroll
= false;
2691 bool handled
= contents()->HandleWheelEvent(event
);
2692 #if defined(OS_MACOSX)
2693 EXPECT_FALSE(handled
);
2694 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2696 EXPECT_TRUE(handled
);
2697 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2698 EXPECT_TRUE(delegate
->last_zoom_in());
2701 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2702 WebInputEvent::AltKey
;
2703 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2704 event
.canScroll
= false;
2705 handled
= contents()->HandleWheelEvent(event
);
2706 #if defined(OS_MACOSX)
2707 EXPECT_FALSE(handled
);
2708 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2710 EXPECT_TRUE(handled
);
2711 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2712 EXPECT_FALSE(delegate
->last_zoom_in());
2715 // Unless there is no vertical movement.
2716 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2717 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2718 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2720 // Events containing precise scrolling deltas also shouldn't result in the
2721 // zoom being adjusted, to avoid accidental adjustments caused by
2722 // two-finger-scrolling on a touchpad.
2723 modifiers
= WebInputEvent::ControlKey
;
2724 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2725 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2726 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2728 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2729 contents()->SetDelegate(nullptr);
2732 // Tests that GetRelatedActiveContentsCount is shared between related
2733 // SiteInstances and includes WebContents that have not navigated yet.
2734 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2735 scoped_refptr
<SiteInstance
> instance1(
2736 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2737 scoped_refptr
<SiteInstance
> instance2(
2738 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2740 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2741 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2743 scoped_ptr
<TestWebContents
> contents1(
2744 TestWebContents::Create(browser_context(), instance1
.get()));
2745 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2746 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2748 scoped_ptr
<TestWebContents
> contents2(
2749 TestWebContents::Create(browser_context(), instance1
.get()));
2750 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2751 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2754 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2755 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2758 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2759 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2762 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2763 // same-site and cross-site navigations.
2764 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2765 scoped_refptr
<SiteInstance
> instance(
2766 SiteInstance::Create(browser_context()));
2768 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2770 scoped_ptr
<TestWebContents
> contents(
2771 TestWebContents::Create(browser_context(), instance
.get()));
2772 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2774 // Navigate to a URL.
2775 contents
->GetController().LoadURL(GURL("http://a.com/1"),
2777 ui::PAGE_TRANSITION_TYPED
,
2779 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2780 contents
->CommitPendingNavigation();
2781 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2783 // Navigate to a URL in the same site.
2784 contents
->GetController().LoadURL(GURL("http://a.com/2"),
2786 ui::PAGE_TRANSITION_TYPED
,
2788 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2789 contents
->CommitPendingNavigation();
2790 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2792 // Navigate to a URL in a different site.
2793 const GURL kUrl
= GURL("http://b.com");
2794 contents
->GetController().LoadURL(kUrl
,
2796 ui::PAGE_TRANSITION_TYPED
,
2798 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2799 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2800 switches::kEnableBrowserSideNavigation
)) {
2801 contents
->GetMainFrame()->PrepareForCommit();
2803 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2804 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2805 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kUrl
);
2806 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2809 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2812 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2814 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2815 scoped_refptr
<SiteInstance
> instance(
2816 SiteInstance::Create(browser_context()));
2818 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2820 scoped_ptr
<TestWebContents
> contents(
2821 TestWebContents::Create(browser_context(), instance
.get()));
2822 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2824 // Navigate to a URL.
2825 contents
->NavigateAndCommit(GURL("http://a.com"));
2826 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2828 // Navigate to a URL which sort of looks like a chrome:// url.
2829 contents
->NavigateAndCommit(GURL("http://gpu"));
2830 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2832 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2833 const GURL kWebUIUrl
= GURL("chrome://gpu");
2834 contents
->GetController().LoadURL(kWebUIUrl
,
2836 ui::PAGE_TRANSITION_TYPED
,
2838 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2839 contents
->GetMainFrame()->PrepareForCommit();
2840 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2841 scoped_refptr
<SiteInstance
> instance_webui(
2842 contents
->GetPendingMainFrame()->GetSiteInstance());
2843 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2845 // At this point, contents still counts for the old BrowsingInstance.
2846 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2847 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2849 // Commit and contents counts for the new one.
2850 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kWebUIUrl
);
2851 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2852 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2855 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2856 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2859 class LoadingWebContentsObserver
: public WebContentsObserver
{
2861 explicit LoadingWebContentsObserver(WebContents
* contents
)
2862 : WebContentsObserver(contents
),
2863 is_loading_(false) {
2865 ~LoadingWebContentsObserver() override
{}
2867 void DidStartLoading() override
{ is_loading_
= true; }
2868 void DidStopLoading() override
{ is_loading_
= false; }
2870 bool is_loading() const { return is_loading_
; }
2875 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver
);
2878 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2879 // interleaving cross-process navigations in multiple subframes.
2880 // See https://crbug.com/448601 for details of the underlying issue. The
2881 // sequence of events that reproduce it are as follows:
2882 // * Navigate top-level frame with one subframe.
2883 // * Subframe navigates more than once before the top-level frame has had a
2884 // chance to complete the load.
2885 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2886 // to 0, while the loading_progresses_ map is not reset.
2887 TEST_F(WebContentsImplTest
, StartStopEventsBalance
) {
2888 // The bug manifests itself in regular mode as well, but browser-initiated
2889 // navigation of subframes is only possible in --site-per-process mode within
2891 IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
2892 const GURL
initial_url("about:blank");
2893 const GURL
main_url("http://www.chromium.org");
2894 const GURL
foo_url("http://foo.chromium.org");
2895 const GURL
bar_url("http://bar.chromium.org");
2896 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
2898 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
2899 LoadingWebContentsObserver
observer(contents());
2901 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
2902 // The frame should still be loading.
2903 controller().LoadURL(
2904 main_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2905 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2906 orig_rfh
->PrepareForCommit();
2907 orig_rfh
->OnMessageReceived(
2908 FrameHostMsg_DidStartLoading(orig_rfh
->GetRoutingID(), false));
2909 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, main_url
,
2910 ui::PAGE_TRANSITION_TYPED
);
2911 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2912 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
2913 EXPECT_TRUE(contents()->IsLoading());
2914 EXPECT_TRUE(observer
.is_loading());
2916 // Create a child frame to navigate multiple times.
2917 TestRenderFrameHost
* subframe
= orig_rfh
->AppendChild("subframe");
2919 // Navigate the child frame to about:blank, which will send both
2920 // DidStartLoading and DidStopLoading messages.
2922 subframe
->SendRendererInitiatedNavigationRequest(initial_url
, false);
2923 subframe
->OnMessageReceived(
2924 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2925 subframe
->SendNavigateWithTransition(1, 0, false, initial_url
,
2926 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2927 subframe
->OnMessageReceived(
2928 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2931 // Navigate the frame to another URL, which will send again
2932 // DidStartLoading and DidStopLoading messages.
2934 subframe
->SendRendererInitiatedNavigationRequest(foo_url
, false);
2935 subframe
->PrepareForCommit();
2936 subframe
->OnMessageReceived(
2937 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2938 subframe
->SendNavigateWithTransition(1, 0, false, foo_url
,
2939 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2940 subframe
->OnMessageReceived(
2941 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2944 // Since the main frame hasn't sent any DidStopLoading messages, it is
2945 // expected that the WebContents is still in loading state.
2946 EXPECT_TRUE(contents()->IsLoading());
2947 EXPECT_TRUE(observer
.is_loading());
2949 // Navigate the frame again, this time using LoadURLWithParams. This causes
2950 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2953 NavigationController::LoadURLParams
load_params(bar_url
);
2954 load_params
.referrer
=
2955 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
2956 load_params
.transition_type
= ui::PAGE_TRANSITION_GENERATED
;
2957 load_params
.extra_headers
= "content-type: text/plain";
2958 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
2959 load_params
.is_renderer_initiated
= false;
2960 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
2961 load_params
.frame_tree_node_id
=
2962 subframe
->frame_tree_node()->frame_tree_node_id();
2963 controller().LoadURLWithParams(load_params
);
2964 entry_id
= controller().GetPendingEntry()->GetUniqueID();
2966 subframe
->OnMessageReceived(
2967 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2969 // Commit the navigation in the child frame and send the DidStopLoading
2971 subframe
->PrepareForCommit();
2972 contents()->TestDidNavigate(subframe
, 3, entry_id
, true, bar_url
,
2973 ui::PAGE_TRANSITION_MANUAL_SUBFRAME
);
2974 subframe
->OnMessageReceived(
2975 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2978 // At this point the status should still be loading, since the main frame
2979 // hasn't sent the DidstopLoading message yet.
2980 EXPECT_TRUE(contents()->IsLoading());
2981 EXPECT_TRUE(observer
.is_loading());
2983 // Send the DidStopLoading for the main frame and ensure it isn't loading
2985 orig_rfh
->OnMessageReceived(
2986 FrameHostMsg_DidStopLoading(orig_rfh
->GetRoutingID()));
2987 EXPECT_FALSE(contents()->IsLoading());
2988 EXPECT_FALSE(observer
.is_loading());
2991 // Ensure that WebContentsImpl does not stop loading too early when there still
2992 // is a pending renderer. This can happen if a same-process non user-initiated
2993 // navigation completes while there is an ongoing cross-process navigation.
2994 // TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
2995 // DidStopLoading are properly called.
2996 TEST_F(WebContentsImplTest
, NoEarlyStop
) {
2997 const GURL
kUrl1("http://www.chromium.org");
2998 const GURL
kUrl2("http://www.google.com");
2999 const GURL
kUrl3("http://www.wikipedia.org");
3001 contents()->NavigateAndCommit(kUrl1
);
3003 TestRenderFrameHost
* current_rfh
= contents()->GetMainFrame();
3005 // Start a browser-initiated cross-process navigation to |kUrl2|. There should
3006 // be a pending RenderFrameHost and the WebContents should be loading.
3007 controller().LoadURL(
3008 kUrl2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
3009 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
3010 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
3011 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
3012 ASSERT_TRUE(pending_rfh
);
3013 EXPECT_TRUE(contents()->IsLoading());
3015 // The current RenderFrameHost starts a non user-initiated render-initiated
3016 // navigation and sends a DidStartLoading IPC. The WebContents should still be
3018 current_rfh
->OnMessageReceived(
3019 FrameHostMsg_DidStartLoading(current_rfh
->GetRoutingID(), false));
3020 EXPECT_TRUE(contents()->IsLoading());
3022 // Simulate the pending RenderFrameHost DidStartLoading. There should still be
3023 // a pending RenderFrameHost and the WebContents should still be loading.
3024 pending_rfh
->PrepareForCommit();
3025 pending_rfh
->OnMessageReceived(
3026 FrameHostMsg_DidStartLoading(pending_rfh
->GetRoutingID(), false));
3027 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3028 EXPECT_TRUE(contents()->IsLoading());
3030 // Simulate the commit and DidStopLoading from the renderer-initiated
3031 // navigation in the current RenderFrameHost. There should still be a pending
3032 // RenderFrameHost and the WebContents should still be loading.
3033 current_rfh
->SendNavigateWithModificationCallback(
3034 1, 0, true, kUrl3
, base::Bind(SetAsNonUserGesture
));
3035 current_rfh
->OnMessageReceived(
3036 FrameHostMsg_DidStopLoading(current_rfh
->GetRoutingID()));
3037 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3038 EXPECT_TRUE(contents()->IsLoading());
3039 // It should commit.
3040 ASSERT_EQ(2, controller().GetEntryCount());
3041 EXPECT_EQ(kUrl3
, controller().GetLastCommittedEntry()->GetURL());
3043 // Commit the navigation. The formerly pending RenderFrameHost should now be
3044 // the current RenderFrameHost and the WebContents should still be loading.
3045 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, kUrl2
,
3046 ui::PAGE_TRANSITION_TYPED
);
3047 EXPECT_FALSE(contents()->GetPendingMainFrame());
3048 TestRenderFrameHost
* new_current_rfh
= contents()->GetMainFrame();
3049 EXPECT_EQ(new_current_rfh
, pending_rfh
);
3050 EXPECT_TRUE(contents()->IsLoading());
3051 EXPECT_EQ(3, controller().GetEntryCount());
3053 // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
3054 // should now have stopped loading.
3055 new_current_rfh
->OnMessageReceived(
3056 FrameHostMsg_DidStopLoading(new_current_rfh
->GetRoutingID()));
3057 EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh
);
3058 EXPECT_FALSE(contents()->IsLoading());
3061 TEST_F(WebContentsImplTest
, MediaPowerSaveBlocking
) {
3062 // PlayerIDs are actually pointers cast to int64, so verify that both negative
3063 // and positive player ids don't blow up.
3064 const int kPlayerAudioVideoId
= 15;
3065 const int kPlayerAudioOnlyId
= -15;
3066 const int kPlayerVideoOnlyId
= 30;
3067 const int kPlayerRemoteId
= -30;
3069 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3070 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3072 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3073 AudioStateProvider
* audio_state
= contents()->audio_state_provider();
3075 // Ensure RenderFrame is initialized before simulating events coming from it.
3076 main_test_rfh()->InitializeRenderFrameIfNeeded();
3078 // The audio power save blocker should not be based on having a media player
3079 // when audio stream monitoring is available.
3080 if (audio_state
->IsAudioStateAvailable()) {
3081 // Send a fake audio stream monitor notification. The audio power save
3082 // blocker should be created.
3083 audio_state
->set_was_recently_audible_for_testing(true);
3084 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3085 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
3087 // Send another fake notification, this time when WasRecentlyAudible() will
3088 // be false. The power save blocker should be released.
3089 audio_state
->set_was_recently_audible_for_testing(false);
3090 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3091 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3094 // Start a player with both audio and video. A video power save blocker
3095 // should be created. If audio stream monitoring is available, an audio power
3096 // save blocker should be created too.
3097 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3098 0, kPlayerAudioVideoId
, true, true, false));
3099 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3100 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3101 !audio_state
->IsAudioStateAvailable());
3103 // Upon hiding the video power save blocker should be released.
3104 contents()->WasHidden();
3105 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3107 // Start another player that only has video. There should be no change in
3108 // the power save blockers. The notification should take into account the
3109 // visibility state of the WebContents.
3110 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3111 0, kPlayerVideoOnlyId
, true, false, false));
3112 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3113 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3114 !audio_state
->IsAudioStateAvailable());
3116 // Showing the WebContents should result in the creation of the blocker.
3117 contents()->WasShown();
3118 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3120 // Start another player that only has audio. There should be no change in
3121 // the power save blockers.
3122 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3123 0, kPlayerAudioOnlyId
, false, true, false));
3124 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3125 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3126 !audio_state
->IsAudioStateAvailable());
3128 // Start a remote player. There should be no change in the power save
3130 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3131 0, kPlayerRemoteId
, true, true, true));
3132 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3133 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3134 !audio_state
->IsAudioStateAvailable());
3136 // Destroy the original audio video player. Both power save blockers should
3138 rfh
->OnMessageReceived(
3139 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId
));
3140 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3141 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3142 !audio_state
->IsAudioStateAvailable());
3144 // Destroy the audio only player. The video power save blocker should remain.
3145 rfh
->OnMessageReceived(
3146 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId
));
3147 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3148 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3150 // Destroy the video only player. No power save blockers should remain.
3151 rfh
->OnMessageReceived(
3152 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId
));
3153 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3154 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3156 // Destroy the remote player. No power save blockers should remain.
3157 rfh
->OnMessageReceived(
3158 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId
));
3159 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3160 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3162 // Start a player with both audio and video. A video power save blocker
3163 // should be created. If audio stream monitoring is available, an audio power
3164 // save blocker should be created too.
3165 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3166 0, kPlayerAudioVideoId
, true, true, false));
3167 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3168 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3169 !audio_state
->IsAudioStateAvailable());
3171 // Crash the renderer.
3172 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
3174 // Verify that all the power save blockers have been released.
3175 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3176 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3179 TEST_F(WebContentsImplTest
, ThemeColorChangeDependingOnFirstVisiblePaint
) {
3180 TestWebContentsObserver
observer(contents());
3181 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3183 SkColor transparent
= SK_ColorTRANSPARENT
;
3185 EXPECT_EQ(transparent
, contents()->GetThemeColor());
3186 EXPECT_EQ(transparent
, observer
.last_theme_color());
3188 // Theme color changes should not propagate past the WebContentsImpl before
3189 // the first visually non-empty paint has occurred.
3190 RenderViewHostTester::TestOnMessageReceived(
3192 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorRED
));
3194 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3195 EXPECT_EQ(transparent
, observer
.last_theme_color());
3197 // Simulate that the first visually non-empty paint has occurred. This will
3198 // propagate the current theme color to the delegates.
3199 RenderViewHostTester::TestOnMessageReceived(
3201 FrameHostMsg_DidFirstVisuallyNonEmptyPaint(rfh
->GetRoutingID()));
3203 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3204 EXPECT_EQ(SK_ColorRED
, observer
.last_theme_color());
3206 // Additional changes made by the web contents should propagate as well.
3207 RenderViewHostTester::TestOnMessageReceived(
3209 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorGREEN
));
3211 EXPECT_EQ(SK_ColorGREEN
, contents()->GetThemeColor());
3212 EXPECT_EQ(SK_ColorGREEN
, observer
.last_theme_color());
3215 // Test that if a renderer reports that it has loaded a resource from
3216 // memory cache with bad security info (i.e. can't be deserialized), the
3217 // renderer gets killed.
3218 TEST_F(WebContentsImplTest
, LoadResourceFromMemoryCacheWithBadSecurityInfo
) {
3219 MockRenderProcessHost
* rph
= contents()->GetMainFrame()->GetProcess();
3220 EXPECT_EQ(0, rph
->bad_msg_count());
3222 contents()->OnDidLoadResourceFromMemoryCache(
3223 GURL("http://example.test"), "not valid security info", "GET",
3224 "mime type", RESOURCE_TYPE_MAIN_FRAME
);
3225 EXPECT_EQ(1, rph
->bad_msg_count());
3228 } // namespace content