1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/logging.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/frame_host/cross_site_transferring_request.h"
9 #include "content/browser/frame_host/interstitial_page_impl.h"
10 #include "content/browser/frame_host/navigation_entry_impl.h"
11 #include "content/browser/frame_host/render_frame_host_impl.h"
12 #include "content/browser/frame_host/render_frame_proxy_host.h"
13 #include "content/browser/media/audio_state_provider.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/browser/site_instance_impl.h"
16 #include "content/browser/webui/content_web_ui_controller_factory.h"
17 #include "content/browser/webui/web_ui_controller_factory_registry.h"
18 #include "content/common/frame_messages.h"
19 #include "content/common/input/synthetic_web_input_event_builders.h"
20 #include "content/common/view_messages.h"
21 #include "content/public/browser/global_request_id.h"
22 #include "content/public/browser/interstitial_page_delegate.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/notification_details.h"
25 #include "content/public/browser/notification_source.h"
26 #include "content/public/browser/render_widget_host_view.h"
27 #include "content/public/browser/web_contents_delegate.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/browser/web_ui_controller.h"
30 #include "content/public/common/bindings_policy.h"
31 #include "content/public/common/content_constants.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/url_constants.h"
34 #include "content/public/common/url_utils.h"
35 #include "content/public/test/mock_render_process_host.h"
36 #include "content/public/test/test_utils.h"
37 #include "content/test/test_content_browser_client.h"
38 #include "content/test/test_content_client.h"
39 #include "content/test/test_render_frame_host.h"
40 #include "content/test/test_render_view_host.h"
41 #include "content/test/test_web_contents.h"
42 #include "testing/gtest/include/gtest/gtest.h"
43 #include "third_party/skia/include/core/SkColor.h"
48 class TestInterstitialPage
;
50 class TestInterstitialPageDelegate
: public InterstitialPageDelegate
{
52 explicit TestInterstitialPageDelegate(TestInterstitialPage
* interstitial_page
)
53 : interstitial_page_(interstitial_page
) {}
54 void CommandReceived(const std::string
& command
) override
;
55 std::string
GetHTMLContents() override
{ return std::string(); }
56 void OnDontProceed() override
;
57 void OnProceed() override
;
60 TestInterstitialPage
* interstitial_page_
;
63 class TestInterstitialPage
: public InterstitialPageImpl
{
65 enum InterstitialState
{
66 INVALID
= 0, // Hasn't yet been initialized.
67 UNDECIDED
, // Initialized, but no decision taken yet.
68 OKED
, // Proceed was called.
69 CANCELED
// DontProceed was called.
74 virtual void TestInterstitialPageDeleted(
75 TestInterstitialPage
* interstitial
) = 0;
78 virtual ~Delegate() {}
81 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
82 // |deleted| (like all interstitial related tests do at this point), make sure
83 // to create an instance of the TestInterstitialPageStateGuard class on the
84 // stack in your test. This will ensure that the TestInterstitialPage states
85 // are cleared when the test finishes.
86 // Not doing so will cause stack trashing if your test does not hide the
87 // interstitial, as in such a case it will be destroyed in the test TearDown
88 // method and will dereference the |deleted| local variable which by then is
90 TestInterstitialPage(WebContentsImpl
* contents
,
93 InterstitialState
* state
,
95 : InterstitialPageImpl(
97 static_cast<RenderWidgetHostDelegate
*>(contents
),
98 new_navigation
, url
, new TestInterstitialPageDelegate(this)),
101 command_received_count_(0),
107 ~TestInterstitialPage() override
{
111 delegate_
->TestInterstitialPageDeleted(this);
114 void OnDontProceed() {
123 int command_received_count() const {
124 return command_received_count_
;
127 void TestDomOperationResponse(const std::string
& json_string
) {
132 void TestDidNavigate(int page_id
,
134 bool did_create_new_entry
,
136 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
137 InitNavigateParams(¶ms
, page_id
, nav_entry_id
, did_create_new_entry
,
138 url
, ui::PAGE_TRANSITION_TYPED
);
139 DidNavigate(GetMainFrame()->GetRenderViewHost(), params
);
142 void TestRenderViewTerminated(base::TerminationStatus status
,
144 RenderViewTerminated(GetMainFrame()->GetRenderViewHost(), status
,
148 bool is_showing() const {
149 return static_cast<TestRenderWidgetHostView
*>(
150 GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
159 void CommandReceived() {
160 command_received_count_
++;
163 void set_delegate(Delegate
* delegate
) {
164 delegate_
= delegate
;
168 WebContentsView
* CreateWebContentsView() override
{ return nullptr; }
171 InterstitialState
* state_
;
173 int command_received_count_
;
177 void TestInterstitialPageDelegate::CommandReceived(const std::string
& command
) {
178 interstitial_page_
->CommandReceived();
181 void TestInterstitialPageDelegate::OnDontProceed() {
182 interstitial_page_
->OnDontProceed();
185 void TestInterstitialPageDelegate::OnProceed() {
186 interstitial_page_
->OnProceed();
189 class TestInterstitialPageStateGuard
: public TestInterstitialPage::Delegate
{
191 explicit TestInterstitialPageStateGuard(
192 TestInterstitialPage
* interstitial_page
)
193 : interstitial_page_(interstitial_page
) {
194 DCHECK(interstitial_page_
);
195 interstitial_page_
->set_delegate(this);
197 ~TestInterstitialPageStateGuard() override
{
198 if (interstitial_page_
)
199 interstitial_page_
->ClearStates();
202 void TestInterstitialPageDeleted(
203 TestInterstitialPage
* interstitial
) override
{
204 DCHECK(interstitial_page_
== interstitial
);
205 interstitial_page_
= nullptr;
209 TestInterstitialPage
* interstitial_page_
;
212 class WebContentsImplTestBrowserClient
: public TestContentBrowserClient
{
214 WebContentsImplTestBrowserClient()
215 : assign_site_for_url_(false) {}
217 ~WebContentsImplTestBrowserClient() override
{}
219 bool ShouldAssignSiteForURL(const GURL
& url
) override
{
220 return assign_site_for_url_
;
223 void set_assign_site_for_url(bool assign
) {
224 assign_site_for_url_
= assign
;
228 bool assign_site_for_url_
;
231 class WebContentsImplTest
: public RenderViewHostImplTestHarness
{
233 void SetUp() override
{
234 RenderViewHostImplTestHarness::SetUp();
235 WebUIControllerFactory::RegisterFactory(
236 ContentWebUIControllerFactory::GetInstance());
239 void TearDown() override
{
240 WebUIControllerFactory::UnregisterFactoryForTesting(
241 ContentWebUIControllerFactory::GetInstance());
242 RenderViewHostImplTestHarness::TearDown();
246 class TestWebContentsObserver
: public WebContentsObserver
{
248 explicit TestWebContentsObserver(WebContents
* contents
)
249 : WebContentsObserver(contents
),
250 last_theme_color_(SK_ColorTRANSPARENT
) {
252 ~TestWebContentsObserver() override
{}
254 void DidFinishLoad(RenderFrameHost
* render_frame_host
,
255 const GURL
& validated_url
) override
{
256 last_url_
= validated_url
;
258 void DidFailLoad(RenderFrameHost
* render_frame_host
,
259 const GURL
& validated_url
,
261 const base::string16
& error_description
,
262 bool was_ignored_by_handler
) override
{
263 last_url_
= validated_url
;
266 void DidChangeThemeColor(SkColor theme_color
) override
{
267 last_theme_color_
= theme_color
;
270 const GURL
& last_url() const { return last_url_
; }
271 SkColor
last_theme_color() const { return last_theme_color_
; }
275 SkColor last_theme_color_
;
277 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver
);
280 // Pretends to be a normal browser that receives toggles and transitions to/from
281 // a fullscreened state.
282 class FakeFullscreenDelegate
: public WebContentsDelegate
{
284 FakeFullscreenDelegate() : fullscreened_contents_(nullptr) {}
285 ~FakeFullscreenDelegate() override
{}
287 void EnterFullscreenModeForTab(WebContents
* web_contents
,
288 const GURL
& origin
) override
{
289 fullscreened_contents_
= web_contents
;
292 void ExitFullscreenModeForTab(WebContents
* web_contents
) override
{
293 fullscreened_contents_
= nullptr;
296 bool IsFullscreenForTabOrPending(
297 const WebContents
* web_contents
) const override
{
298 return fullscreened_contents_
&& web_contents
== fullscreened_contents_
;
302 WebContents
* fullscreened_contents_
;
304 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate
);
307 class FakeValidationMessageDelegate
: public WebContentsDelegate
{
309 FakeValidationMessageDelegate()
310 : hide_validation_message_was_called_(false) {}
311 ~FakeValidationMessageDelegate() override
{}
313 void HideValidationMessage(WebContents
* web_contents
) override
{
314 hide_validation_message_was_called_
= true;
317 bool hide_validation_message_was_called() const {
318 return hide_validation_message_was_called_
;
322 bool hide_validation_message_was_called_
;
324 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate
);
329 // Test to make sure that title updates get stripped of whitespace.
330 TEST_F(WebContentsImplTest
, UpdateTitle
) {
331 NavigationControllerImpl
& cont
=
332 static_cast<NavigationControllerImpl
&>(controller());
333 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
334 InitNavigateParams(¶ms
, 0, 0, true, GURL(url::kAboutBlankURL
),
335 ui::PAGE_TRANSITION_TYPED
);
337 LoadCommittedDetails details
;
338 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
340 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
341 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
342 base::i18n::LEFT_TO_RIGHT
);
343 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
346 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
347 const GURL
kGURL("chrome://blah");
348 controller().LoadURL(
349 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
350 EXPECT_EQ(base::string16(), contents()->GetTitle());
353 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
354 const GURL
kGURL("chrome://blah");
355 const base::string16 title
= base::ASCIIToUTF16("My Title");
356 controller().LoadURL(
357 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
359 NavigationEntry
* entry
= controller().GetVisibleEntry();
360 ASSERT_EQ(kGURL
, entry
->GetURL());
361 entry
->SetTitle(title
);
363 EXPECT_EQ(title
, contents()->GetTitle());
366 // Test view source mode for a webui page.
367 TEST_F(WebContentsImplTest
, NTPViewSource
) {
368 NavigationControllerImpl
& cont
=
369 static_cast<NavigationControllerImpl
&>(controller());
370 const char kUrl
[] = "view-source:chrome://blah";
371 const GURL
kGURL(kUrl
);
373 process()->sink().ClearMessages();
376 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
377 int entry_id
= cont
.GetPendingEntry()->GetUniqueID();
378 rvh()->GetDelegate()->RenderViewCreated(rvh());
379 // Did we get the expected message?
380 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
381 ViewMsg_EnableViewSourceMode::ID
));
383 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
384 InitNavigateParams(¶ms
, 0, entry_id
, true, kGURL
,
385 ui::PAGE_TRANSITION_TYPED
);
386 LoadCommittedDetails details
;
387 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
388 // Also check title and url.
389 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
392 // Test to ensure UpdateMaxPageID is working properly.
393 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
394 SiteInstance
* instance1
= contents()->GetSiteInstance();
395 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(nullptr));
398 EXPECT_EQ(-1, contents()->GetMaxPageID());
399 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
400 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
402 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
403 contents()->UpdateMaxPageID(3);
404 contents()->UpdateMaxPageID(1);
405 EXPECT_EQ(3, contents()->GetMaxPageID());
406 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
407 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
409 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
410 EXPECT_EQ(3, contents()->GetMaxPageID());
411 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
412 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
415 // Test simple same-SiteInstance navigation.
416 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
417 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
418 SiteInstance
* instance1
= contents()->GetSiteInstance();
419 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
422 const GURL
url("http://www.google.com");
423 controller().LoadURL(
424 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
425 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
426 main_test_rfh()->PrepareForCommit();
427 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
428 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
429 // Controller's pending entry will have a null site instance until we assign
430 // it in DidNavigate.
433 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
436 // DidNavigate from the page
437 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
438 ui::PAGE_TRANSITION_TYPED
);
439 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
440 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
441 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
442 // Controller's entry should now have the SiteInstance, or else we won't be
443 // able to find it later.
446 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
450 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
451 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
452 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
453 const GURL
url(std::string("http://example.org/").append(
454 GetMaxURLChars() + 1, 'a'));
456 controller().LoadURL(
457 url
, Referrer(), ui::PAGE_TRANSITION_GENERATED
, std::string());
458 EXPECT_EQ(nullptr, controller().GetVisibleEntry());
461 // Test that navigating across a site boundary creates a new RenderViewHost
462 // with a new SiteInstance. Going back should do the same.
463 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
464 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
465 int orig_rvh_delete_count
= 0;
466 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
467 SiteInstance
* instance1
= contents()->GetSiteInstance();
469 // Navigate to URL. First URL should use first RenderViewHost.
470 const GURL
url("http://www.google.com");
471 controller().LoadURL(
472 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
473 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
474 orig_rfh
->PrepareForCommit();
475 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
476 ui::PAGE_TRANSITION_TYPED
);
478 // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
479 // that orig_rfh doesn't get deleted when it gets swapped out.
480 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
482 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
483 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
484 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
485 EXPECT_EQ(url
, contents()->GetVisibleURL());
487 // Navigate to new site
488 const GURL
url2("http://www.yahoo.com");
489 controller().LoadURL(
490 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
491 entry_id
= controller().GetPendingEntry()->GetUniqueID();
492 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
493 switches::kEnableBrowserSideNavigation
)) {
494 orig_rfh
->PrepareForCommit();
496 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
497 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
498 EXPECT_EQ(url2
, contents()->GetVisibleURL());
499 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
500 int pending_rvh_delete_count
= 0;
501 pending_rfh
->GetRenderViewHost()->set_delete_counter(
502 &pending_rvh_delete_count
);
504 // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
505 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
506 switches::kEnableBrowserSideNavigation
)) {
507 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
508 orig_rfh
->SendBeforeUnloadACK(true);
509 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
512 // DidNavigate from the pending page
513 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
514 ui::PAGE_TRANSITION_TYPED
);
515 SiteInstance
* instance2
= contents()->GetSiteInstance();
517 // Keep the number of active frames in pending_rfh's SiteInstance
518 // non-zero so that orig_rfh doesn't get deleted when it gets
520 pending_rfh
->GetSiteInstance()->increment_active_frame_count();
522 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
523 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
524 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
525 EXPECT_EQ(url2
, contents()->GetVisibleURL());
526 EXPECT_NE(instance1
, instance2
);
527 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
528 // We keep a proxy for the original RFH's SiteInstance.
529 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
530 orig_rfh
->GetSiteInstance()));
531 EXPECT_EQ(orig_rvh_delete_count
, 0);
533 // Going back should switch SiteInstances again. The first SiteInstance is
534 // stored in the NavigationEntry, so it should be the same as at the start.
535 // We should use the same RFH as before, swapping it back in.
536 controller().GoBack();
537 entry_id
= controller().GetPendingEntry()->GetUniqueID();
538 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
539 switches::kEnableBrowserSideNavigation
)) {
540 contents()->GetMainFrame()->PrepareForCommit();
542 TestRenderFrameHost
* goback_rfh
= contents()->GetPendingMainFrame();
543 if (!RenderFrameHostManager::IsSwappedOutStateForbidden()) {
544 // Recycling the rfh is a behavior specific to swappedout://
545 EXPECT_EQ(orig_rfh
, goback_rfh
);
547 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
549 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
550 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
551 switches::kEnableBrowserSideNavigation
)) {
552 EXPECT_TRUE(goback_rfh
->are_navigations_suspended());
553 pending_rfh
->SendBeforeUnloadACK(true);
554 EXPECT_FALSE(goback_rfh
->are_navigations_suspended());
557 // DidNavigate from the back action
558 contents()->TestDidNavigate(goback_rfh
, 1, entry_id
, false, url2
,
559 ui::PAGE_TRANSITION_TYPED
);
560 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
561 EXPECT_EQ(goback_rfh
, contents()->GetMainFrame());
562 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
563 // There should be a proxy for the pending RFH SiteInstance.
564 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
565 GetRenderFrameProxyHost(pending_rfh
->GetSiteInstance()));
566 EXPECT_EQ(pending_rvh_delete_count
, 0);
567 pending_rfh
->OnSwappedOut();
569 // Close contents and ensure RVHs are deleted.
571 EXPECT_EQ(orig_rvh_delete_count
, 1);
572 EXPECT_EQ(pending_rvh_delete_count
, 1);
575 // Test that navigating across a site boundary after a crash creates a new
576 // RFH without requiring a cross-site transition (i.e., PENDING state).
577 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
578 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
580 int orig_rvh_delete_count
= 0;
581 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
582 SiteInstance
* instance1
= contents()->GetSiteInstance();
584 // Navigate to URL. First URL should use first RenderViewHost.
585 const GURL
url("http://www.google.com");
586 controller().LoadURL(
587 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
588 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
589 contents()->GetMainFrame()->PrepareForCommit();
590 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
591 ui::PAGE_TRANSITION_TYPED
);
593 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
594 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
596 // Simulate a renderer crash.
597 EXPECT_TRUE(orig_rfh
->IsRenderFrameLive());
598 orig_rfh
->GetProcess()->SimulateCrash();
599 EXPECT_FALSE(orig_rfh
->IsRenderFrameLive());
601 // Navigate to new site. We should not go into PENDING.
602 const GURL
url2("http://www.yahoo.com");
603 controller().LoadURL(
604 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
605 entry_id
= controller().GetPendingEntry()->GetUniqueID();
606 contents()->GetMainFrame()->PrepareForCommit();
607 TestRenderFrameHost
* new_rfh
= contents()->GetMainFrame();
608 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
609 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
610 EXPECT_NE(orig_rfh
, new_rfh
);
611 EXPECT_EQ(orig_rvh_delete_count
, 1);
613 // DidNavigate from the new page
614 contents()->TestDidNavigate(new_rfh
, 1, entry_id
, true, url2
,
615 ui::PAGE_TRANSITION_TYPED
);
616 SiteInstance
* instance2
= contents()->GetSiteInstance();
618 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
619 EXPECT_EQ(new_rfh
, main_rfh());
620 EXPECT_NE(instance1
, instance2
);
621 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
623 // Close contents and ensure RVHs are deleted.
625 EXPECT_EQ(orig_rvh_delete_count
, 1);
628 // Test that opening a new contents in the same SiteInstance and then navigating
629 // both contentses to a new site will place both contentses in a single
631 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
632 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
633 SiteInstance
* instance1
= contents()->GetSiteInstance();
635 // Navigate to URL. First URL should use first RenderViewHost.
636 const GURL
url("http://www.google.com");
637 controller().LoadURL(
638 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
639 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
640 contents()->GetMainFrame()->PrepareForCommit();
641 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
642 ui::PAGE_TRANSITION_TYPED
);
644 // Open a new contents with the same SiteInstance, navigated to the same site.
645 scoped_ptr
<TestWebContents
> contents2(
646 TestWebContents::Create(browser_context(), instance1
));
647 contents2
->GetController().LoadURL(url
, Referrer(),
648 ui::PAGE_TRANSITION_TYPED
,
650 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
651 contents2
->GetMainFrame()->PrepareForCommit();
652 // Need this page id to be 2 since the site instance is the same (which is the
653 // scope of page IDs) and we want to consider this a new page.
654 contents2
->TestDidNavigate(contents2
->GetMainFrame(), 2, entry_id
, true, url
,
655 ui::PAGE_TRANSITION_TYPED
);
657 // Navigate first contents to a new site.
658 const GURL
url2a("http://www.yahoo.com");
659 controller().LoadURL(
660 url2a
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
661 entry_id
= controller().GetPendingEntry()->GetUniqueID();
662 orig_rfh
->PrepareForCommit();
663 TestRenderFrameHost
* pending_rfh_a
= contents()->GetPendingMainFrame();
664 contents()->TestDidNavigate(pending_rfh_a
, 1, entry_id
, true, url2a
,
665 ui::PAGE_TRANSITION_TYPED
);
666 SiteInstance
* instance2a
= contents()->GetSiteInstance();
667 EXPECT_NE(instance1
, instance2a
);
669 // Navigate second contents to the same site as the first tab.
670 const GURL
url2b("http://mail.yahoo.com");
671 contents2
->GetController().LoadURL(url2b
, Referrer(),
672 ui::PAGE_TRANSITION_TYPED
,
674 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
675 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
676 rfh2
->PrepareForCommit();
677 TestRenderFrameHost
* pending_rfh_b
= contents2
->GetPendingMainFrame();
678 EXPECT_NE(nullptr, pending_rfh_b
);
679 EXPECT_TRUE(contents2
->CrossProcessNavigationPending());
681 // NOTE(creis): We used to be in danger of showing a crash page here if the
682 // second contents hadn't navigated somewhere first (bug 1145430). That case
683 // is now covered by the CrossSiteBoundariesAfterCrash test.
684 contents2
->TestDidNavigate(pending_rfh_b
, 2, entry_id
, true, url2b
,
685 ui::PAGE_TRANSITION_TYPED
);
686 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
687 EXPECT_NE(instance1
, instance2b
);
689 // Both contentses should now be in the same SiteInstance.
690 EXPECT_EQ(instance2a
, instance2b
);
693 // The embedder can request sites for certain urls not be be assigned to the
694 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
695 // allowing to reuse the renderer backing certain chrome urls for subsequent
696 // navigation. The test verifies that the override is honored.
697 TEST_F(WebContentsImplTest
, NavigateFromSitelessUrl
) {
698 WebContentsImplTestBrowserClient browser_client
;
699 SetBrowserClientForTesting(&browser_client
);
701 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
702 int orig_rvh_delete_count
= 0;
703 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
704 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
706 browser_client
.set_assign_site_for_url(false);
707 // Navigate to an URL that will not assign a new SiteInstance.
708 const GURL
native_url("non-site-url://stuffandthings");
709 controller().LoadURL(
710 native_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
711 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
712 contents()->GetMainFrame()->PrepareForCommit();
713 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, native_url
,
714 ui::PAGE_TRANSITION_TYPED
);
716 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
717 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
718 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
719 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
720 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
721 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
722 EXPECT_FALSE(orig_instance
->HasSite());
724 browser_client
.set_assign_site_for_url(true);
725 // Navigate to new site (should keep same site instance).
726 const GURL
url("http://www.google.com");
727 controller().LoadURL(
728 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
729 entry_id
= controller().GetPendingEntry()->GetUniqueID();
730 contents()->GetMainFrame()->PrepareForCommit();
731 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
732 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
733 EXPECT_EQ(url
, contents()->GetVisibleURL());
734 EXPECT_FALSE(contents()->GetPendingMainFrame());
735 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url
,
736 ui::PAGE_TRANSITION_TYPED
);
738 // Keep the number of active frames in orig_rfh's SiteInstance
739 // non-zero so that orig_rfh doesn't get deleted when it gets
741 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
743 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
745 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
746 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
748 // Navigate to another new site (should create a new site instance).
749 const GURL
url2("http://www.yahoo.com");
750 controller().LoadURL(
751 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
752 entry_id
= controller().GetPendingEntry()->GetUniqueID();
753 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
754 switches::kEnableBrowserSideNavigation
)) {
755 orig_rfh
->PrepareForCommit();
757 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
758 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
759 EXPECT_EQ(url2
, contents()->GetVisibleURL());
760 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
761 int pending_rvh_delete_count
= 0;
762 pending_rfh
->GetRenderViewHost()->set_delete_counter(
763 &pending_rvh_delete_count
);
765 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
766 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
767 switches::kEnableBrowserSideNavigation
)) {
768 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
769 orig_rfh
->SendBeforeUnloadACK(true);
770 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
773 // DidNavigate from the pending page.
774 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
775 ui::PAGE_TRANSITION_TYPED
);
776 SiteInstance
* new_instance
= contents()->GetSiteInstance();
778 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
779 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
780 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
781 EXPECT_EQ(url2
, contents()->GetVisibleURL());
782 EXPECT_NE(new_instance
, orig_instance
);
783 EXPECT_FALSE(contents()->GetPendingMainFrame());
784 // We keep a proxy for the original RFH's SiteInstance.
785 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
786 orig_rfh
->GetSiteInstance()));
787 EXPECT_EQ(orig_rvh_delete_count
, 0);
788 orig_rfh
->OnSwappedOut();
790 // Close contents and ensure RVHs are deleted.
792 EXPECT_EQ(orig_rvh_delete_count
, 1);
793 EXPECT_EQ(pending_rvh_delete_count
, 1);
796 // Regression test for http://crbug.com/386542 - variation of
797 // NavigateFromSitelessUrl in which the original navigation is a session
799 TEST_F(WebContentsImplTest
, NavigateFromRestoredSitelessUrl
) {
800 WebContentsImplTestBrowserClient browser_client
;
801 SetBrowserClientForTesting(&browser_client
);
802 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
803 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
805 // Restore a navigation entry for URL that should not assign site to the
807 browser_client
.set_assign_site_for_url(false);
808 const GURL
native_url("non-site-url://stuffandthings");
809 ScopedVector
<NavigationEntry
> entries
;
810 scoped_ptr
<NavigationEntry
> new_entry
=
811 NavigationControllerImpl::CreateNavigationEntry(
812 native_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false,
813 std::string(), browser_context());
814 new_entry
->SetPageID(0);
815 entries
.push_back(new_entry
.Pass());
816 controller().Restore(
818 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
820 ASSERT_EQ(0u, entries
.size());
821 ASSERT_EQ(1, controller().GetEntryCount());
823 controller().GoToIndex(0);
824 NavigationEntry
* entry
= controller().GetPendingEntry();
825 orig_rfh
->PrepareForCommit();
826 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
827 native_url
, ui::PAGE_TRANSITION_RELOAD
);
828 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
829 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
830 EXPECT_FALSE(orig_instance
->HasSite());
832 // Navigate to a regular site and verify that the SiteInstance was kept.
833 browser_client
.set_assign_site_for_url(true);
834 const GURL
url("http://www.google.com");
835 controller().LoadURL(
836 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
837 entry
= controller().GetPendingEntry();
838 orig_rfh
->PrepareForCommit();
839 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, url
,
840 ui::PAGE_TRANSITION_TYPED
);
841 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
847 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
848 // tab is restored, the SiteInstance will change upon navigation.
849 TEST_F(WebContentsImplTest
, NavigateFromRestoredRegularUrl
) {
850 WebContentsImplTestBrowserClient browser_client
;
851 SetBrowserClientForTesting(&browser_client
);
852 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
853 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
855 // Restore a navigation entry for a regular URL ensuring that the embedder
856 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
857 browser_client
.set_assign_site_for_url(true);
858 const GURL
regular_url("http://www.yahoo.com");
859 ScopedVector
<NavigationEntry
> entries
;
860 scoped_ptr
<NavigationEntry
> new_entry
=
861 NavigationControllerImpl::CreateNavigationEntry(
862 regular_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false,
863 std::string(), browser_context());
864 new_entry
->SetPageID(0);
865 entries
.push_back(new_entry
.Pass());
866 controller().Restore(
868 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
870 ASSERT_EQ(0u, entries
.size());
872 ASSERT_EQ(1, controller().GetEntryCount());
873 controller().GoToIndex(0);
874 NavigationEntry
* entry
= controller().GetPendingEntry();
875 orig_rfh
->PrepareForCommit();
876 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
877 regular_url
, ui::PAGE_TRANSITION_RELOAD
);
878 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
879 EXPECT_TRUE(orig_instance
->HasSite());
881 // Navigate to another site and verify that a new SiteInstance was created.
882 const GURL
url("http://www.google.com");
883 controller().LoadURL(
884 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
885 entry
= controller().GetPendingEntry();
886 orig_rfh
->PrepareForCommit();
887 contents()->TestDidNavigate(contents()->GetPendingMainFrame(), 2,
888 entry
->GetUniqueID(), true, url
,
889 ui::PAGE_TRANSITION_TYPED
);
890 EXPECT_NE(orig_instance
, contents()->GetSiteInstance());
896 // Test that we can find an opener RVH even if it's pending.
897 // http://crbug.com/176252.
898 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
899 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
901 // Navigate to a URL.
902 const GURL
url("http://www.google.com");
903 controller().LoadURL(
904 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
905 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
906 orig_rfh
->PrepareForCommit();
907 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
908 ui::PAGE_TRANSITION_TYPED
);
910 // Start to navigate first tab to a new site, so that it has a pending RVH.
911 const GURL
url2("http://www.yahoo.com");
912 controller().LoadURL(
913 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
914 orig_rfh
->PrepareForCommit();
915 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
916 SiteInstance
* instance
= pending_rfh
->GetSiteInstance();
918 // While it is still pending, simulate opening a new tab with the first tab
919 // as its opener. This will call CreateOpenerProxies on the opener to ensure
920 // that an RVH exists.
921 scoped_ptr
<TestWebContents
> popup(
922 TestWebContents::Create(browser_context(), instance
));
923 popup
->SetOpener(contents());
924 contents()->GetRenderManager()->CreateOpenerProxies(instance
);
926 // If swapped out is forbidden, a new proxy should be created for the opener
927 // in |instance|, and we should ensure that its routing ID is returned here.
928 // Otherwise, we should find the pending RFH and not create a new proxy.
929 int opener_frame_routing_id
=
930 popup
->GetRenderManager()->GetOpenerRoutingID(instance
);
931 RenderFrameProxyHost
* proxy
=
932 contents()->GetRenderManager()->GetRenderFrameProxyHost(instance
);
933 if (RenderFrameHostManager::IsSwappedOutStateForbidden()) {
935 EXPECT_EQ(proxy
->GetRoutingID(), opener_frame_routing_id
);
937 // Ensure that committing the navigation removes the proxy.
938 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
939 contents()->TestDidNavigate(pending_rfh
, 2, entry_id
, true, url2
,
940 ui::PAGE_TRANSITION_TYPED
);
942 contents()->GetRenderManager()->GetRenderFrameProxyHost(instance
));
945 EXPECT_EQ(pending_rfh
->GetRoutingID(), opener_frame_routing_id
);
949 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
950 // to determine whether a navigation is cross-site.
951 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
952 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
953 SiteInstance
* instance1
= contents()->GetSiteInstance();
956 const GURL
url("http://www.google.com");
957 controller().LoadURL(
958 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
959 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
960 contents()->GetMainFrame()->PrepareForCommit();
961 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
962 ui::PAGE_TRANSITION_TYPED
);
964 // Open a related contents to a second site.
965 scoped_ptr
<TestWebContents
> contents2(
966 TestWebContents::Create(browser_context(), instance1
));
967 const GURL
url2("http://www.yahoo.com");
968 contents2
->GetController().LoadURL(url2
, Referrer(),
969 ui::PAGE_TRANSITION_TYPED
,
971 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
972 contents2
->GetMainFrame()->PrepareForCommit();
974 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
976 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
977 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
978 contents2
->TestDidNavigate(rfh2
, 2, entry_id
, true, url2
,
979 ui::PAGE_TRANSITION_TYPED
);
980 SiteInstance
* instance2
= contents2
->GetSiteInstance();
981 EXPECT_NE(instance1
, instance2
);
982 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
984 // Simulate a link click in first contents to second site. Doesn't switch
985 // SiteInstances, because we don't intercept Blink navigations.
986 orig_rfh
->SendRendererInitiatedNavigationRequest(url2
, true);
987 orig_rfh
->PrepareForCommit();
988 contents()->TestDidNavigate(orig_rfh
, 2, 0, true, url2
,
989 ui::PAGE_TRANSITION_TYPED
);
990 SiteInstance
* instance3
= contents()->GetSiteInstance();
991 EXPECT_EQ(instance1
, instance3
);
992 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
994 // Navigate to the new site. Doesn't switch SiteInstancees, because we
995 // compare against the current URL, not the SiteInstance's site.
996 const GURL
url3("http://mail.yahoo.com");
997 controller().LoadURL(
998 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
999 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1000 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1001 contents()->GetMainFrame()->PrepareForCommit();
1002 contents()->TestDidNavigate(orig_rfh
, 3, entry_id
, true, url3
,
1003 ui::PAGE_TRANSITION_TYPED
);
1004 SiteInstance
* instance4
= contents()->GetSiteInstance();
1005 EXPECT_EQ(instance1
, instance4
);
1008 // Test that the onbeforeunload and onunload handlers run when navigating
1009 // across site boundaries.
1010 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
1011 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1012 SiteInstance
* instance1
= contents()->GetSiteInstance();
1014 // Navigate to URL. First URL should use first RenderViewHost.
1015 const GURL
url("http://www.google.com");
1016 controller().LoadURL(
1017 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1018 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1019 contents()->GetMainFrame()->PrepareForCommit();
1020 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1021 ui::PAGE_TRANSITION_TYPED
);
1022 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1023 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1025 // Navigate to new site, but simulate an onbeforeunload denial.
1026 const GURL
url2("http://www.yahoo.com");
1027 controller().LoadURL(
1028 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1029 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1030 base::TimeTicks now
= base::TimeTicks::Now();
1031 orig_rfh
->OnMessageReceived(
1032 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
1033 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1034 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1035 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1037 // Navigate again, but simulate an onbeforeunload approval.
1038 controller().LoadURL(
1039 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1040 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1041 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1042 now
= base::TimeTicks::Now();
1043 orig_rfh
->PrepareForCommit();
1044 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1045 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1046 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1048 // We won't hear DidNavigate until the onunload handler has finished running.
1050 // DidNavigate from the pending page.
1051 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1052 ui::PAGE_TRANSITION_TYPED
);
1053 SiteInstance
* instance2
= contents()->GetSiteInstance();
1054 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1055 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1056 EXPECT_NE(instance1
, instance2
);
1057 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1060 // Test that during a slow cross-site navigation, the original renderer can
1061 // navigate to a different URL and have it displayed, canceling the slow
1063 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
1064 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1065 SiteInstance
* instance1
= contents()->GetSiteInstance();
1067 // Navigate to URL. First URL should use first RenderFrameHost.
1068 const GURL
url("http://www.google.com");
1069 controller().LoadURL(
1070 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1071 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1072 contents()->GetMainFrame()->PrepareForCommit();
1073 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1074 ui::PAGE_TRANSITION_TYPED
);
1075 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1076 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1078 // Navigate to new site, simulating an onbeforeunload approval.
1079 const GURL
url2("http://www.yahoo.com");
1080 controller().LoadURL(
1081 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1082 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1083 orig_rfh
->PrepareForCommit();
1084 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1086 // Suppose the original renderer navigates before the new one is ready.
1087 orig_rfh
->SendNavigate(2, 0, true, GURL("http://www.google.com/foo"));
1089 // Verify that the pending navigation is cancelled.
1090 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1091 SiteInstance
* instance2
= contents()->GetSiteInstance();
1092 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1093 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1094 EXPECT_EQ(instance1
, instance2
);
1095 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1098 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1099 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1100 const GURL
url1("chrome://gpu");
1101 controller().LoadURL(
1102 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1103 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1104 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
1105 ntp_rfh
->PrepareForCommit();
1106 contents()->TestDidNavigate(ntp_rfh
, 1, entry_id
, true, url1
,
1107 ui::PAGE_TRANSITION_TYPED
);
1108 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1109 SiteInstance
* instance1
= contents()->GetSiteInstance();
1111 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1112 EXPECT_EQ(ntp_rfh
, contents()->GetMainFrame());
1113 EXPECT_EQ(url1
, entry1
->GetURL());
1114 EXPECT_EQ(instance1
,
1115 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1116 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1117 BINDINGS_POLICY_WEB_UI
);
1119 // Navigate to new site.
1120 const GURL
url2("http://www.google.com");
1121 controller().LoadURL(
1122 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1123 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1124 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1125 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1127 // Simulate beforeunload approval.
1128 EXPECT_TRUE(ntp_rfh
->is_waiting_for_beforeunload_ack());
1129 base::TimeTicks now
= base::TimeTicks::Now();
1130 ntp_rfh
->PrepareForCommit();
1132 // DidNavigate from the pending page.
1133 contents()->TestDidNavigate(google_rfh
, 1, entry_id
, true, url2
,
1134 ui::PAGE_TRANSITION_TYPED
);
1135 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1136 SiteInstance
* instance2
= contents()->GetSiteInstance();
1138 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1139 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1140 EXPECT_NE(instance1
, instance2
);
1141 EXPECT_FALSE(contents()->GetPendingMainFrame());
1142 EXPECT_EQ(url2
, entry2
->GetURL());
1143 EXPECT_EQ(instance2
,
1144 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1145 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1146 BINDINGS_POLICY_WEB_UI
);
1148 // Navigate to third page on same site.
1149 const GURL
url3("http://news.google.com");
1150 controller().LoadURL(
1151 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1152 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1153 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1154 contents()->GetMainFrame()->PrepareForCommit();
1155 contents()->TestDidNavigate(google_rfh
, 2, entry_id
, true, url3
,
1156 ui::PAGE_TRANSITION_TYPED
);
1157 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1158 SiteInstance
* instance3
= contents()->GetSiteInstance();
1160 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1161 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1162 EXPECT_EQ(instance2
, instance3
);
1163 EXPECT_FALSE(contents()->GetPendingMainFrame());
1164 EXPECT_EQ(url3
, entry3
->GetURL());
1165 EXPECT_EQ(instance3
,
1166 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1168 // Go back within the site.
1169 controller().GoBack();
1170 NavigationEntry
* goback_entry
= controller().GetPendingEntry();
1171 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1172 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1174 // Before that commits, go back again.
1175 controller().GoBack();
1176 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1177 EXPECT_TRUE(contents()->GetPendingMainFrame());
1178 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1180 // Simulate beforeunload approval.
1181 EXPECT_TRUE(google_rfh
->is_waiting_for_beforeunload_ack());
1182 now
= base::TimeTicks::Now();
1183 google_rfh
->PrepareForCommit();
1184 google_rfh
->OnMessageReceived(
1185 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1187 // DidNavigate from the first back. This aborts the second back's pending RFH.
1188 contents()->TestDidNavigate(google_rfh
, 1, goback_entry
->GetUniqueID(), false,
1189 url2
, ui::PAGE_TRANSITION_TYPED
);
1191 // We should commit this page and forget about the second back.
1192 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1193 EXPECT_FALSE(controller().GetPendingEntry());
1194 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1195 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1197 // We should not have corrupted the NTP entry.
1198 EXPECT_EQ(instance3
,
1199 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1200 EXPECT_EQ(instance2
,
1201 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1202 EXPECT_EQ(instance1
,
1203 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1204 EXPECT_EQ(url1
, entry1
->GetURL());
1207 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1208 // original renderer will not cancel the slow navigation (bug 42029).
1209 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1210 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1212 // Navigate to URL. First URL should use the original RenderFrameHost.
1213 const GURL
url("http://www.google.com");
1214 controller().LoadURL(
1215 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1216 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1217 contents()->GetMainFrame()->PrepareForCommit();
1218 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1219 ui::PAGE_TRANSITION_TYPED
);
1220 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1221 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1223 // Start navigating to new site.
1224 const GURL
url2("http://www.yahoo.com");
1225 controller().LoadURL(
1226 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1228 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1229 // waiting for a before unload response.
1230 TestRenderFrameHost
* child_rfh
= orig_rfh
->AppendChild("subframe");
1231 child_rfh
->SendNavigateWithTransition(1, 0, false,
1232 GURL("http://google.com/frame"),
1233 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
1234 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1236 // Now simulate the onbeforeunload approval and verify the navigation is
1238 orig_rfh
->PrepareForCommit();
1239 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1240 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1244 void SetAsNonUserGesture(FrameHostMsg_DidCommitProvisionalLoad_Params
* params
) {
1245 params
->gesture
= NavigationGestureAuto
;
1249 // Test that a cross-site navigation is not preempted if the previous
1250 // renderer sends a FrameNavigate message just before being told to stop.
1251 // We should only preempt the cross-site navigation if the previous renderer
1252 // has started a new navigation. See http://crbug.com/79176.
1253 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1254 // Navigate to WebUI URL.
1255 const GURL
url("chrome://gpu");
1256 controller().LoadURL(
1257 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1258 int entry1_id
= controller().GetPendingEntry()->GetUniqueID();
1259 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1260 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1262 // Navigate to new site, with the beforeunload request in flight.
1263 const GURL
url2("http://www.yahoo.com");
1264 controller().LoadURL(
1265 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1266 int entry2_id
= controller().GetPendingEntry()->GetUniqueID();
1267 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1268 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1269 EXPECT_TRUE(orig_rfh
->is_waiting_for_beforeunload_ack());
1270 EXPECT_NE(orig_rfh
, pending_rfh
);
1272 // Suppose the first navigation tries to commit now, with a
1273 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1274 // but it should act as if the beforeunload ack arrived.
1275 orig_rfh
->SendNavigateWithModificationCallback(
1276 1, entry1_id
, true, url
, base::Bind(SetAsNonUserGesture
));
1277 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1278 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1279 EXPECT_FALSE(orig_rfh
->is_waiting_for_beforeunload_ack());
1280 // It should commit.
1281 ASSERT_EQ(1, controller().GetEntryCount());
1282 EXPECT_EQ(url
, controller().GetLastCommittedEntry()->GetURL());
1284 // The pending navigation should be able to commit successfully.
1285 contents()->TestDidNavigate(pending_rfh
, 1, entry2_id
, true, url2
,
1286 ui::PAGE_TRANSITION_TYPED
);
1287 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1288 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1289 EXPECT_EQ(2, controller().GetEntryCount());
1292 // Test that NavigationEntries have the correct page state after going
1293 // forward and back. Prevents regression for bug 1116137.
1294 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1295 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1297 // Navigate to URL. There should be no committed entry yet.
1298 const GURL
url("http://www.google.com");
1299 controller().LoadURL(
1300 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1301 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1302 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1303 EXPECT_EQ(nullptr, entry
);
1305 // Committed entry should have page state after DidNavigate.
1306 orig_rfh
->PrepareForCommit();
1307 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1308 ui::PAGE_TRANSITION_TYPED
);
1309 entry
= controller().GetLastCommittedEntry();
1310 EXPECT_TRUE(entry
->GetPageState().IsValid());
1312 // Navigate to same site.
1313 const GURL
url2("http://images.google.com");
1314 controller().LoadURL(
1315 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1316 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1317 entry
= controller().GetLastCommittedEntry();
1318 EXPECT_TRUE(entry
->GetPageState().IsValid());
1320 // Committed entry should have page state after DidNavigate.
1321 orig_rfh
->PrepareForCommit();
1322 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1323 ui::PAGE_TRANSITION_TYPED
);
1324 entry
= controller().GetLastCommittedEntry();
1325 EXPECT_TRUE(entry
->GetPageState().IsValid());
1327 // Now go back. Committed entry should still have page state.
1328 controller().GoBack();
1329 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1330 orig_rfh
->PrepareForCommit();
1331 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, false, url
,
1332 ui::PAGE_TRANSITION_TYPED
);
1333 entry
= controller().GetLastCommittedEntry();
1334 EXPECT_TRUE(entry
->GetPageState().IsValid());
1337 // Test that NavigationEntries have the correct page state and SiteInstance
1338 // state after opening a new window to about:blank. Prevents regression for
1339 // bugs b/1116137 and http://crbug.com/111975.
1340 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1341 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1343 // Navigate to about:blank.
1344 const GURL
url(url::kAboutBlankURL
);
1345 orig_rfh
->SendRendererInitiatedNavigationRequest(url
, false);
1346 contents()->TestDidNavigate(orig_rfh
, 1, 0, true, url
,
1347 ui::PAGE_TRANSITION_TYPED
);
1349 // Should have a page state here.
1350 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1351 EXPECT_TRUE(entry
->GetPageState().IsValid());
1353 // The SiteInstance should be available for other navigations to use.
1354 NavigationEntryImpl
* entry_impl
=
1355 NavigationEntryImpl::FromNavigationEntry(entry
);
1356 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1357 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1359 // Navigating to a normal page should not cause a process swap.
1360 const GURL
new_url("http://www.google.com");
1361 controller().LoadURL(new_url
, Referrer(),
1362 ui::PAGE_TRANSITION_TYPED
, std::string());
1363 entry
= controller().GetPendingEntry();
1364 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1365 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1366 orig_rfh
->PrepareForCommit();
1367 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, new_url
,
1368 ui::PAGE_TRANSITION_TYPED
);
1369 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1370 controller().GetLastCommittedEntry());
1371 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1372 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1375 // Tests that fullscreen is exited throughout the object hierarchy when
1376 // navigating to a new page.
1377 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1378 FakeFullscreenDelegate fake_delegate
;
1379 contents()->SetDelegate(&fake_delegate
);
1380 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1381 TestRenderViewHost
* orig_rvh
= orig_rfh
->GetRenderViewHost();
1383 // Navigate to a site.
1384 const GURL
url("http://www.google.com");
1385 controller().LoadURL(
1386 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1387 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1388 contents()->GetMainFrame()->PrepareForCommit();
1389 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1390 ui::PAGE_TRANSITION_TYPED
);
1391 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1393 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1394 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1395 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1396 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1397 orig_rfh
->OnMessageReceived(
1398 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1399 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1400 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1401 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1403 // Navigate to a new site.
1404 const GURL
url2("http://www.yahoo.com");
1405 controller().LoadURL(
1406 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1407 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1408 contents()->GetMainFrame()->PrepareForCommit();
1409 TestRenderFrameHost
* const pending_rfh
= contents()->GetPendingMainFrame();
1410 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1411 ui::PAGE_TRANSITION_TYPED
);
1413 // Confirm fullscreen has exited.
1414 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1415 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1416 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1418 contents()->SetDelegate(nullptr);
1421 // Tests that fullscreen is exited throughout the object hierarchy when
1422 // instructing NavigationController to GoBack() or GoForward().
1423 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1424 FakeFullscreenDelegate fake_delegate
;
1425 contents()->SetDelegate(&fake_delegate
);
1426 TestRenderFrameHost
* const orig_rfh
= contents()->GetMainFrame();
1427 TestRenderViewHost
* const orig_rvh
= orig_rfh
->GetRenderViewHost();
1429 // Navigate to a site.
1430 const GURL
url("http://www.google.com");
1431 controller().LoadURL(
1432 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1433 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1434 orig_rfh
->PrepareForCommit();
1435 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1436 ui::PAGE_TRANSITION_TYPED
);
1437 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1439 // Now, navigate to another page on the same site.
1440 const GURL
url2("http://www.google.com/search?q=kittens");
1441 controller().LoadURL(
1442 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1443 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1444 orig_rfh
->PrepareForCommit();
1445 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1446 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1447 ui::PAGE_TRANSITION_TYPED
);
1448 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1450 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1451 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1452 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1453 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1455 for (int i
= 0; i
< 2; ++i
) {
1456 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1457 orig_rfh
->OnMessageReceived(
1458 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1459 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1460 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1461 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1463 // Navigate backward (or forward).
1465 controller().GoBack();
1467 controller().GoForward();
1468 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1469 orig_rfh
->PrepareForCommit();
1470 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1471 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1472 contents()->TestDidNavigate(orig_rfh
, i
+ 1, entry_id
, false, url
,
1473 ui::PAGE_TRANSITION_FORWARD_BACK
);
1475 // Confirm fullscreen has exited.
1476 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1477 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1478 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1481 contents()->SetDelegate(nullptr);
1484 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1485 FakeValidationMessageDelegate fake_delegate
;
1486 contents()->SetDelegate(&fake_delegate
);
1487 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1489 // Initialize the RenderFrame and then simulate crashing the renderer
1491 contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
1492 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1494 // Confirm HideValidationMessage was called.
1495 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1497 contents()->SetDelegate(nullptr);
1500 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1502 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1503 FakeFullscreenDelegate fake_delegate
;
1504 contents()->SetDelegate(&fake_delegate
);
1506 // Navigate to a site.
1507 const GURL
url("http://www.google.com");
1508 controller().LoadURL(
1509 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1510 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1511 main_test_rfh()->PrepareForCommit();
1512 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
1513 url
, ui::PAGE_TRANSITION_TYPED
);
1515 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1516 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1517 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1518 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1519 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1520 contents()->GetMainFrame()->GetRoutingID(), true));
1521 EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
1522 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1523 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1525 // Crash the renderer.
1526 main_test_rfh()->GetProcess()->SimulateCrash();
1528 // Confirm fullscreen has exited.
1529 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1530 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1531 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1533 contents()->SetDelegate(nullptr);
1536 ////////////////////////////////////////////////////////////////////////////////
1537 // Interstitial Tests
1538 ////////////////////////////////////////////////////////////////////////////////
1540 // Test navigating to a page (with the navigation initiated from the browser,
1541 // as when a URL is typed in the location bar) that shows an interstitial and
1542 // creates a new navigation entry, then hiding it without proceeding.
1543 TEST_F(WebContentsImplTest
,
1544 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1545 // Navigate to a page.
1546 GURL
url1("http://www.google.com");
1547 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1548 EXPECT_EQ(1, controller().GetEntryCount());
1550 // Initiate a browser navigation that will trigger the interstitial.
1551 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1552 ui::PAGE_TRANSITION_TYPED
, std::string());
1553 NavigationEntry
* entry
= controller().GetPendingEntry();
1555 // Show an interstitial.
1556 TestInterstitialPage::InterstitialState state
=
1557 TestInterstitialPage::INVALID
;
1558 bool deleted
= false;
1559 GURL
url2("http://interstitial");
1560 TestInterstitialPage
* interstitial
=
1561 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1562 TestInterstitialPageStateGuard
state_guard(interstitial
);
1563 interstitial
->Show();
1564 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1565 // The interstitial should not show until its navigation has committed.
1566 EXPECT_FALSE(interstitial
->is_showing());
1567 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1568 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1569 // Let's commit the interstitial navigation.
1570 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1571 EXPECT_TRUE(interstitial
->is_showing());
1572 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1573 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1574 entry
= controller().GetVisibleEntry();
1575 ASSERT_NE(nullptr, entry
);
1576 EXPECT_TRUE(entry
->GetURL() == url2
);
1578 // Now don't proceed.
1579 interstitial
->DontProceed();
1580 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1581 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1582 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1583 entry
= controller().GetVisibleEntry();
1584 ASSERT_NE(nullptr, entry
);
1585 EXPECT_TRUE(entry
->GetURL() == url1
);
1586 EXPECT_EQ(1, controller().GetEntryCount());
1588 RunAllPendingInMessageLoop();
1589 EXPECT_TRUE(deleted
);
1592 // Test navigating to a page (with the navigation initiated from the renderer,
1593 // as when clicking on a link in the page) that shows an interstitial and
1594 // creates a new navigation entry, then hiding it without proceeding.
1595 TEST_F(WebContentsImplTest
,
1596 ShowInterstitialFromRendererWithNewNavigationDontProceed
) {
1597 // Navigate to a page.
1598 GURL
url1("http://www.google.com");
1599 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1600 EXPECT_EQ(1, controller().GetEntryCount());
1602 // Show an interstitial (no pending entry, the interstitial would have been
1603 // triggered by clicking on a link).
1604 TestInterstitialPage::InterstitialState state
=
1605 TestInterstitialPage::INVALID
;
1606 bool deleted
= false;
1607 GURL
url2("http://interstitial");
1608 TestInterstitialPage
* interstitial
=
1609 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1610 TestInterstitialPageStateGuard
state_guard(interstitial
);
1611 interstitial
->Show();
1612 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1613 // The interstitial should not show until its navigation has committed.
1614 EXPECT_FALSE(interstitial
->is_showing());
1615 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1616 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1617 // Let's commit the interstitial navigation.
1618 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1619 EXPECT_TRUE(interstitial
->is_showing());
1620 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1621 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1622 NavigationEntry
* entry
= controller().GetVisibleEntry();
1623 ASSERT_NE(nullptr, entry
);
1624 EXPECT_TRUE(entry
->GetURL() == url2
);
1626 // Now don't proceed.
1627 interstitial
->DontProceed();
1628 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1629 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1630 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1631 entry
= controller().GetVisibleEntry();
1632 ASSERT_NE(nullptr, entry
);
1633 EXPECT_TRUE(entry
->GetURL() == url1
);
1634 EXPECT_EQ(1, controller().GetEntryCount());
1636 RunAllPendingInMessageLoop();
1637 EXPECT_TRUE(deleted
);
1640 // Test navigating to a page that shows an interstitial without creating a new
1641 // navigation entry (this happens when the interstitial is triggered by a
1642 // sub-resource in the page), then hiding it without proceeding.
1643 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1644 // Navigate to a page.
1645 GURL
url1("http://www.google.com");
1646 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1647 EXPECT_EQ(1, controller().GetEntryCount());
1649 // Show an interstitial.
1650 TestInterstitialPage::InterstitialState state
=
1651 TestInterstitialPage::INVALID
;
1652 bool deleted
= false;
1653 GURL
url2("http://interstitial");
1654 TestInterstitialPage
* interstitial
=
1655 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1656 TestInterstitialPageStateGuard
state_guard(interstitial
);
1657 interstitial
->Show();
1658 // The interstitial should not show until its navigation has committed.
1659 EXPECT_FALSE(interstitial
->is_showing());
1660 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1661 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1662 // Let's commit the interstitial navigation.
1663 interstitial
->TestDidNavigate(1, 0, true, url2
);
1664 EXPECT_TRUE(interstitial
->is_showing());
1665 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1666 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1667 NavigationEntry
* entry
= controller().GetVisibleEntry();
1668 ASSERT_NE(nullptr, entry
);
1669 // The URL specified to the interstitial should have been ignored.
1670 EXPECT_TRUE(entry
->GetURL() == url1
);
1672 // Now don't proceed.
1673 interstitial
->DontProceed();
1674 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1675 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1676 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1677 entry
= controller().GetVisibleEntry();
1678 ASSERT_NE(nullptr, entry
);
1679 EXPECT_TRUE(entry
->GetURL() == url1
);
1680 EXPECT_EQ(1, controller().GetEntryCount());
1682 RunAllPendingInMessageLoop();
1683 EXPECT_TRUE(deleted
);
1686 // Test navigating to a page (with the navigation initiated from the browser,
1687 // as when a URL is typed in the location bar) that shows an interstitial and
1688 // creates a new navigation entry, then proceeding.
1689 TEST_F(WebContentsImplTest
,
1690 ShowInterstitialFromBrowserNewNavigationProceed
) {
1691 // Navigate to a page.
1692 GURL
url1("http://www.google.com");
1693 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1694 EXPECT_EQ(1, controller().GetEntryCount());
1696 // Initiate a browser navigation that will trigger the interstitial
1697 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1698 ui::PAGE_TRANSITION_TYPED
, std::string());
1700 // Show an interstitial.
1701 TestInterstitialPage::InterstitialState state
=
1702 TestInterstitialPage::INVALID
;
1703 bool deleted
= false;
1704 GURL
url2("http://interstitial");
1705 TestInterstitialPage
* interstitial
=
1706 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1707 TestInterstitialPageStateGuard
state_guard(interstitial
);
1708 interstitial
->Show();
1709 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1710 // The interstitial should not show until its navigation has committed.
1711 EXPECT_FALSE(interstitial
->is_showing());
1712 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1713 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1714 // Let's commit the interstitial navigation.
1715 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1716 EXPECT_TRUE(interstitial
->is_showing());
1717 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1718 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1719 NavigationEntry
* entry
= controller().GetVisibleEntry();
1720 ASSERT_NE(nullptr, entry
);
1721 EXPECT_TRUE(entry
->GetURL() == url2
);
1724 interstitial
->Proceed();
1725 // The interstitial should show until the new navigation commits.
1726 RunAllPendingInMessageLoop();
1727 ASSERT_FALSE(deleted
);
1728 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1729 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1730 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1732 // Simulate the navigation to the page, that's when the interstitial gets
1734 GURL
url3("http://www.thepage.com");
1735 contents()->GetMainFrame()->PrepareForCommit();
1736 contents()->GetMainFrame()->SendNavigate(2, 0, true, url3
);
1738 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1739 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1740 entry
= controller().GetVisibleEntry();
1741 ASSERT_NE(nullptr, entry
);
1742 EXPECT_TRUE(entry
->GetURL() == url3
);
1744 EXPECT_EQ(2, controller().GetEntryCount());
1746 RunAllPendingInMessageLoop();
1747 EXPECT_TRUE(deleted
);
1750 // Test navigating to a page (with the navigation initiated from the renderer,
1751 // as when clicking on a link in the page) that shows an interstitial and
1752 // creates a new navigation entry, then proceeding.
1753 TEST_F(WebContentsImplTest
,
1754 ShowInterstitialFromRendererNewNavigationProceed
) {
1755 // Navigate to a page.
1756 GURL
url1("http://www.google.com");
1757 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1758 EXPECT_EQ(1, controller().GetEntryCount());
1760 // Show an interstitial.
1761 TestInterstitialPage::InterstitialState state
=
1762 TestInterstitialPage::INVALID
;
1763 bool deleted
= false;
1764 GURL
url2("http://interstitial");
1765 TestInterstitialPage
* interstitial
=
1766 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1767 TestInterstitialPageStateGuard
state_guard(interstitial
);
1768 interstitial
->Show();
1769 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1770 // The interstitial should not show until its navigation has committed.
1771 EXPECT_FALSE(interstitial
->is_showing());
1772 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1773 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1774 // Let's commit the interstitial navigation.
1775 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1776 EXPECT_TRUE(interstitial
->is_showing());
1777 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1778 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1779 NavigationEntry
* entry
= controller().GetVisibleEntry();
1780 ASSERT_NE(nullptr, entry
);
1781 EXPECT_TRUE(entry
->GetURL() == url2
);
1784 interstitial
->Proceed();
1785 // The interstitial should show until the new navigation commits.
1786 RunAllPendingInMessageLoop();
1787 ASSERT_FALSE(deleted
);
1788 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1789 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1790 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1792 // Simulate the navigation to the page, that's when the interstitial gets
1794 GURL
url3("http://www.thepage.com");
1795 main_test_rfh()->NavigateAndCommitRendererInitiated(2, true, url3
);
1797 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1798 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1799 entry
= controller().GetVisibleEntry();
1800 ASSERT_NE(nullptr, entry
);
1801 EXPECT_TRUE(entry
->GetURL() == url3
);
1803 EXPECT_EQ(2, controller().GetEntryCount());
1805 RunAllPendingInMessageLoop();
1806 EXPECT_TRUE(deleted
);
1809 // Test navigating to a page that shows an interstitial without creating a new
1810 // navigation entry (this happens when the interstitial is triggered by a
1811 // sub-resource in the page), then proceeding.
1812 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1813 // Navigate to a page so we have a navigation entry in the controller.
1814 GURL
url1("http://www.google.com");
1815 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1816 EXPECT_EQ(1, controller().GetEntryCount());
1818 // Show an interstitial.
1819 TestInterstitialPage::InterstitialState state
=
1820 TestInterstitialPage::INVALID
;
1821 bool deleted
= false;
1822 GURL
url2("http://interstitial");
1823 TestInterstitialPage
* interstitial
=
1824 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1825 TestInterstitialPageStateGuard
state_guard(interstitial
);
1826 interstitial
->Show();
1827 // The interstitial should not show until its navigation has committed.
1828 EXPECT_FALSE(interstitial
->is_showing());
1829 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1830 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1831 // Let's commit the interstitial navigation.
1832 interstitial
->TestDidNavigate(1, 0, true, url2
);
1833 EXPECT_TRUE(interstitial
->is_showing());
1834 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1835 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1836 NavigationEntry
* entry
= controller().GetVisibleEntry();
1837 ASSERT_NE(nullptr, entry
);
1838 // The URL specified to the interstitial should have been ignored.
1839 EXPECT_TRUE(entry
->GetURL() == url1
);
1842 interstitial
->Proceed();
1843 // Since this is not a new navigation, the previous page is dismissed right
1844 // away and shows the original page.
1845 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1846 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1847 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1848 entry
= controller().GetVisibleEntry();
1849 ASSERT_NE(nullptr, entry
);
1850 EXPECT_TRUE(entry
->GetURL() == url1
);
1852 EXPECT_EQ(1, controller().GetEntryCount());
1854 RunAllPendingInMessageLoop();
1855 EXPECT_TRUE(deleted
);
1858 // Test navigating to a page that shows an interstitial, then navigating away.
1859 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1860 // Show interstitial.
1861 TestInterstitialPage::InterstitialState state
=
1862 TestInterstitialPage::INVALID
;
1863 bool deleted
= false;
1864 GURL
url("http://interstitial");
1865 TestInterstitialPage
* interstitial
=
1866 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1867 TestInterstitialPageStateGuard
state_guard(interstitial
);
1868 interstitial
->Show();
1869 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1870 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
1872 // While interstitial showing, navigate to a new URL.
1873 const GURL
url2("http://www.yahoo.com");
1874 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2
);
1876 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1878 RunAllPendingInMessageLoop();
1879 EXPECT_TRUE(deleted
);
1882 // Test navigating to a page that shows an interstitial, then going back.
1883 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1884 // Navigate to a page so we have a navigation entry in the controller.
1885 GURL
url1("http://www.google.com");
1886 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1887 EXPECT_EQ(1, controller().GetEntryCount());
1889 // Show interstitial.
1890 TestInterstitialPage::InterstitialState state
=
1891 TestInterstitialPage::INVALID
;
1892 bool deleted
= false;
1893 GURL
interstitial_url("http://interstitial");
1894 TestInterstitialPage
* interstitial
=
1895 new TestInterstitialPage(contents(), true, interstitial_url
,
1897 TestInterstitialPageStateGuard
state_guard(interstitial
);
1898 interstitial
->Show();
1899 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1900 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1902 EXPECT_EQ(2, controller().GetEntryCount());
1904 // While the interstitial is showing, go back. This will dismiss the
1905 // interstitial and not initiate a navigation, but just show the existing
1907 controller().GoBack();
1909 // Make sure we are back to the original page and that the interstitial is
1911 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1912 NavigationEntry
* entry
= controller().GetVisibleEntry();
1914 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1915 EXPECT_EQ(1, controller().GetEntryCount());
1917 RunAllPendingInMessageLoop();
1918 EXPECT_TRUE(deleted
);
1921 // Test navigating to a page that shows an interstitial, has a renderer crash,
1922 // and then goes back.
1923 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1924 // Navigate to a page so we have a navigation entry in the controller.
1925 GURL
url1("http://www.google.com");
1926 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1927 EXPECT_EQ(1, controller().GetEntryCount());
1928 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1930 // Show interstitial.
1931 TestInterstitialPage::InterstitialState state
=
1932 TestInterstitialPage::INVALID
;
1933 bool deleted
= false;
1934 GURL
interstitial_url("http://interstitial");
1935 TestInterstitialPage
* interstitial
=
1936 new TestInterstitialPage(contents(), true, interstitial_url
,
1938 TestInterstitialPageStateGuard
state_guard(interstitial
);
1939 interstitial
->Show();
1940 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1941 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1944 // Crash the renderer
1945 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1947 // While the interstitial is showing, go back. This will dismiss the
1948 // interstitial and not initiate a navigation, but just show the existing
1950 controller().GoBack();
1952 // Make sure we are back to the original page and that the interstitial is
1954 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1955 entry
= controller().GetVisibleEntry();
1957 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1959 RunAllPendingInMessageLoop();
1960 EXPECT_TRUE(deleted
);
1963 // Test navigating to a page that shows an interstitial, has the renderer crash,
1964 // and then navigates to the interstitial.
1965 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1966 // Navigate to a page so we have a navigation entry in the controller.
1967 GURL
url1("http://www.google.com");
1968 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1969 EXPECT_EQ(1, controller().GetEntryCount());
1971 // Show interstitial.
1972 TestInterstitialPage::InterstitialState state
=
1973 TestInterstitialPage::INVALID
;
1974 bool deleted
= false;
1975 GURL
interstitial_url("http://interstitial");
1976 TestInterstitialPage
* interstitial
=
1977 new TestInterstitialPage(contents(), true, interstitial_url
,
1979 TestInterstitialPageStateGuard
state_guard(interstitial
);
1980 interstitial
->Show();
1981 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1983 // Crash the renderer
1984 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1986 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1990 // Test navigating to a page that shows an interstitial, then close the
1992 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1993 // Show interstitial.
1994 TestInterstitialPage::InterstitialState state
=
1995 TestInterstitialPage::INVALID
;
1996 bool deleted
= false;
1997 GURL
url("http://interstitial");
1998 TestInterstitialPage
* interstitial
=
1999 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2000 TestInterstitialPageStateGuard
state_guard(interstitial
);
2001 interstitial
->Show();
2002 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2003 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2005 // Now close the contents.
2007 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2009 RunAllPendingInMessageLoop();
2010 EXPECT_TRUE(deleted
);
2013 // Test navigating to a page that shows an interstitial, then close the
2015 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
2016 // Show interstitial.
2017 TestInterstitialPage::InterstitialState state
=
2018 TestInterstitialPage::INVALID
;
2019 bool deleted
= false;
2020 GURL
url("http://interstitial");
2021 TestInterstitialPage
* interstitial
=
2022 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2023 TestInterstitialPageStateGuard
state_guard(interstitial
);
2024 interstitial
->Show();
2025 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2026 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2027 TestRenderFrameHost
* rfh
=
2028 static_cast<TestRenderFrameHost
*>(interstitial
->GetMainFrame());
2030 // Now close the contents.
2032 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2034 // Before the interstitial has a chance to process its shutdown task,
2035 // simulate quitting the browser. This goes through all processes and
2036 // tells them to destruct.
2037 rfh
->GetProcess()->SimulateCrash();
2039 RunAllPendingInMessageLoop();
2040 EXPECT_TRUE(deleted
);
2043 // Test that after Proceed is called and an interstitial is still shown, no more
2044 // commands get executed.
2045 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
2046 // Navigate to a page so we have a navigation entry in the controller.
2047 GURL
url1("http://www.google.com");
2048 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2049 EXPECT_EQ(1, controller().GetEntryCount());
2051 // Show an interstitial.
2052 TestInterstitialPage::InterstitialState state
=
2053 TestInterstitialPage::INVALID
;
2054 bool deleted
= false;
2055 GURL
url2("http://interstitial");
2056 TestInterstitialPage
* interstitial
=
2057 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2058 TestInterstitialPageStateGuard
state_guard(interstitial
);
2059 interstitial
->Show();
2060 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2061 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2064 EXPECT_EQ(0, interstitial
->command_received_count());
2065 interstitial
->TestDomOperationResponse("toto");
2066 EXPECT_EQ(1, interstitial
->command_received_count());
2069 interstitial
->Proceed();
2070 RunAllPendingInMessageLoop();
2071 ASSERT_FALSE(deleted
);
2073 // While the navigation to the new page is pending, send other commands, they
2074 // should be ignored.
2075 interstitial
->TestDomOperationResponse("hello");
2076 interstitial
->TestDomOperationResponse("hi");
2077 EXPECT_EQ(1, interstitial
->command_received_count());
2080 // Test showing an interstitial while another interstitial is already showing.
2081 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
2082 // Navigate to a page so we have a navigation entry in the controller.
2083 GURL
start_url("http://www.google.com");
2084 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2085 EXPECT_EQ(1, controller().GetEntryCount());
2087 // Show an interstitial.
2088 TestInterstitialPage::InterstitialState state1
=
2089 TestInterstitialPage::INVALID
;
2090 bool deleted1
= false;
2091 GURL
url1("http://interstitial1");
2092 TestInterstitialPage
* interstitial1
=
2093 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2094 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2095 interstitial1
->Show();
2096 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2097 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2099 // Now show another interstitial.
2100 TestInterstitialPage::InterstitialState state2
=
2101 TestInterstitialPage::INVALID
;
2102 bool deleted2
= false;
2103 GURL
url2("http://interstitial2");
2104 TestInterstitialPage
* interstitial2
=
2105 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2106 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2107 interstitial2
->Show();
2108 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2109 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2111 // Showing interstitial2 should have caused interstitial1 to go away.
2112 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2113 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2115 RunAllPendingInMessageLoop();
2116 EXPECT_TRUE(deleted1
);
2117 ASSERT_FALSE(deleted2
);
2119 // Let's make sure interstitial2 is working as intended.
2120 interstitial2
->Proceed();
2121 GURL
landing_url("http://www.thepage.com");
2122 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2124 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2125 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2126 NavigationEntry
* entry
= controller().GetVisibleEntry();
2127 ASSERT_NE(nullptr, entry
);
2128 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2129 EXPECT_EQ(2, controller().GetEntryCount());
2130 RunAllPendingInMessageLoop();
2131 EXPECT_TRUE(deleted2
);
2134 // Test showing an interstitial, proceeding and then navigating to another
2136 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2137 // Navigate to a page so we have a navigation entry in the controller.
2138 GURL
start_url("http://www.google.com");
2139 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2140 EXPECT_EQ(1, controller().GetEntryCount());
2142 // Show an interstitial.
2143 TestInterstitialPage::InterstitialState state1
=
2144 TestInterstitialPage::INVALID
;
2145 bool deleted1
= false;
2146 GURL
url1("http://interstitial1");
2147 TestInterstitialPage
* interstitial1
=
2148 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2149 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2150 interstitial1
->Show();
2151 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2152 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2154 // Take action. The interstitial won't be hidden until the navigation is
2156 interstitial1
->Proceed();
2157 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2159 // Now show another interstitial (simulating the navigation causing another
2161 TestInterstitialPage::InterstitialState state2
=
2162 TestInterstitialPage::INVALID
;
2163 bool deleted2
= false;
2164 GURL
url2("http://interstitial2");
2165 TestInterstitialPage
* interstitial2
=
2166 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2167 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2168 interstitial2
->Show();
2169 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2170 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2172 // Showing interstitial2 should have caused interstitial1 to go away.
2173 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2174 RunAllPendingInMessageLoop();
2175 EXPECT_TRUE(deleted1
);
2176 ASSERT_FALSE(deleted2
);
2178 // Let's make sure interstitial2 is working as intended.
2179 interstitial2
->Proceed();
2180 GURL
landing_url("http://www.thepage.com");
2181 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2183 RunAllPendingInMessageLoop();
2184 EXPECT_TRUE(deleted2
);
2185 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2186 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2187 NavigationEntry
* entry
= controller().GetVisibleEntry();
2188 ASSERT_NE(nullptr, entry
);
2189 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2190 EXPECT_EQ(2, controller().GetEntryCount());
2193 // Test that navigating away from an interstitial while it's loading cause it
2195 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2196 // Show an interstitial.
2197 TestInterstitialPage::InterstitialState state
=
2198 TestInterstitialPage::INVALID
;
2199 bool deleted
= false;
2200 GURL
interstitial_url("http://interstitial");
2201 TestInterstitialPage
* interstitial
=
2202 new TestInterstitialPage(contents(), true, interstitial_url
,
2204 TestInterstitialPageStateGuard
state_guard(interstitial
);
2205 interstitial
->Show();
2206 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2208 // Let's simulate a navigation initiated from the browser before the
2209 // interstitial finishes loading.
2210 const GURL
url("http://www.google.com");
2211 controller().LoadURL(
2212 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2213 EXPECT_FALSE(interstitial
->is_showing());
2214 RunAllPendingInMessageLoop();
2215 ASSERT_FALSE(deleted
);
2217 // Now let's make the interstitial navigation commit.
2218 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true,
2221 // After it loaded the interstitial should be gone.
2222 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2224 RunAllPendingInMessageLoop();
2225 EXPECT_TRUE(deleted
);
2228 // Test that a new request to show an interstitial while an interstitial is
2229 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2230 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2231 GURL
interstitial_url("http://interstitial");
2233 // Show a first interstitial.
2234 TestInterstitialPage::InterstitialState state1
=
2235 TestInterstitialPage::INVALID
;
2236 bool deleted1
= false;
2237 TestInterstitialPage
* interstitial1
=
2238 new TestInterstitialPage(contents(), true, interstitial_url
,
2239 &state1
, &deleted1
);
2240 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2241 interstitial1
->Show();
2243 // Show another interstitial on that same contents before the first one had
2245 TestInterstitialPage::InterstitialState state2
=
2246 TestInterstitialPage::INVALID
;
2247 bool deleted2
= false;
2248 TestInterstitialPage
* interstitial2
=
2249 new TestInterstitialPage(contents(), true, interstitial_url
,
2250 &state2
, &deleted2
);
2251 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2252 interstitial2
->Show();
2253 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2255 // The first interstitial should have been closed and deleted.
2256 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2257 // The 2nd one should still be OK.
2258 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2260 RunAllPendingInMessageLoop();
2261 EXPECT_TRUE(deleted1
);
2262 ASSERT_FALSE(deleted2
);
2264 // Make the interstitial navigation commit it should be showing.
2265 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true,
2267 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2270 // Test showing an interstitial and have its renderer crash.
2271 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2272 // Show an interstitial.
2273 TestInterstitialPage::InterstitialState state
=
2274 TestInterstitialPage::INVALID
;
2275 bool deleted
= false;
2276 GURL
url("http://interstitial");
2277 TestInterstitialPage
* interstitial
=
2278 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2279 TestInterstitialPageStateGuard
state_guard(interstitial
);
2280 interstitial
->Show();
2281 // Simulate a renderer crash before the interstitial is shown.
2282 interstitial
->TestRenderViewTerminated(
2283 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2284 // The interstitial should have been dismissed.
2285 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2286 RunAllPendingInMessageLoop();
2287 EXPECT_TRUE(deleted
);
2289 // Now try again but this time crash the intersitial after it was shown.
2291 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2292 interstitial
->Show();
2293 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2294 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2295 // Simulate a renderer crash.
2296 interstitial
->TestRenderViewTerminated(
2297 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2298 // The interstitial should have been dismissed.
2299 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2300 RunAllPendingInMessageLoop();
2301 EXPECT_TRUE(deleted
);
2304 // Tests that showing an interstitial as a result of a browser initiated
2305 // navigation while an interstitial is showing does not remove the pending
2306 // entry (see http://crbug.com/9791).
2307 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2308 const char kUrl
[] = "http://www.badguys.com/";
2309 const GURL
kGURL(kUrl
);
2311 // Start a navigation to a page
2312 contents()->GetController().LoadURL(
2313 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2315 // Simulate that navigation triggering an interstitial.
2316 TestInterstitialPage::InterstitialState state
=
2317 TestInterstitialPage::INVALID
;
2318 bool deleted
= false;
2319 TestInterstitialPage
* interstitial
=
2320 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2321 TestInterstitialPageStateGuard
state_guard(interstitial
);
2322 interstitial
->Show();
2323 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2324 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2326 // Initiate a new navigation from the browser that also triggers an
2328 contents()->GetController().LoadURL(
2329 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2330 TestInterstitialPage::InterstitialState state2
=
2331 TestInterstitialPage::INVALID
;
2332 bool deleted2
= false;
2333 TestInterstitialPage
* interstitial2
=
2334 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2335 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2336 interstitial2
->Show();
2337 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2338 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2340 // Make sure we still have an entry.
2341 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2343 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2345 // And that the first interstitial is gone, but not the second.
2346 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2347 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2348 RunAllPendingInMessageLoop();
2349 EXPECT_TRUE(deleted
);
2350 EXPECT_FALSE(deleted2
);
2353 // Tests that Javascript messages are not shown while an interstitial is
2355 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2356 const char kUrl
[] = "http://www.badguys.com/";
2357 const GURL
kGURL(kUrl
);
2359 // Start a navigation to a page
2360 contents()->GetController().LoadURL(
2361 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2362 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2363 main_test_rfh()->PrepareForCommit();
2364 // DidNavigate from the page
2365 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
2366 kGURL
, ui::PAGE_TRANSITION_TYPED
);
2368 // Simulate showing an interstitial while the page is showing.
2369 TestInterstitialPage::InterstitialState state
=
2370 TestInterstitialPage::INVALID
;
2371 bool deleted
= false;
2372 TestInterstitialPage
* interstitial
=
2373 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2374 TestInterstitialPageStateGuard
state_guard(interstitial
);
2375 interstitial
->Show();
2376 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2377 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2379 // While the interstitial is showing, let's simulate the hidden page
2380 // attempting to show a JS message.
2381 IPC::Message
* dummy_message
= new IPC::Message
;
2382 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2383 base::ASCIIToUTF16("This is an informative message"),
2384 base::ASCIIToUTF16("OK"),
2385 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2386 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2389 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2390 // interstitial it isn't copied over to the destination.
2391 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2392 // Navigate to a page.
2393 GURL
url1("http://www.google.com");
2394 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2395 EXPECT_EQ(1, controller().GetEntryCount());
2397 // Initiate a browser navigation that will trigger the interstitial
2398 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2399 ui::PAGE_TRANSITION_TYPED
, std::string());
2401 // Show an interstitial.
2402 TestInterstitialPage::InterstitialState state
=
2403 TestInterstitialPage::INVALID
;
2404 bool deleted
= false;
2405 GURL
url2("http://interstitial");
2406 TestInterstitialPage
* interstitial
=
2407 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2408 TestInterstitialPageStateGuard
state_guard(interstitial
);
2409 interstitial
->Show();
2410 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2411 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2412 EXPECT_TRUE(interstitial
->is_showing());
2413 EXPECT_EQ(2, controller().GetEntryCount());
2415 // Create another NavigationController.
2416 GURL
url3("http://foo2");
2417 scoped_ptr
<TestWebContents
> other_contents(
2418 static_cast<TestWebContents
*>(CreateTestWebContents()));
2419 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2420 other_contents
->NavigateAndCommit(url3
);
2421 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
2422 other_controller
.CopyStateFromAndPrune(&controller(), false);
2424 // The merged controller should only have two entries: url1 and url2.
2425 ASSERT_EQ(2, other_controller
.GetEntryCount());
2426 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2427 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2428 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2430 // And the merged controller shouldn't be showing an interstitial.
2431 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2434 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2435 // showing an interstitial.
2436 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2437 // Navigate to a page.
2438 GURL
url1("http://www.google.com");
2439 contents()->NavigateAndCommit(url1
);
2441 // Create another NavigationController.
2442 scoped_ptr
<TestWebContents
> other_contents(
2443 static_cast<TestWebContents
*>(CreateTestWebContents()));
2444 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2446 // Navigate it to url2.
2447 GURL
url2("http://foo2");
2448 other_contents
->NavigateAndCommit(url2
);
2450 // Show an interstitial.
2451 TestInterstitialPage::InterstitialState state
=
2452 TestInterstitialPage::INVALID
;
2453 bool deleted
= false;
2454 GURL
url3("http://interstitial");
2455 TestInterstitialPage
* interstitial
=
2456 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2458 TestInterstitialPageStateGuard
state_guard(interstitial
);
2459 interstitial
->Show();
2460 int interstitial_entry_id
=
2461 other_controller
.GetTransientEntry()->GetUniqueID();
2462 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url3
);
2463 EXPECT_TRUE(interstitial
->is_showing());
2464 EXPECT_EQ(2, other_controller
.GetEntryCount());
2466 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2467 // interstitial is showing in the target.
2468 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2471 // Regression test for http://crbug.com/168611 - the URLs passed by the
2472 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2473 TEST_F(WebContentsImplTest
, FilterURLs
) {
2474 TestWebContentsObserver
observer(contents());
2476 // A navigation to about:whatever should always look like a navigation to
2478 GURL
url_normalized(url::kAboutBlankURL
);
2479 GURL
url_from_ipc("about:whatever");
2481 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2482 // will use the given URL to create the NavigationEntry as well, and that
2483 // entry should contain the filtered URL.
2484 contents()->NavigateAndCommit(url_normalized
);
2486 // Check that an IPC with about:whatever is correctly normalized.
2487 contents()->TestDidFinishLoad(url_from_ipc
);
2489 EXPECT_EQ(url_normalized
, observer
.last_url());
2491 // Create and navigate another WebContents.
2492 scoped_ptr
<TestWebContents
> other_contents(
2493 static_cast<TestWebContents
*>(CreateTestWebContents()));
2494 TestWebContentsObserver
other_observer(other_contents
.get());
2495 other_contents
->NavigateAndCommit(url_normalized
);
2497 // Check that an IPC with about:whatever is correctly normalized.
2498 other_contents
->TestDidFailLoadWithError(
2499 url_from_ipc
, 1, base::string16(), false);
2500 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2503 // Test that if a pending contents is deleted before it is shown, we don't
2505 TEST_F(WebContentsImplTest
, PendingContents
) {
2506 scoped_ptr
<TestWebContents
> other_contents(
2507 static_cast<TestWebContents
*>(CreateTestWebContents()));
2508 contents()->AddPendingContents(other_contents
.get());
2509 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2510 other_contents
.reset();
2511 EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id
));
2514 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2515 const gfx::Size
original_preferred_size(1024, 768);
2516 contents()->UpdatePreferredSize(original_preferred_size
);
2518 // With no capturers, expect the preferred size to be the one propagated into
2519 // WebContentsImpl via the RenderViewHostDelegate interface.
2520 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2521 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2523 // Increment capturer count, but without specifying a capture size. Expect
2524 // a "not set" preferred size.
2525 contents()->IncrementCapturerCount(gfx::Size());
2526 EXPECT_EQ(1, contents()->GetCapturerCount());
2527 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2529 // Increment capturer count again, but with an overriding capture size.
2530 // Expect preferred size to now be overridden to the capture size.
2531 const gfx::Size
capture_size(1280, 720);
2532 contents()->IncrementCapturerCount(capture_size
);
2533 EXPECT_EQ(2, contents()->GetCapturerCount());
2534 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2536 // Increment capturer count a third time, but the expect that the preferred
2537 // size is still the first capture size.
2538 const gfx::Size
another_capture_size(720, 480);
2539 contents()->IncrementCapturerCount(another_capture_size
);
2540 EXPECT_EQ(3, contents()->GetCapturerCount());
2541 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2543 // Decrement capturer count twice, but expect the preferred size to still be
2545 contents()->DecrementCapturerCount();
2546 contents()->DecrementCapturerCount();
2547 EXPECT_EQ(1, contents()->GetCapturerCount());
2548 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2550 // Decrement capturer count, and since the count has dropped to zero, the
2551 // original preferred size should be restored.
2552 contents()->DecrementCapturerCount();
2553 EXPECT_EQ(0, contents()->GetCapturerCount());
2554 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2557 TEST_F(WebContentsImplTest
, CapturerPreventsHiding
) {
2558 const gfx::Size
original_preferred_size(1024, 768);
2559 contents()->UpdatePreferredSize(original_preferred_size
);
2561 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2562 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2564 // With no capturers, setting and un-setting occlusion should change the
2565 // view's occlusion state.
2566 EXPECT_FALSE(view
->is_showing());
2567 contents()->WasShown();
2568 EXPECT_TRUE(view
->is_showing());
2569 contents()->WasHidden();
2570 EXPECT_FALSE(view
->is_showing());
2571 contents()->WasShown();
2572 EXPECT_TRUE(view
->is_showing());
2574 // Add a capturer and try to hide the contents. The view will remain visible.
2575 contents()->IncrementCapturerCount(gfx::Size());
2576 contents()->WasHidden();
2577 EXPECT_TRUE(view
->is_showing());
2579 // Remove the capturer, and the WasHidden should take effect.
2580 contents()->DecrementCapturerCount();
2581 EXPECT_FALSE(view
->is_showing());
2584 TEST_F(WebContentsImplTest
, CapturerPreventsOcclusion
) {
2585 const gfx::Size
original_preferred_size(1024, 768);
2586 contents()->UpdatePreferredSize(original_preferred_size
);
2588 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2589 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2591 // With no capturers, setting and un-setting occlusion should change the
2592 // view's occlusion state.
2593 EXPECT_FALSE(view
->is_occluded());
2594 contents()->WasOccluded();
2595 EXPECT_TRUE(view
->is_occluded());
2596 contents()->WasUnOccluded();
2597 EXPECT_FALSE(view
->is_occluded());
2598 contents()->WasOccluded();
2599 EXPECT_TRUE(view
->is_occluded());
2601 // Add a capturer. This should cause the view to be un-occluded.
2602 contents()->IncrementCapturerCount(gfx::Size());
2603 EXPECT_FALSE(view
->is_occluded());
2605 // Try to occlude the view. This will fail to propagate because of the
2607 contents()->WasOccluded();
2608 EXPECT_FALSE(view
->is_occluded());
2610 // Remove the capturer and try again.
2611 contents()->DecrementCapturerCount();
2612 EXPECT_FALSE(view
->is_occluded());
2613 contents()->WasOccluded();
2614 EXPECT_TRUE(view
->is_occluded());
2617 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2619 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2620 // The WebContents starts with a valid creation time.
2621 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2623 // Reset the last active time to a known-bad value.
2624 contents()->last_active_time_
= base::TimeTicks();
2625 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2627 // Simulate activating the WebContents. The active time should update.
2628 contents()->WasShown();
2629 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2632 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2634 ContentsZoomChangedDelegate() :
2635 contents_zoom_changed_call_count_(0),
2636 last_zoom_in_(false) {
2639 int GetAndResetContentsZoomChangedCallCount() {
2640 int count
= contents_zoom_changed_call_count_
;
2641 contents_zoom_changed_call_count_
= 0;
2645 bool last_zoom_in() const {
2646 return last_zoom_in_
;
2649 // WebContentsDelegate:
2650 void ContentsZoomChange(bool zoom_in
) override
{
2651 contents_zoom_changed_call_count_
++;
2652 last_zoom_in_
= zoom_in
;
2656 int contents_zoom_changed_call_count_
;
2659 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2662 // Tests that some mouseehweel events get turned into browser zoom requests.
2663 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2664 using blink::WebInputEvent
;
2666 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2667 new ContentsZoomChangedDelegate());
2668 contents()->SetDelegate(delegate
.get());
2671 // Verify that normal mouse wheel events do nothing to change the zoom level.
2672 blink::WebMouseWheelEvent event
=
2673 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2674 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2675 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2677 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
|
2678 WebInputEvent::ControlKey
;
2679 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2680 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2681 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2683 // But whenever the ctrl modifier is applied with canScroll=false, they can
2684 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2686 modifiers
= WebInputEvent::ControlKey
;
2687 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2688 event
.canScroll
= false;
2689 bool handled
= contents()->HandleWheelEvent(event
);
2690 #if defined(OS_MACOSX)
2691 EXPECT_FALSE(handled
);
2692 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2694 EXPECT_TRUE(handled
);
2695 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2696 EXPECT_TRUE(delegate
->last_zoom_in());
2699 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2700 WebInputEvent::AltKey
;
2701 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2702 event
.canScroll
= false;
2703 handled
= contents()->HandleWheelEvent(event
);
2704 #if defined(OS_MACOSX)
2705 EXPECT_FALSE(handled
);
2706 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2708 EXPECT_TRUE(handled
);
2709 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2710 EXPECT_FALSE(delegate
->last_zoom_in());
2713 // Unless there is no vertical movement.
2714 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2715 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2716 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2718 // Events containing precise scrolling deltas also shouldn't result in the
2719 // zoom being adjusted, to avoid accidental adjustments caused by
2720 // two-finger-scrolling on a touchpad.
2721 modifiers
= WebInputEvent::ControlKey
;
2722 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2723 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2724 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2726 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2727 contents()->SetDelegate(nullptr);
2730 // Tests that GetRelatedActiveContentsCount is shared between related
2731 // SiteInstances and includes WebContents that have not navigated yet.
2732 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2733 scoped_refptr
<SiteInstance
> instance1(
2734 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2735 scoped_refptr
<SiteInstance
> instance2(
2736 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2738 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2739 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2741 scoped_ptr
<TestWebContents
> contents1(
2742 TestWebContents::Create(browser_context(), instance1
.get()));
2743 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2744 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2746 scoped_ptr
<TestWebContents
> contents2(
2747 TestWebContents::Create(browser_context(), instance1
.get()));
2748 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2749 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2752 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2753 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2756 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2757 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2760 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2761 // same-site and cross-site navigations.
2762 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2763 scoped_refptr
<SiteInstance
> instance(
2764 SiteInstance::Create(browser_context()));
2766 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2768 scoped_ptr
<TestWebContents
> contents(
2769 TestWebContents::Create(browser_context(), instance
.get()));
2770 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2772 // Navigate to a URL.
2773 contents
->GetController().LoadURL(GURL("http://a.com/1"),
2775 ui::PAGE_TRANSITION_TYPED
,
2777 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2778 contents
->CommitPendingNavigation();
2779 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2781 // Navigate to a URL in the same site.
2782 contents
->GetController().LoadURL(GURL("http://a.com/2"),
2784 ui::PAGE_TRANSITION_TYPED
,
2786 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2787 contents
->CommitPendingNavigation();
2788 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2790 // Navigate to a URL in a different site.
2791 const GURL kUrl
= GURL("http://b.com");
2792 contents
->GetController().LoadURL(kUrl
,
2794 ui::PAGE_TRANSITION_TYPED
,
2796 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2797 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2798 switches::kEnableBrowserSideNavigation
)) {
2799 contents
->GetMainFrame()->PrepareForCommit();
2801 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2802 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2803 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kUrl
);
2804 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2807 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2810 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2812 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2813 scoped_refptr
<SiteInstance
> instance(
2814 SiteInstance::Create(browser_context()));
2816 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2818 scoped_ptr
<TestWebContents
> contents(
2819 TestWebContents::Create(browser_context(), instance
.get()));
2820 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2822 // Navigate to a URL.
2823 contents
->NavigateAndCommit(GURL("http://a.com"));
2824 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2826 // Navigate to a URL which sort of looks like a chrome:// url.
2827 contents
->NavigateAndCommit(GURL("http://gpu"));
2828 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2830 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2831 const GURL kWebUIUrl
= GURL("chrome://gpu");
2832 contents
->GetController().LoadURL(kWebUIUrl
,
2834 ui::PAGE_TRANSITION_TYPED
,
2836 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2837 contents
->GetMainFrame()->PrepareForCommit();
2838 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2839 scoped_refptr
<SiteInstance
> instance_webui(
2840 contents
->GetPendingMainFrame()->GetSiteInstance());
2841 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2843 // At this point, contents still counts for the old BrowsingInstance.
2844 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2845 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2847 // Commit and contents counts for the new one.
2848 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kWebUIUrl
);
2849 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2850 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2853 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2854 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2857 class LoadingWebContentsObserver
: public WebContentsObserver
{
2859 explicit LoadingWebContentsObserver(WebContents
* contents
)
2860 : WebContentsObserver(contents
),
2861 is_loading_(false) {
2863 ~LoadingWebContentsObserver() override
{}
2865 void DidStartLoading() override
{ is_loading_
= true; }
2866 void DidStopLoading() override
{ is_loading_
= false; }
2868 bool is_loading() const { return is_loading_
; }
2873 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver
);
2876 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2877 // interleaving cross-process navigations in multiple subframes.
2878 // See https://crbug.com/448601 for details of the underlying issue. The
2879 // sequence of events that reproduce it are as follows:
2880 // * Navigate top-level frame with one subframe.
2881 // * Subframe navigates more than once before the top-level frame has had a
2882 // chance to complete the load.
2883 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2884 // to 0, while the loading_progresses_ map is not reset.
2885 TEST_F(WebContentsImplTest
, StartStopEventsBalance
) {
2886 // The bug manifests itself in regular mode as well, but browser-initiated
2887 // navigation of subframes is only possible in --site-per-process mode within
2889 base::CommandLine::ForCurrentProcess()->AppendSwitch(
2890 switches::kSitePerProcess
);
2891 const GURL
initial_url("about:blank");
2892 const GURL
main_url("http://www.chromium.org");
2893 const GURL
foo_url("http://foo.chromium.org");
2894 const GURL
bar_url("http://bar.chromium.org");
2895 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
2897 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
2898 LoadingWebContentsObserver
observer(contents());
2900 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
2901 // The frame should still be loading.
2902 controller().LoadURL(
2903 main_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2904 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2905 orig_rfh
->PrepareForCommit();
2906 orig_rfh
->OnMessageReceived(
2907 FrameHostMsg_DidStartLoading(orig_rfh
->GetRoutingID(), false));
2908 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, main_url
,
2909 ui::PAGE_TRANSITION_TYPED
);
2910 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2911 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
2912 EXPECT_TRUE(contents()->IsLoading());
2913 EXPECT_TRUE(observer
.is_loading());
2915 // Create a child frame to navigate multiple times.
2916 TestRenderFrameHost
* subframe
= orig_rfh
->AppendChild("subframe");
2918 // Navigate the child frame to about:blank, which will send both
2919 // DidStartLoading and DidStopLoading messages.
2921 subframe
->SendRendererInitiatedNavigationRequest(initial_url
, false);
2922 subframe
->OnMessageReceived(
2923 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2924 subframe
->SendNavigateWithTransition(1, 0, false, initial_url
,
2925 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2926 subframe
->OnMessageReceived(
2927 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2930 // Navigate the frame to another URL, which will send again
2931 // DidStartLoading and DidStopLoading messages.
2933 subframe
->SendRendererInitiatedNavigationRequest(foo_url
, false);
2934 subframe
->PrepareForCommit();
2935 subframe
->OnMessageReceived(
2936 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2937 subframe
->SendNavigateWithTransition(1, 0, false, foo_url
,
2938 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2939 subframe
->OnMessageReceived(
2940 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2943 // Since the main frame hasn't sent any DidStopLoading messages, it is
2944 // expected that the WebContents is still in loading state.
2945 EXPECT_TRUE(contents()->IsLoading());
2946 EXPECT_TRUE(observer
.is_loading());
2948 // Navigate the frame again, this time using LoadURLWithParams. This causes
2949 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2952 NavigationController::LoadURLParams
load_params(bar_url
);
2953 load_params
.referrer
=
2954 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
2955 load_params
.transition_type
= ui::PAGE_TRANSITION_GENERATED
;
2956 load_params
.extra_headers
= "content-type: text/plain";
2957 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
2958 load_params
.is_renderer_initiated
= false;
2959 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
2960 load_params
.frame_tree_node_id
=
2961 subframe
->frame_tree_node()->frame_tree_node_id();
2962 controller().LoadURLWithParams(load_params
);
2963 entry_id
= controller().GetPendingEntry()->GetUniqueID();
2965 subframe
->OnMessageReceived(
2966 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2968 // Commit the navigation in the child frame and send the DidStopLoading
2970 subframe
->PrepareForCommit();
2971 contents()->TestDidNavigate(subframe
, 3, entry_id
, true, bar_url
,
2972 ui::PAGE_TRANSITION_MANUAL_SUBFRAME
);
2973 subframe
->OnMessageReceived(
2974 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2977 // At this point the status should still be loading, since the main frame
2978 // hasn't sent the DidstopLoading message yet.
2979 EXPECT_TRUE(contents()->IsLoading());
2980 EXPECT_TRUE(observer
.is_loading());
2982 // Send the DidStopLoading for the main frame and ensure it isn't loading
2984 orig_rfh
->OnMessageReceived(
2985 FrameHostMsg_DidStopLoading(orig_rfh
->GetRoutingID()));
2986 EXPECT_FALSE(contents()->IsLoading());
2987 EXPECT_FALSE(observer
.is_loading());
2990 // Ensure that WebContentsImpl does not stop loading too early when there still
2991 // is a pending renderer. This can happen if a same-process non user-initiated
2992 // navigation completes while there is an ongoing cross-process navigation.
2993 // TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
2994 // DidStopLoading are properly called.
2995 TEST_F(WebContentsImplTest
, NoEarlyStop
) {
2996 const GURL
kUrl1("http://www.chromium.org");
2997 const GURL
kUrl2("http://www.google.com");
2998 const GURL
kUrl3("http://www.wikipedia.org");
3000 contents()->NavigateAndCommit(kUrl1
);
3002 TestRenderFrameHost
* current_rfh
= contents()->GetMainFrame();
3004 // Start a browser-initiated cross-process navigation to |kUrl2|. There should
3005 // be a pending RenderFrameHost and the WebContents should be loading.
3006 controller().LoadURL(
3007 kUrl2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
3008 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
3009 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
3010 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
3011 ASSERT_TRUE(pending_rfh
);
3012 EXPECT_TRUE(contents()->IsLoading());
3014 // The current RenderFrameHost starts a non user-initiated render-initiated
3015 // navigation and sends a DidStartLoading IPC. The WebContents should still be
3017 current_rfh
->OnMessageReceived(
3018 FrameHostMsg_DidStartLoading(current_rfh
->GetRoutingID(), false));
3019 EXPECT_TRUE(contents()->IsLoading());
3021 // Simulate the pending RenderFrameHost DidStartLoading. There should still be
3022 // a pending RenderFrameHost and the WebContents should still be loading.
3023 pending_rfh
->PrepareForCommit();
3024 pending_rfh
->OnMessageReceived(
3025 FrameHostMsg_DidStartLoading(pending_rfh
->GetRoutingID(), false));
3026 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3027 EXPECT_TRUE(contents()->IsLoading());
3029 // Simulate the commit and DidStopLoading from the renderer-initiated
3030 // navigation in the current RenderFrameHost. There should still be a pending
3031 // RenderFrameHost and the WebContents should still be loading.
3032 current_rfh
->SendNavigateWithModificationCallback(
3033 1, 0, true, kUrl3
, base::Bind(SetAsNonUserGesture
));
3034 current_rfh
->OnMessageReceived(
3035 FrameHostMsg_DidStopLoading(current_rfh
->GetRoutingID()));
3036 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3037 EXPECT_TRUE(contents()->IsLoading());
3038 // It should commit.
3039 ASSERT_EQ(2, controller().GetEntryCount());
3040 EXPECT_EQ(kUrl3
, controller().GetLastCommittedEntry()->GetURL());
3042 // Commit the navigation. The formerly pending RenderFrameHost should now be
3043 // the current RenderFrameHost and the WebContents should still be loading.
3044 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, kUrl2
,
3045 ui::PAGE_TRANSITION_TYPED
);
3046 EXPECT_FALSE(contents()->GetPendingMainFrame());
3047 TestRenderFrameHost
* new_current_rfh
= contents()->GetMainFrame();
3048 EXPECT_EQ(new_current_rfh
, pending_rfh
);
3049 EXPECT_TRUE(contents()->IsLoading());
3050 EXPECT_EQ(3, controller().GetEntryCount());
3052 // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
3053 // should now have stopped loading.
3054 new_current_rfh
->OnMessageReceived(
3055 FrameHostMsg_DidStopLoading(new_current_rfh
->GetRoutingID()));
3056 EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh
);
3057 EXPECT_FALSE(contents()->IsLoading());
3060 TEST_F(WebContentsImplTest
, MediaPowerSaveBlocking
) {
3061 // PlayerIDs are actually pointers cast to int64, so verify that both negative
3062 // and positive player ids don't blow up.
3063 const int kPlayerAudioVideoId
= 15;
3064 const int kPlayerAudioOnlyId
= -15;
3065 const int kPlayerVideoOnlyId
= 30;
3066 const int kPlayerRemoteId
= -30;
3068 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3069 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3071 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3072 AudioStateProvider
* audio_state
= contents()->audio_state_provider();
3074 // Ensure RenderFrame is initialized before simulating events coming from it.
3075 main_test_rfh()->InitializeRenderFrameIfNeeded();
3077 // The audio power save blocker should not be based on having a media player
3078 // when audio stream monitoring is available.
3079 if (audio_state
->IsAudioStateAvailable()) {
3080 // Send a fake audio stream monitor notification. The audio power save
3081 // blocker should be created.
3082 audio_state
->set_was_recently_audible_for_testing(true);
3083 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3084 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
3086 // Send another fake notification, this time when WasRecentlyAudible() will
3087 // be false. The power save blocker should be released.
3088 audio_state
->set_was_recently_audible_for_testing(false);
3089 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3090 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3093 // Start a player with both audio and video. A video power save blocker
3094 // should be created. If audio stream monitoring is available, an audio power
3095 // save blocker should be created too.
3096 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3097 0, kPlayerAudioVideoId
, true, true, false));
3098 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3099 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3100 !audio_state
->IsAudioStateAvailable());
3102 // Upon hiding the video power save blocker should be released.
3103 contents()->WasHidden();
3104 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3106 // Start another player that only has video. There should be no change in
3107 // the power save blockers. The notification should take into account the
3108 // visibility state of the WebContents.
3109 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3110 0, kPlayerVideoOnlyId
, true, false, false));
3111 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3112 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3113 !audio_state
->IsAudioStateAvailable());
3115 // Showing the WebContents should result in the creation of the blocker.
3116 contents()->WasShown();
3117 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3119 // Start another player that only has audio. There should be no change in
3120 // the power save blockers.
3121 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3122 0, kPlayerAudioOnlyId
, false, true, false));
3123 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3124 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3125 !audio_state
->IsAudioStateAvailable());
3127 // Start a remote player. There should be no change in the power save
3129 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3130 0, kPlayerRemoteId
, true, true, true));
3131 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3132 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3133 !audio_state
->IsAudioStateAvailable());
3135 // Destroy the original audio video player. Both power save blockers should
3137 rfh
->OnMessageReceived(
3138 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId
));
3139 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3140 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3141 !audio_state
->IsAudioStateAvailable());
3143 // Destroy the audio only player. The video power save blocker should remain.
3144 rfh
->OnMessageReceived(
3145 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId
));
3146 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3147 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3149 // Destroy the video only player. No power save blockers should remain.
3150 rfh
->OnMessageReceived(
3151 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId
));
3152 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3153 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3155 // Destroy the remote player. No power save blockers should remain.
3156 rfh
->OnMessageReceived(
3157 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId
));
3158 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3159 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3161 // Start a player with both audio and video. A video power save blocker
3162 // should be created. If audio stream monitoring is available, an audio power
3163 // save blocker should be created too.
3164 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3165 0, kPlayerAudioVideoId
, true, true, false));
3166 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3167 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3168 !audio_state
->IsAudioStateAvailable());
3170 // Crash the renderer.
3171 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
3173 // Verify that all the power save blockers have been released.
3174 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3175 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3178 TEST_F(WebContentsImplTest
, ThemeColorChangeDependingOnFirstVisiblePaint
) {
3179 TestWebContentsObserver
observer(contents());
3180 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3182 SkColor transparent
= SK_ColorTRANSPARENT
;
3184 EXPECT_EQ(transparent
, contents()->GetThemeColor());
3185 EXPECT_EQ(transparent
, observer
.last_theme_color());
3187 // Theme color changes should not propagate past the WebContentsImpl before
3188 // the first visually non-empty paint has occurred.
3189 RenderViewHostTester::TestOnMessageReceived(
3191 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorRED
));
3193 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3194 EXPECT_EQ(transparent
, observer
.last_theme_color());
3196 // Simulate that the first visually non-empty paint has occurred. This will
3197 // propagate the current theme color to the delegates.
3198 RenderViewHostTester::TestOnMessageReceived(
3200 FrameHostMsg_DidFirstVisuallyNonEmptyPaint(rfh
->GetRoutingID()));
3202 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3203 EXPECT_EQ(SK_ColorRED
, observer
.last_theme_color());
3205 // Additional changes made by the web contents should propagate as well.
3206 RenderViewHostTester::TestOnMessageReceived(
3208 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorGREEN
));
3210 EXPECT_EQ(SK_ColorGREEN
, contents()->GetThemeColor());
3211 EXPECT_EQ(SK_ColorGREEN
, observer
.last_theme_color());
3214 // Test that if a renderer reports that it has loaded a resource from
3215 // memory cache with bad security info (i.e. can't be deserialized), the
3216 // renderer gets killed.
3217 TEST_F(WebContentsImplTest
, LoadResourceFromMemoryCacheWithBadSecurityInfo
) {
3218 MockRenderProcessHost
* rph
= contents()->GetMainFrame()->GetProcess();
3219 EXPECT_EQ(0, rph
->bad_msg_count());
3221 contents()->OnDidLoadResourceFromMemoryCache(
3222 GURL("http://example.test"), "not valid security info", "GET",
3223 "mime type", RESOURCE_TYPE_MAIN_FRAME
);
3224 EXPECT_EQ(1, rph
->bad_msg_count());
3227 } // namespace content