1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/logging.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/frame_host/cross_site_transferring_request.h"
9 #include "content/browser/frame_host/interstitial_page_impl.h"
10 #include "content/browser/frame_host/navigation_entry_impl.h"
11 #include "content/browser/frame_host/render_frame_host_impl.h"
12 #include "content/browser/media/audio_state_provider.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/browser/site_instance_impl.h"
15 #include "content/browser/webui/content_web_ui_controller_factory.h"
16 #include "content/browser/webui/web_ui_controller_factory_registry.h"
17 #include "content/common/frame_messages.h"
18 #include "content/common/input/synthetic_web_input_event_builders.h"
19 #include "content/common/view_messages.h"
20 #include "content/public/browser/global_request_id.h"
21 #include "content/public/browser/interstitial_page_delegate.h"
22 #include "content/public/browser/navigation_details.h"
23 #include "content/public/browser/notification_details.h"
24 #include "content/public/browser/notification_source.h"
25 #include "content/public/browser/render_widget_host_view.h"
26 #include "content/public/browser/web_contents_delegate.h"
27 #include "content/public/browser/web_contents_observer.h"
28 #include "content/public/browser/web_ui_controller.h"
29 #include "content/public/common/bindings_policy.h"
30 #include "content/public/common/content_constants.h"
31 #include "content/public/common/content_switches.h"
32 #include "content/public/common/url_constants.h"
33 #include "content/public/common/url_utils.h"
34 #include "content/public/test/mock_render_process_host.h"
35 #include "content/public/test/test_utils.h"
36 #include "content/test/test_content_browser_client.h"
37 #include "content/test/test_content_client.h"
38 #include "content/test/test_render_frame_host.h"
39 #include "content/test/test_render_view_host.h"
40 #include "content/test/test_web_contents.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "third_party/skia/include/core/SkColor.h"
47 class TestInterstitialPage
;
49 class TestInterstitialPageDelegate
: public InterstitialPageDelegate
{
51 explicit TestInterstitialPageDelegate(TestInterstitialPage
* interstitial_page
)
52 : interstitial_page_(interstitial_page
) {}
53 void CommandReceived(const std::string
& command
) override
;
54 std::string
GetHTMLContents() override
{ return std::string(); }
55 void OnDontProceed() override
;
56 void OnProceed() override
;
59 TestInterstitialPage
* interstitial_page_
;
62 class TestInterstitialPage
: public InterstitialPageImpl
{
64 enum InterstitialState
{
65 INVALID
= 0, // Hasn't yet been initialized.
66 UNDECIDED
, // Initialized, but no decision taken yet.
67 OKED
, // Proceed was called.
68 CANCELED
// DontProceed was called.
73 virtual void TestInterstitialPageDeleted(
74 TestInterstitialPage
* interstitial
) = 0;
77 virtual ~Delegate() {}
80 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
81 // |deleted| (like all interstitial related tests do at this point), make sure
82 // to create an instance of the TestInterstitialPageStateGuard class on the
83 // stack in your test. This will ensure that the TestInterstitialPage states
84 // are cleared when the test finishes.
85 // Not doing so will cause stack trashing if your test does not hide the
86 // interstitial, as in such a case it will be destroyed in the test TearDown
87 // method and will dereference the |deleted| local variable which by then is
89 TestInterstitialPage(WebContentsImpl
* contents
,
92 InterstitialState
* state
,
94 : InterstitialPageImpl(
96 static_cast<RenderWidgetHostDelegate
*>(contents
),
97 new_navigation
, url
, new TestInterstitialPageDelegate(this)),
100 command_received_count_(0),
106 ~TestInterstitialPage() override
{
110 delegate_
->TestInterstitialPageDeleted(this);
113 void OnDontProceed() {
122 int command_received_count() const {
123 return command_received_count_
;
126 void TestDomOperationResponse(const std::string
& json_string
) {
131 void TestDidNavigate(int page_id
,
133 bool did_create_new_entry
,
135 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
136 InitNavigateParams(¶ms
, page_id
, nav_entry_id
, did_create_new_entry
,
137 url
, ui::PAGE_TRANSITION_TYPED
);
138 DidNavigate(GetMainFrame()->GetRenderViewHost(), params
);
141 void TestRenderViewTerminated(base::TerminationStatus status
,
143 RenderViewTerminated(GetMainFrame()->GetRenderViewHost(), status
,
147 bool is_showing() const {
148 return static_cast<TestRenderWidgetHostView
*>(
149 GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
158 void CommandReceived() {
159 command_received_count_
++;
162 void set_delegate(Delegate
* delegate
) {
163 delegate_
= delegate
;
167 WebContentsView
* CreateWebContentsView() override
{ return nullptr; }
170 InterstitialState
* state_
;
172 int command_received_count_
;
176 void TestInterstitialPageDelegate::CommandReceived(const std::string
& command
) {
177 interstitial_page_
->CommandReceived();
180 void TestInterstitialPageDelegate::OnDontProceed() {
181 interstitial_page_
->OnDontProceed();
184 void TestInterstitialPageDelegate::OnProceed() {
185 interstitial_page_
->OnProceed();
188 class TestInterstitialPageStateGuard
: public TestInterstitialPage::Delegate
{
190 explicit TestInterstitialPageStateGuard(
191 TestInterstitialPage
* interstitial_page
)
192 : interstitial_page_(interstitial_page
) {
193 DCHECK(interstitial_page_
);
194 interstitial_page_
->set_delegate(this);
196 ~TestInterstitialPageStateGuard() override
{
197 if (interstitial_page_
)
198 interstitial_page_
->ClearStates();
201 void TestInterstitialPageDeleted(
202 TestInterstitialPage
* interstitial
) override
{
203 DCHECK(interstitial_page_
== interstitial
);
204 interstitial_page_
= nullptr;
208 TestInterstitialPage
* interstitial_page_
;
211 class WebContentsImplTestBrowserClient
: public TestContentBrowserClient
{
213 WebContentsImplTestBrowserClient()
214 : assign_site_for_url_(false) {}
216 ~WebContentsImplTestBrowserClient() override
{}
218 bool ShouldAssignSiteForURL(const GURL
& url
) override
{
219 return assign_site_for_url_
;
222 void set_assign_site_for_url(bool assign
) {
223 assign_site_for_url_
= assign
;
227 bool assign_site_for_url_
;
230 class WebContentsImplTest
: public RenderViewHostImplTestHarness
{
232 void SetUp() override
{
233 RenderViewHostImplTestHarness::SetUp();
234 WebUIControllerFactory::RegisterFactory(
235 ContentWebUIControllerFactory::GetInstance());
238 void TearDown() override
{
239 WebUIControllerFactory::UnregisterFactoryForTesting(
240 ContentWebUIControllerFactory::GetInstance());
241 RenderViewHostImplTestHarness::TearDown();
245 class TestWebContentsObserver
: public WebContentsObserver
{
247 explicit TestWebContentsObserver(WebContents
* contents
)
248 : WebContentsObserver(contents
),
249 last_theme_color_(SK_ColorTRANSPARENT
) {
251 ~TestWebContentsObserver() override
{}
253 void DidFinishLoad(RenderFrameHost
* render_frame_host
,
254 const GURL
& validated_url
) override
{
255 last_url_
= validated_url
;
257 void DidFailLoad(RenderFrameHost
* render_frame_host
,
258 const GURL
& validated_url
,
260 const base::string16
& error_description
) override
{
261 last_url_
= validated_url
;
264 void DidChangeThemeColor(SkColor theme_color
) override
{
265 last_theme_color_
= theme_color
;
268 const GURL
& last_url() const { return last_url_
; }
269 SkColor
last_theme_color() const { return last_theme_color_
; }
273 SkColor last_theme_color_
;
275 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver
);
278 // Pretends to be a normal browser that receives toggles and transitions to/from
279 // a fullscreened state.
280 class FakeFullscreenDelegate
: public WebContentsDelegate
{
282 FakeFullscreenDelegate() : fullscreened_contents_(nullptr) {}
283 ~FakeFullscreenDelegate() override
{}
285 void EnterFullscreenModeForTab(WebContents
* web_contents
,
286 const GURL
& origin
) override
{
287 fullscreened_contents_
= web_contents
;
290 void ExitFullscreenModeForTab(WebContents
* web_contents
) override
{
291 fullscreened_contents_
= nullptr;
294 bool IsFullscreenForTabOrPending(
295 const WebContents
* web_contents
) const override
{
296 return fullscreened_contents_
&& web_contents
== fullscreened_contents_
;
300 WebContents
* fullscreened_contents_
;
302 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate
);
305 class FakeValidationMessageDelegate
: public WebContentsDelegate
{
307 FakeValidationMessageDelegate()
308 : hide_validation_message_was_called_(false) {}
309 ~FakeValidationMessageDelegate() override
{}
311 void HideValidationMessage(WebContents
* web_contents
) override
{
312 hide_validation_message_was_called_
= true;
315 bool hide_validation_message_was_called() const {
316 return hide_validation_message_was_called_
;
320 bool hide_validation_message_was_called_
;
322 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate
);
327 // Test to make sure that title updates get stripped of whitespace.
328 TEST_F(WebContentsImplTest
, UpdateTitle
) {
329 NavigationControllerImpl
& cont
=
330 static_cast<NavigationControllerImpl
&>(controller());
331 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
332 InitNavigateParams(¶ms
, 0, 0, true, GURL(url::kAboutBlankURL
),
333 ui::PAGE_TRANSITION_TYPED
);
335 LoadCommittedDetails details
;
336 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
338 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
339 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
340 base::i18n::LEFT_TO_RIGHT
);
341 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
344 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
345 const GURL
kGURL("chrome://blah");
346 controller().LoadURL(
347 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
348 EXPECT_EQ(base::string16(), contents()->GetTitle());
351 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
352 const GURL
kGURL("chrome://blah");
353 const base::string16 title
= base::ASCIIToUTF16("My Title");
354 controller().LoadURL(
355 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
357 NavigationEntry
* entry
= controller().GetVisibleEntry();
358 ASSERT_EQ(kGURL
, entry
->GetURL());
359 entry
->SetTitle(title
);
361 EXPECT_EQ(title
, contents()->GetTitle());
364 // Test view source mode for a webui page.
365 TEST_F(WebContentsImplTest
, NTPViewSource
) {
366 NavigationControllerImpl
& cont
=
367 static_cast<NavigationControllerImpl
&>(controller());
368 const char kUrl
[] = "view-source:chrome://blah";
369 const GURL
kGURL(kUrl
);
371 process()->sink().ClearMessages();
374 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
375 int entry_id
= cont
.GetPendingEntry()->GetUniqueID();
376 rvh()->GetDelegate()->RenderViewCreated(rvh());
377 // Did we get the expected message?
378 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
379 ViewMsg_EnableViewSourceMode::ID
));
381 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
382 InitNavigateParams(¶ms
, 0, entry_id
, true, kGURL
,
383 ui::PAGE_TRANSITION_TYPED
);
384 LoadCommittedDetails details
;
385 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
386 // Also check title and url.
387 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
390 // Test to ensure UpdateMaxPageID is working properly.
391 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
392 SiteInstance
* instance1
= contents()->GetSiteInstance();
393 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(nullptr));
396 EXPECT_EQ(-1, contents()->GetMaxPageID());
397 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
398 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
400 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
401 contents()->UpdateMaxPageID(3);
402 contents()->UpdateMaxPageID(1);
403 EXPECT_EQ(3, contents()->GetMaxPageID());
404 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
405 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
407 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
408 EXPECT_EQ(3, contents()->GetMaxPageID());
409 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
410 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
413 // Test simple same-SiteInstance navigation.
414 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
415 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
416 SiteInstance
* instance1
= contents()->GetSiteInstance();
417 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
420 const GURL
url("http://www.google.com");
421 controller().LoadURL(
422 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
423 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
424 main_test_rfh()->PrepareForCommit();
425 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
426 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
427 // Controller's pending entry will have a null site instance until we assign
428 // it in DidNavigate.
431 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
434 // DidNavigate from the page
435 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
436 ui::PAGE_TRANSITION_TYPED
);
437 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
438 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
439 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
440 // Controller's entry should now have the SiteInstance, or else we won't be
441 // able to find it later.
444 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
448 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
449 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
450 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
451 const GURL
url(std::string("http://example.org/").append(
452 GetMaxURLChars() + 1, 'a'));
454 controller().LoadURL(
455 url
, Referrer(), ui::PAGE_TRANSITION_GENERATED
, std::string());
456 EXPECT_EQ(nullptr, controller().GetVisibleEntry());
459 // Test that navigating across a site boundary creates a new RenderViewHost
460 // with a new SiteInstance. Going back should do the same.
461 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
462 bool is_site_per_process
= base::CommandLine::ForCurrentProcess()->HasSwitch(
463 switches::kSitePerProcess
);
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 (!is_site_per_process
)
544 EXPECT_EQ(orig_rfh
, goback_rfh
);
545 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
547 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
548 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
549 switches::kEnableBrowserSideNavigation
)) {
550 EXPECT_TRUE(goback_rfh
->are_navigations_suspended());
551 pending_rfh
->SendBeforeUnloadACK(true);
552 EXPECT_FALSE(goback_rfh
->are_navigations_suspended());
555 // DidNavigate from the back action
556 contents()->TestDidNavigate(goback_rfh
, 1, entry_id
, false, url2
,
557 ui::PAGE_TRANSITION_TYPED
);
558 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
559 EXPECT_EQ(goback_rfh
, contents()->GetMainFrame());
560 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
561 // There should be a proxy for the pending RFH SiteInstance.
562 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
563 GetRenderFrameProxyHost(pending_rfh
->GetSiteInstance()));
564 EXPECT_EQ(pending_rvh_delete_count
, 0);
565 pending_rfh
->OnSwappedOut();
567 // Close contents and ensure RVHs are deleted.
569 EXPECT_EQ(orig_rvh_delete_count
, 1);
570 EXPECT_EQ(pending_rvh_delete_count
, 1);
573 // Test that navigating across a site boundary after a crash creates a new
574 // RFH without requiring a cross-site transition (i.e., PENDING state).
575 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
576 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
578 int orig_rvh_delete_count
= 0;
579 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
580 SiteInstance
* instance1
= contents()->GetSiteInstance();
582 // Navigate to URL. First URL should use first RenderViewHost.
583 const GURL
url("http://www.google.com");
584 controller().LoadURL(
585 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
586 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
587 contents()->GetMainFrame()->PrepareForCommit();
588 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
589 ui::PAGE_TRANSITION_TYPED
);
591 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
592 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
594 // Simulate a renderer crash.
595 EXPECT_TRUE(orig_rfh
->IsRenderFrameLive());
596 orig_rfh
->GetProcess()->SimulateCrash();
597 EXPECT_FALSE(orig_rfh
->IsRenderFrameLive());
599 // Navigate to new site. We should not go into PENDING.
600 const GURL
url2("http://www.yahoo.com");
601 controller().LoadURL(
602 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
603 entry_id
= controller().GetPendingEntry()->GetUniqueID();
604 contents()->GetMainFrame()->PrepareForCommit();
605 TestRenderFrameHost
* new_rfh
= contents()->GetMainFrame();
606 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
607 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
608 EXPECT_NE(orig_rfh
, new_rfh
);
609 EXPECT_EQ(orig_rvh_delete_count
, 1);
611 // DidNavigate from the new page
612 contents()->TestDidNavigate(new_rfh
, 1, entry_id
, true, url2
,
613 ui::PAGE_TRANSITION_TYPED
);
614 SiteInstance
* instance2
= contents()->GetSiteInstance();
616 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
617 EXPECT_EQ(new_rfh
, main_rfh());
618 EXPECT_NE(instance1
, instance2
);
619 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
621 // Close contents and ensure RVHs are deleted.
623 EXPECT_EQ(orig_rvh_delete_count
, 1);
626 // Test that opening a new contents in the same SiteInstance and then navigating
627 // both contentses to a new site will place both contentses in a single
629 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
630 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
631 SiteInstance
* instance1
= contents()->GetSiteInstance();
633 // Navigate to URL. First URL should use first RenderViewHost.
634 const GURL
url("http://www.google.com");
635 controller().LoadURL(
636 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
637 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
638 contents()->GetMainFrame()->PrepareForCommit();
639 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
640 ui::PAGE_TRANSITION_TYPED
);
642 // Open a new contents with the same SiteInstance, navigated to the same site.
643 scoped_ptr
<TestWebContents
> contents2(
644 TestWebContents::Create(browser_context(), instance1
));
645 contents2
->GetController().LoadURL(url
, Referrer(),
646 ui::PAGE_TRANSITION_TYPED
,
648 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
649 contents2
->GetMainFrame()->PrepareForCommit();
650 // Need this page id to be 2 since the site instance is the same (which is the
651 // scope of page IDs) and we want to consider this a new page.
652 contents2
->TestDidNavigate(contents2
->GetMainFrame(), 2, entry_id
, true, url
,
653 ui::PAGE_TRANSITION_TYPED
);
655 // Navigate first contents to a new site.
656 const GURL
url2a("http://www.yahoo.com");
657 controller().LoadURL(
658 url2a
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
659 entry_id
= controller().GetPendingEntry()->GetUniqueID();
660 orig_rfh
->PrepareForCommit();
661 TestRenderFrameHost
* pending_rfh_a
= contents()->GetPendingMainFrame();
662 contents()->TestDidNavigate(pending_rfh_a
, 1, entry_id
, true, url2a
,
663 ui::PAGE_TRANSITION_TYPED
);
664 SiteInstance
* instance2a
= contents()->GetSiteInstance();
665 EXPECT_NE(instance1
, instance2a
);
667 // Navigate second contents to the same site as the first tab.
668 const GURL
url2b("http://mail.yahoo.com");
669 contents2
->GetController().LoadURL(url2b
, Referrer(),
670 ui::PAGE_TRANSITION_TYPED
,
672 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
673 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
674 rfh2
->PrepareForCommit();
675 TestRenderFrameHost
* pending_rfh_b
= contents2
->GetPendingMainFrame();
676 EXPECT_NE(nullptr, pending_rfh_b
);
677 EXPECT_TRUE(contents2
->CrossProcessNavigationPending());
679 // NOTE(creis): We used to be in danger of showing a crash page here if the
680 // second contents hadn't navigated somewhere first (bug 1145430). That case
681 // is now covered by the CrossSiteBoundariesAfterCrash test.
682 contents2
->TestDidNavigate(pending_rfh_b
, 2, entry_id
, true, url2b
,
683 ui::PAGE_TRANSITION_TYPED
);
684 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
685 EXPECT_NE(instance1
, instance2b
);
687 // Both contentses should now be in the same SiteInstance.
688 EXPECT_EQ(instance2a
, instance2b
);
691 // The embedder can request sites for certain urls not be be assigned to the
692 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
693 // allowing to reuse the renderer backing certain chrome urls for subsequent
694 // navigation. The test verifies that the override is honored.
695 TEST_F(WebContentsImplTest
, NavigateFromSitelessUrl
) {
696 WebContentsImplTestBrowserClient browser_client
;
697 SetBrowserClientForTesting(&browser_client
);
699 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
700 int orig_rvh_delete_count
= 0;
701 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
702 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
704 browser_client
.set_assign_site_for_url(false);
705 // Navigate to an URL that will not assign a new SiteInstance.
706 const GURL
native_url("non-site-url://stuffandthings");
707 controller().LoadURL(
708 native_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
709 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
710 contents()->GetMainFrame()->PrepareForCommit();
711 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, native_url
,
712 ui::PAGE_TRANSITION_TYPED
);
714 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
715 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
716 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
717 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
718 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
719 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
720 EXPECT_FALSE(orig_instance
->HasSite());
722 browser_client
.set_assign_site_for_url(true);
723 // Navigate to new site (should keep same site instance).
724 const GURL
url("http://www.google.com");
725 controller().LoadURL(
726 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
727 entry_id
= controller().GetPendingEntry()->GetUniqueID();
728 contents()->GetMainFrame()->PrepareForCommit();
729 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
730 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
731 EXPECT_EQ(url
, contents()->GetVisibleURL());
732 EXPECT_FALSE(contents()->GetPendingMainFrame());
733 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url
,
734 ui::PAGE_TRANSITION_TYPED
);
736 // Keep the number of active frames in orig_rfh's SiteInstance
737 // non-zero so that orig_rfh doesn't get deleted when it gets
739 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
741 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
743 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
744 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
746 // Navigate to another new site (should create a new site instance).
747 const GURL
url2("http://www.yahoo.com");
748 controller().LoadURL(
749 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
750 entry_id
= controller().GetPendingEntry()->GetUniqueID();
751 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
752 switches::kEnableBrowserSideNavigation
)) {
753 orig_rfh
->PrepareForCommit();
755 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
756 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
757 EXPECT_EQ(url2
, contents()->GetVisibleURL());
758 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
759 int pending_rvh_delete_count
= 0;
760 pending_rfh
->GetRenderViewHost()->set_delete_counter(
761 &pending_rvh_delete_count
);
763 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
764 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
765 switches::kEnableBrowserSideNavigation
)) {
766 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
767 orig_rfh
->SendBeforeUnloadACK(true);
768 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
771 // DidNavigate from the pending page.
772 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
773 ui::PAGE_TRANSITION_TYPED
);
774 SiteInstance
* new_instance
= contents()->GetSiteInstance();
776 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
777 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
778 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
779 EXPECT_EQ(url2
, contents()->GetVisibleURL());
780 EXPECT_NE(new_instance
, orig_instance
);
781 EXPECT_FALSE(contents()->GetPendingMainFrame());
782 // We keep a proxy for the original RFH's SiteInstance.
783 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
784 orig_rfh
->GetSiteInstance()));
785 EXPECT_EQ(orig_rvh_delete_count
, 0);
786 orig_rfh
->OnSwappedOut();
788 // Close contents and ensure RVHs are deleted.
790 EXPECT_EQ(orig_rvh_delete_count
, 1);
791 EXPECT_EQ(pending_rvh_delete_count
, 1);
794 // Regression test for http://crbug.com/386542 - variation of
795 // NavigateFromSitelessUrl in which the original navigation is a session
797 TEST_F(WebContentsImplTest
, NavigateFromRestoredSitelessUrl
) {
798 WebContentsImplTestBrowserClient browser_client
;
799 SetBrowserClientForTesting(&browser_client
);
800 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
801 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
803 // Restore a navigation entry for URL that should not assign site to the
805 browser_client
.set_assign_site_for_url(false);
806 const GURL
native_url("non-site-url://stuffandthings");
807 ScopedVector
<NavigationEntry
> entries
;
808 scoped_ptr
<NavigationEntry
> new_entry
=
809 NavigationControllerImpl::CreateNavigationEntry(
810 native_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false,
811 std::string(), browser_context());
812 new_entry
->SetPageID(0);
813 entries
.push_back(new_entry
.Pass());
814 controller().Restore(
816 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
818 ASSERT_EQ(0u, entries
.size());
819 ASSERT_EQ(1, controller().GetEntryCount());
821 controller().GoToIndex(0);
822 NavigationEntry
* entry
= controller().GetPendingEntry();
823 orig_rfh
->PrepareForCommit();
824 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
825 native_url
, ui::PAGE_TRANSITION_RELOAD
);
826 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
827 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
828 EXPECT_FALSE(orig_instance
->HasSite());
830 // Navigate to a regular site and verify that the SiteInstance was kept.
831 browser_client
.set_assign_site_for_url(true);
832 const GURL
url("http://www.google.com");
833 controller().LoadURL(
834 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
835 entry
= controller().GetPendingEntry();
836 orig_rfh
->PrepareForCommit();
837 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, url
,
838 ui::PAGE_TRANSITION_TYPED
);
839 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
845 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
846 // tab is restored, the SiteInstance will change upon navigation.
847 TEST_F(WebContentsImplTest
, NavigateFromRestoredRegularUrl
) {
848 WebContentsImplTestBrowserClient browser_client
;
849 SetBrowserClientForTesting(&browser_client
);
850 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
851 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
853 // Restore a navigation entry for a regular URL ensuring that the embedder
854 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
855 browser_client
.set_assign_site_for_url(true);
856 const GURL
regular_url("http://www.yahoo.com");
857 ScopedVector
<NavigationEntry
> entries
;
858 scoped_ptr
<NavigationEntry
> new_entry
=
859 NavigationControllerImpl::CreateNavigationEntry(
860 regular_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false,
861 std::string(), browser_context());
862 new_entry
->SetPageID(0);
863 entries
.push_back(new_entry
.Pass());
864 controller().Restore(
866 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
868 ASSERT_EQ(0u, entries
.size());
870 ASSERT_EQ(1, controller().GetEntryCount());
871 controller().GoToIndex(0);
872 NavigationEntry
* entry
= controller().GetPendingEntry();
873 orig_rfh
->PrepareForCommit();
874 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
875 regular_url
, ui::PAGE_TRANSITION_RELOAD
);
876 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
877 EXPECT_TRUE(orig_instance
->HasSite());
879 // Navigate to another site and verify that a new SiteInstance was created.
880 const GURL
url("http://www.google.com");
881 controller().LoadURL(
882 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
883 entry
= controller().GetPendingEntry();
884 orig_rfh
->PrepareForCommit();
885 contents()->TestDidNavigate(contents()->GetPendingMainFrame(), 2,
886 entry
->GetUniqueID(), true, url
,
887 ui::PAGE_TRANSITION_TYPED
);
888 EXPECT_NE(orig_instance
, contents()->GetSiteInstance());
894 // Test that we can find an opener RVH even if it's pending.
895 // http://crbug.com/176252.
896 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
897 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
899 // Navigate to a URL.
900 const GURL
url("http://www.google.com");
901 controller().LoadURL(
902 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
903 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
904 orig_rfh
->PrepareForCommit();
905 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
906 ui::PAGE_TRANSITION_TYPED
);
908 // Start to navigate first tab to a new site, so that it has a pending RVH.
909 const GURL
url2("http://www.yahoo.com");
910 controller().LoadURL(
911 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
912 orig_rfh
->PrepareForCommit();
913 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
915 // While it is still pending, simulate opening a new tab with the first tab
916 // as its opener. This will call CreateOpenerProxies on the opener to ensure
917 // that an RVH exists.
918 int opener_routing_id
= contents()->GetRenderManager()->CreateOpenerProxies(
919 pending_rfh
->GetSiteInstance());
921 // We should find the pending RVH and not create a new one.
922 EXPECT_EQ(pending_rfh
->GetRenderViewHost()->GetRoutingID(),
926 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
927 // to determine whether a navigation is cross-site.
928 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
929 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
930 SiteInstance
* instance1
= contents()->GetSiteInstance();
933 const GURL
url("http://www.google.com");
934 controller().LoadURL(
935 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
936 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
937 contents()->GetMainFrame()->PrepareForCommit();
938 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
939 ui::PAGE_TRANSITION_TYPED
);
941 // Open a related contents to a second site.
942 scoped_ptr
<TestWebContents
> contents2(
943 TestWebContents::Create(browser_context(), instance1
));
944 const GURL
url2("http://www.yahoo.com");
945 contents2
->GetController().LoadURL(url2
, Referrer(),
946 ui::PAGE_TRANSITION_TYPED
,
948 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
949 contents2
->GetMainFrame()->PrepareForCommit();
951 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
953 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
954 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
955 contents2
->TestDidNavigate(rfh2
, 2, entry_id
, true, url2
,
956 ui::PAGE_TRANSITION_TYPED
);
957 SiteInstance
* instance2
= contents2
->GetSiteInstance();
958 EXPECT_NE(instance1
, instance2
);
959 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
961 // Simulate a link click in first contents to second site. Doesn't switch
962 // SiteInstances, because we don't intercept Blink navigations.
963 orig_rfh
->SendRendererInitiatedNavigationRequest(url2
, true);
964 orig_rfh
->PrepareForCommit();
965 contents()->TestDidNavigate(orig_rfh
, 2, 0, true, url2
,
966 ui::PAGE_TRANSITION_TYPED
);
967 SiteInstance
* instance3
= contents()->GetSiteInstance();
968 EXPECT_EQ(instance1
, instance3
);
969 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
971 // Navigate to the new site. Doesn't switch SiteInstancees, because we
972 // compare against the current URL, not the SiteInstance's site.
973 const GURL
url3("http://mail.yahoo.com");
974 controller().LoadURL(
975 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
976 entry_id
= controller().GetPendingEntry()->GetUniqueID();
977 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
978 contents()->GetMainFrame()->PrepareForCommit();
979 contents()->TestDidNavigate(orig_rfh
, 3, entry_id
, true, url3
,
980 ui::PAGE_TRANSITION_TYPED
);
981 SiteInstance
* instance4
= contents()->GetSiteInstance();
982 EXPECT_EQ(instance1
, instance4
);
985 // Test that the onbeforeunload and onunload handlers run when navigating
986 // across site boundaries.
987 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
988 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
989 SiteInstance
* instance1
= contents()->GetSiteInstance();
991 // Navigate to URL. First URL should use first RenderViewHost.
992 const GURL
url("http://www.google.com");
993 controller().LoadURL(
994 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
995 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
996 contents()->GetMainFrame()->PrepareForCommit();
997 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
998 ui::PAGE_TRANSITION_TYPED
);
999 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1000 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1002 // Navigate to new site, but simulate an onbeforeunload denial.
1003 const GURL
url2("http://www.yahoo.com");
1004 controller().LoadURL(
1005 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1006 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1007 base::TimeTicks now
= base::TimeTicks::Now();
1008 orig_rfh
->OnMessageReceived(
1009 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
1010 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1011 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1012 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1014 // Navigate again, but simulate an onbeforeunload approval.
1015 controller().LoadURL(
1016 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1017 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1018 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1019 now
= base::TimeTicks::Now();
1020 orig_rfh
->PrepareForCommit();
1021 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1022 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1023 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1025 // We won't hear DidNavigate until the onunload handler has finished running.
1027 // DidNavigate from the pending page.
1028 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1029 ui::PAGE_TRANSITION_TYPED
);
1030 SiteInstance
* instance2
= contents()->GetSiteInstance();
1031 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1032 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1033 EXPECT_NE(instance1
, instance2
);
1034 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1037 // Test that during a slow cross-site navigation, the original renderer can
1038 // navigate to a different URL and have it displayed, canceling the slow
1040 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
1041 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1042 SiteInstance
* instance1
= contents()->GetSiteInstance();
1044 // Navigate to URL. First URL should use first RenderFrameHost.
1045 const GURL
url("http://www.google.com");
1046 controller().LoadURL(
1047 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1048 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1049 contents()->GetMainFrame()->PrepareForCommit();
1050 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1051 ui::PAGE_TRANSITION_TYPED
);
1052 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1053 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1055 // Navigate to new site, simulating an onbeforeunload approval.
1056 const GURL
url2("http://www.yahoo.com");
1057 controller().LoadURL(
1058 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1059 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1060 orig_rfh
->PrepareForCommit();
1061 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1063 // Suppose the original renderer navigates before the new one is ready.
1064 orig_rfh
->SendNavigate(2, 0, true, GURL("http://www.google.com/foo"));
1066 // Verify that the pending navigation is cancelled.
1067 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1068 SiteInstance
* instance2
= contents()->GetSiteInstance();
1069 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1070 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1071 EXPECT_EQ(instance1
, instance2
);
1072 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1075 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1076 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1077 const GURL
url1("chrome://gpu");
1078 controller().LoadURL(
1079 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1080 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1081 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
1082 ntp_rfh
->PrepareForCommit();
1083 contents()->TestDidNavigate(ntp_rfh
, 1, entry_id
, true, url1
,
1084 ui::PAGE_TRANSITION_TYPED
);
1085 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1086 SiteInstance
* instance1
= contents()->GetSiteInstance();
1088 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1089 EXPECT_EQ(ntp_rfh
, contents()->GetMainFrame());
1090 EXPECT_EQ(url1
, entry1
->GetURL());
1091 EXPECT_EQ(instance1
,
1092 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1093 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1094 BINDINGS_POLICY_WEB_UI
);
1096 // Navigate to new site.
1097 const GURL
url2("http://www.google.com");
1098 controller().LoadURL(
1099 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1100 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1101 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1102 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1104 // Simulate beforeunload approval.
1105 EXPECT_TRUE(ntp_rfh
->IsWaitingForBeforeUnloadACK());
1106 base::TimeTicks now
= base::TimeTicks::Now();
1107 ntp_rfh
->PrepareForCommit();
1109 // DidNavigate from the pending page.
1110 contents()->TestDidNavigate(google_rfh
, 1, entry_id
, true, url2
,
1111 ui::PAGE_TRANSITION_TYPED
);
1112 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1113 SiteInstance
* instance2
= contents()->GetSiteInstance();
1115 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1116 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1117 EXPECT_NE(instance1
, instance2
);
1118 EXPECT_FALSE(contents()->GetPendingMainFrame());
1119 EXPECT_EQ(url2
, entry2
->GetURL());
1120 EXPECT_EQ(instance2
,
1121 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1122 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1123 BINDINGS_POLICY_WEB_UI
);
1125 // Navigate to third page on same site.
1126 const GURL
url3("http://news.google.com");
1127 controller().LoadURL(
1128 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1129 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1130 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1131 contents()->GetMainFrame()->PrepareForCommit();
1132 contents()->TestDidNavigate(google_rfh
, 2, entry_id
, true, url3
,
1133 ui::PAGE_TRANSITION_TYPED
);
1134 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1135 SiteInstance
* instance3
= contents()->GetSiteInstance();
1137 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1138 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1139 EXPECT_EQ(instance2
, instance3
);
1140 EXPECT_FALSE(contents()->GetPendingMainFrame());
1141 EXPECT_EQ(url3
, entry3
->GetURL());
1142 EXPECT_EQ(instance3
,
1143 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1145 // Go back within the site.
1146 controller().GoBack();
1147 NavigationEntry
* goback_entry
= controller().GetPendingEntry();
1148 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1149 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1151 // Before that commits, go back again.
1152 controller().GoBack();
1153 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1154 EXPECT_TRUE(contents()->GetPendingMainFrame());
1155 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1157 // Simulate beforeunload approval.
1158 EXPECT_TRUE(google_rfh
->IsWaitingForBeforeUnloadACK());
1159 now
= base::TimeTicks::Now();
1160 google_rfh
->PrepareForCommit();
1161 google_rfh
->OnMessageReceived(
1162 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1164 // DidNavigate from the first back. This aborts the second back's pending RFH.
1165 contents()->TestDidNavigate(google_rfh
, 1, goback_entry
->GetUniqueID(), false,
1166 url2
, ui::PAGE_TRANSITION_TYPED
);
1168 // We should commit this page and forget about the second back.
1169 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1170 EXPECT_FALSE(controller().GetPendingEntry());
1171 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1172 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1174 // We should not have corrupted the NTP entry.
1175 EXPECT_EQ(instance3
,
1176 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1177 EXPECT_EQ(instance2
,
1178 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1179 EXPECT_EQ(instance1
,
1180 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1181 EXPECT_EQ(url1
, entry1
->GetURL());
1184 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1185 // original renderer will not cancel the slow navigation (bug 42029).
1186 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1187 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1189 // Navigate to URL. First URL should use the original RenderFrameHost.
1190 const GURL
url("http://www.google.com");
1191 controller().LoadURL(
1192 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1193 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1194 contents()->GetMainFrame()->PrepareForCommit();
1195 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1196 ui::PAGE_TRANSITION_TYPED
);
1197 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1198 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1200 // Start navigating to new site.
1201 const GURL
url2("http://www.yahoo.com");
1202 controller().LoadURL(
1203 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1205 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1206 // waiting for a before unload response.
1207 TestRenderFrameHost
* child_rfh
= orig_rfh
->AppendChild("subframe");
1208 child_rfh
->SendNavigateWithTransition(1, 0, false,
1209 GURL("http://google.com/frame"),
1210 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
1211 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1213 // Now simulate the onbeforeunload approval and verify the navigation is
1215 orig_rfh
->PrepareForCommit();
1216 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1217 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1221 void SetAsNonUserGesture(FrameHostMsg_DidCommitProvisionalLoad_Params
* params
) {
1222 params
->gesture
= NavigationGestureAuto
;
1226 // Test that a cross-site navigation is not preempted if the previous
1227 // renderer sends a FrameNavigate message just before being told to stop.
1228 // We should only preempt the cross-site navigation if the previous renderer
1229 // has started a new navigation. See http://crbug.com/79176.
1230 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1231 // Navigate to WebUI URL.
1232 const GURL
url("chrome://gpu");
1233 controller().LoadURL(
1234 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1235 int entry1_id
= controller().GetPendingEntry()->GetUniqueID();
1236 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1237 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1239 // Navigate to new site, with the beforeunload request in flight.
1240 const GURL
url2("http://www.yahoo.com");
1241 controller().LoadURL(
1242 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1243 int entry2_id
= controller().GetPendingEntry()->GetUniqueID();
1244 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1245 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1246 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1247 EXPECT_NE(orig_rfh
, pending_rfh
);
1249 // Suppose the first navigation tries to commit now, with a
1250 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1251 // but it should act as if the beforeunload ack arrived.
1252 orig_rfh
->SendNavigateWithModificationCallback(
1253 1, entry1_id
, true, url
, base::Bind(SetAsNonUserGesture
));
1254 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1255 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1256 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1257 // It should commit.
1258 ASSERT_EQ(1, controller().GetEntryCount());
1259 EXPECT_EQ(url
, controller().GetLastCommittedEntry()->GetURL());
1261 // The pending navigation should be able to commit successfully.
1262 contents()->TestDidNavigate(pending_rfh
, 1, entry2_id
, true, url2
,
1263 ui::PAGE_TRANSITION_TYPED
);
1264 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1265 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1266 EXPECT_EQ(2, controller().GetEntryCount());
1269 // Test that NavigationEntries have the correct page state after going
1270 // forward and back. Prevents regression for bug 1116137.
1271 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1272 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1274 // Navigate to URL. There should be no committed entry yet.
1275 const GURL
url("http://www.google.com");
1276 controller().LoadURL(
1277 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1278 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1279 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1280 EXPECT_EQ(nullptr, entry
);
1282 // Committed entry should have page state after DidNavigate.
1283 orig_rfh
->PrepareForCommit();
1284 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1285 ui::PAGE_TRANSITION_TYPED
);
1286 entry
= controller().GetLastCommittedEntry();
1287 EXPECT_TRUE(entry
->GetPageState().IsValid());
1289 // Navigate to same site.
1290 const GURL
url2("http://images.google.com");
1291 controller().LoadURL(
1292 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1293 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1294 entry
= controller().GetLastCommittedEntry();
1295 EXPECT_TRUE(entry
->GetPageState().IsValid());
1297 // Committed entry should have page state after DidNavigate.
1298 orig_rfh
->PrepareForCommit();
1299 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1300 ui::PAGE_TRANSITION_TYPED
);
1301 entry
= controller().GetLastCommittedEntry();
1302 EXPECT_TRUE(entry
->GetPageState().IsValid());
1304 // Now go back. Committed entry should still have page state.
1305 controller().GoBack();
1306 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1307 orig_rfh
->PrepareForCommit();
1308 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, false, url
,
1309 ui::PAGE_TRANSITION_TYPED
);
1310 entry
= controller().GetLastCommittedEntry();
1311 EXPECT_TRUE(entry
->GetPageState().IsValid());
1314 // Test that NavigationEntries have the correct page state and SiteInstance
1315 // state after opening a new window to about:blank. Prevents regression for
1316 // bugs b/1116137 and http://crbug.com/111975.
1317 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1318 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1320 // Navigate to about:blank.
1321 const GURL
url(url::kAboutBlankURL
);
1322 orig_rfh
->SendRendererInitiatedNavigationRequest(url
, false);
1323 orig_rfh
->PrepareForCommit();
1324 contents()->TestDidNavigate(orig_rfh
, 1, 0, true, url
,
1325 ui::PAGE_TRANSITION_TYPED
);
1327 // Should have a page state here.
1328 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1329 EXPECT_TRUE(entry
->GetPageState().IsValid());
1331 // The SiteInstance should be available for other navigations to use.
1332 NavigationEntryImpl
* entry_impl
=
1333 NavigationEntryImpl::FromNavigationEntry(entry
);
1334 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1335 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1337 // Navigating to a normal page should not cause a process swap.
1338 const GURL
new_url("http://www.google.com");
1339 controller().LoadURL(new_url
, Referrer(),
1340 ui::PAGE_TRANSITION_TYPED
, std::string());
1341 entry
= controller().GetPendingEntry();
1342 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1343 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1344 orig_rfh
->PrepareForCommit();
1345 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, new_url
,
1346 ui::PAGE_TRANSITION_TYPED
);
1347 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1348 controller().GetLastCommittedEntry());
1349 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1350 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1353 // Tests that fullscreen is exited throughout the object hierarchy when
1354 // navigating to a new page.
1355 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1356 FakeFullscreenDelegate fake_delegate
;
1357 contents()->SetDelegate(&fake_delegate
);
1358 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1359 TestRenderViewHost
* orig_rvh
= orig_rfh
->GetRenderViewHost();
1361 // Navigate to a site.
1362 const GURL
url("http://www.google.com");
1363 controller().LoadURL(
1364 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1365 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1366 contents()->GetMainFrame()->PrepareForCommit();
1367 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1368 ui::PAGE_TRANSITION_TYPED
);
1369 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1371 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1372 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1373 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1374 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1375 orig_rfh
->OnMessageReceived(
1376 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1377 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1378 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1379 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1381 // Navigate to a new site.
1382 const GURL
url2("http://www.yahoo.com");
1383 controller().LoadURL(
1384 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1385 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1386 contents()->GetMainFrame()->PrepareForCommit();
1387 TestRenderFrameHost
* const pending_rfh
= contents()->GetPendingMainFrame();
1388 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1389 ui::PAGE_TRANSITION_TYPED
);
1391 // Confirm fullscreen has exited.
1392 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1393 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1394 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1396 contents()->SetDelegate(nullptr);
1399 // Tests that fullscreen is exited throughout the object hierarchy when
1400 // instructing NavigationController to GoBack() or GoForward().
1401 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1402 FakeFullscreenDelegate fake_delegate
;
1403 contents()->SetDelegate(&fake_delegate
);
1404 TestRenderFrameHost
* const orig_rfh
= contents()->GetMainFrame();
1405 TestRenderViewHost
* const orig_rvh
= orig_rfh
->GetRenderViewHost();
1407 // Navigate to a site.
1408 const GURL
url("http://www.google.com");
1409 controller().LoadURL(
1410 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1411 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1412 orig_rfh
->PrepareForCommit();
1413 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1414 ui::PAGE_TRANSITION_TYPED
);
1415 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1417 // Now, navigate to another page on the same site.
1418 const GURL
url2("http://www.google.com/search?q=kittens");
1419 controller().LoadURL(
1420 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1421 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1422 orig_rfh
->PrepareForCommit();
1423 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1424 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1425 ui::PAGE_TRANSITION_TYPED
);
1426 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1428 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1429 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1430 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1431 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1433 for (int i
= 0; i
< 2; ++i
) {
1434 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1435 orig_rfh
->OnMessageReceived(
1436 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1437 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1438 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1439 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1441 // Navigate backward (or forward).
1443 controller().GoBack();
1445 controller().GoForward();
1446 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1447 orig_rfh
->PrepareForCommit();
1448 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1449 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1450 contents()->TestDidNavigate(orig_rfh
, i
+ 1, entry_id
, false, url
,
1451 ui::PAGE_TRANSITION_FORWARD_BACK
);
1453 // Confirm fullscreen has exited.
1454 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1455 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1456 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1459 contents()->SetDelegate(nullptr);
1462 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1463 FakeValidationMessageDelegate fake_delegate
;
1464 contents()->SetDelegate(&fake_delegate
);
1465 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1467 // Initialize the RenderFrame and then simulate crashing the renderer
1469 contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
1470 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1472 // Confirm HideValidationMessage was called.
1473 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1475 contents()->SetDelegate(nullptr);
1478 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1480 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1481 FakeFullscreenDelegate fake_delegate
;
1482 contents()->SetDelegate(&fake_delegate
);
1484 // Navigate to a site.
1485 const GURL
url("http://www.google.com");
1486 controller().LoadURL(
1487 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1488 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1489 main_test_rfh()->PrepareForCommit();
1490 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
1491 url
, ui::PAGE_TRANSITION_TYPED
);
1493 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1494 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1495 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1496 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1497 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1498 contents()->GetMainFrame()->GetRoutingID(), true));
1499 EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
1500 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1501 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1503 // Crash the renderer.
1504 main_test_rfh()->GetProcess()->SimulateCrash();
1506 // Confirm fullscreen has exited.
1507 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1508 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1509 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1511 contents()->SetDelegate(nullptr);
1514 ////////////////////////////////////////////////////////////////////////////////
1515 // Interstitial Tests
1516 ////////////////////////////////////////////////////////////////////////////////
1518 // Test navigating to a page (with the navigation initiated from the browser,
1519 // as when a URL is typed in the location bar) that shows an interstitial and
1520 // creates a new navigation entry, then hiding it without proceeding.
1521 TEST_F(WebContentsImplTest
,
1522 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1523 // Navigate to a page.
1524 GURL
url1("http://www.google.com");
1525 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1526 EXPECT_EQ(1, controller().GetEntryCount());
1528 // Initiate a browser navigation that will trigger the interstitial.
1529 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1530 ui::PAGE_TRANSITION_TYPED
, std::string());
1531 NavigationEntry
* entry
= controller().GetPendingEntry();
1533 // Show an interstitial.
1534 TestInterstitialPage::InterstitialState state
=
1535 TestInterstitialPage::INVALID
;
1536 bool deleted
= false;
1537 GURL
url2("http://interstitial");
1538 TestInterstitialPage
* interstitial
=
1539 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1540 TestInterstitialPageStateGuard
state_guard(interstitial
);
1541 interstitial
->Show();
1542 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1543 // The interstitial should not show until its navigation has committed.
1544 EXPECT_FALSE(interstitial
->is_showing());
1545 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1546 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1547 // Let's commit the interstitial navigation.
1548 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1549 EXPECT_TRUE(interstitial
->is_showing());
1550 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1551 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1552 entry
= controller().GetVisibleEntry();
1553 ASSERT_NE(nullptr, entry
);
1554 EXPECT_TRUE(entry
->GetURL() == url2
);
1556 // Now don't proceed.
1557 interstitial
->DontProceed();
1558 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1559 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1560 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1561 entry
= controller().GetVisibleEntry();
1562 ASSERT_NE(nullptr, entry
);
1563 EXPECT_TRUE(entry
->GetURL() == url1
);
1564 EXPECT_EQ(1, controller().GetEntryCount());
1566 RunAllPendingInMessageLoop();
1567 EXPECT_TRUE(deleted
);
1570 // Test navigating to a page (with the navigation initiated from the renderer,
1571 // as when clicking on a link in the page) that shows an interstitial and
1572 // creates a new navigation entry, then hiding it without proceeding.
1573 TEST_F(WebContentsImplTest
,
1574 ShowInterstitialFromRendererWithNewNavigationDontProceed
) {
1575 // Navigate to a page.
1576 GURL
url1("http://www.google.com");
1577 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1578 EXPECT_EQ(1, controller().GetEntryCount());
1580 // Show an interstitial (no pending entry, the interstitial would have been
1581 // triggered by clicking on a link).
1582 TestInterstitialPage::InterstitialState state
=
1583 TestInterstitialPage::INVALID
;
1584 bool deleted
= false;
1585 GURL
url2("http://interstitial");
1586 TestInterstitialPage
* interstitial
=
1587 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1588 TestInterstitialPageStateGuard
state_guard(interstitial
);
1589 interstitial
->Show();
1590 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1591 // The interstitial should not show until its navigation has committed.
1592 EXPECT_FALSE(interstitial
->is_showing());
1593 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1594 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1595 // Let's commit the interstitial navigation.
1596 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1597 EXPECT_TRUE(interstitial
->is_showing());
1598 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1599 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1600 NavigationEntry
* entry
= controller().GetVisibleEntry();
1601 ASSERT_NE(nullptr, entry
);
1602 EXPECT_TRUE(entry
->GetURL() == url2
);
1604 // Now don't proceed.
1605 interstitial
->DontProceed();
1606 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1607 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1608 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1609 entry
= controller().GetVisibleEntry();
1610 ASSERT_NE(nullptr, entry
);
1611 EXPECT_TRUE(entry
->GetURL() == url1
);
1612 EXPECT_EQ(1, controller().GetEntryCount());
1614 RunAllPendingInMessageLoop();
1615 EXPECT_TRUE(deleted
);
1618 // Test navigating to a page that shows an interstitial without creating a new
1619 // navigation entry (this happens when the interstitial is triggered by a
1620 // sub-resource in the page), then hiding it without proceeding.
1621 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1622 // Navigate to a page.
1623 GURL
url1("http://www.google.com");
1624 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1625 EXPECT_EQ(1, controller().GetEntryCount());
1627 // Show an interstitial.
1628 TestInterstitialPage::InterstitialState state
=
1629 TestInterstitialPage::INVALID
;
1630 bool deleted
= false;
1631 GURL
url2("http://interstitial");
1632 TestInterstitialPage
* interstitial
=
1633 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1634 TestInterstitialPageStateGuard
state_guard(interstitial
);
1635 interstitial
->Show();
1636 // The interstitial should not show until its navigation has committed.
1637 EXPECT_FALSE(interstitial
->is_showing());
1638 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1639 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1640 // Let's commit the interstitial navigation.
1641 interstitial
->TestDidNavigate(1, 0, true, url2
);
1642 EXPECT_TRUE(interstitial
->is_showing());
1643 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1644 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1645 NavigationEntry
* entry
= controller().GetVisibleEntry();
1646 ASSERT_NE(nullptr, entry
);
1647 // The URL specified to the interstitial should have been ignored.
1648 EXPECT_TRUE(entry
->GetURL() == url1
);
1650 // Now don't proceed.
1651 interstitial
->DontProceed();
1652 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1653 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1654 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1655 entry
= controller().GetVisibleEntry();
1656 ASSERT_NE(nullptr, entry
);
1657 EXPECT_TRUE(entry
->GetURL() == url1
);
1658 EXPECT_EQ(1, controller().GetEntryCount());
1660 RunAllPendingInMessageLoop();
1661 EXPECT_TRUE(deleted
);
1664 // Test navigating to a page (with the navigation initiated from the browser,
1665 // as when a URL is typed in the location bar) that shows an interstitial and
1666 // creates a new navigation entry, then proceeding.
1667 TEST_F(WebContentsImplTest
,
1668 ShowInterstitialFromBrowserNewNavigationProceed
) {
1669 // Navigate to a page.
1670 GURL
url1("http://www.google.com");
1671 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1672 EXPECT_EQ(1, controller().GetEntryCount());
1674 // Initiate a browser navigation that will trigger the interstitial
1675 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1676 ui::PAGE_TRANSITION_TYPED
, std::string());
1678 // Show an interstitial.
1679 TestInterstitialPage::InterstitialState state
=
1680 TestInterstitialPage::INVALID
;
1681 bool deleted
= false;
1682 GURL
url2("http://interstitial");
1683 TestInterstitialPage
* interstitial
=
1684 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1685 TestInterstitialPageStateGuard
state_guard(interstitial
);
1686 interstitial
->Show();
1687 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1688 // The interstitial should not show until its navigation has committed.
1689 EXPECT_FALSE(interstitial
->is_showing());
1690 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1691 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1692 // Let's commit the interstitial navigation.
1693 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1694 EXPECT_TRUE(interstitial
->is_showing());
1695 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1696 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1697 NavigationEntry
* entry
= controller().GetVisibleEntry();
1698 ASSERT_NE(nullptr, entry
);
1699 EXPECT_TRUE(entry
->GetURL() == url2
);
1702 interstitial
->Proceed();
1703 // The interstitial should show until the new navigation commits.
1704 RunAllPendingInMessageLoop();
1705 ASSERT_FALSE(deleted
);
1706 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1707 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1708 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1710 // Simulate the navigation to the page, that's when the interstitial gets
1712 GURL
url3("http://www.thepage.com");
1713 contents()->GetMainFrame()->PrepareForCommit();
1714 contents()->GetMainFrame()->SendNavigate(2, 0, true, url3
);
1716 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1717 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1718 entry
= controller().GetVisibleEntry();
1719 ASSERT_NE(nullptr, entry
);
1720 EXPECT_TRUE(entry
->GetURL() == url3
);
1722 EXPECT_EQ(2, controller().GetEntryCount());
1724 RunAllPendingInMessageLoop();
1725 EXPECT_TRUE(deleted
);
1728 // Test navigating to a page (with the navigation initiated from the renderer,
1729 // as when clicking on a link in the page) that shows an interstitial and
1730 // creates a new navigation entry, then proceeding.
1731 TEST_F(WebContentsImplTest
,
1732 ShowInterstitialFromRendererNewNavigationProceed
) {
1733 // Navigate to a page.
1734 GURL
url1("http://www.google.com");
1735 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1736 EXPECT_EQ(1, controller().GetEntryCount());
1738 // Show an interstitial.
1739 TestInterstitialPage::InterstitialState state
=
1740 TestInterstitialPage::INVALID
;
1741 bool deleted
= false;
1742 GURL
url2("http://interstitial");
1743 TestInterstitialPage
* interstitial
=
1744 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1745 TestInterstitialPageStateGuard
state_guard(interstitial
);
1746 interstitial
->Show();
1747 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1748 // The interstitial should not show until its navigation has committed.
1749 EXPECT_FALSE(interstitial
->is_showing());
1750 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1751 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1752 // Let's commit the interstitial navigation.
1753 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1754 EXPECT_TRUE(interstitial
->is_showing());
1755 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1756 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1757 NavigationEntry
* entry
= controller().GetVisibleEntry();
1758 ASSERT_NE(nullptr, entry
);
1759 EXPECT_TRUE(entry
->GetURL() == url2
);
1762 interstitial
->Proceed();
1763 // The interstitial should show until the new navigation commits.
1764 RunAllPendingInMessageLoop();
1765 ASSERT_FALSE(deleted
);
1766 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1767 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1768 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1770 // Simulate the navigation to the page, that's when the interstitial gets
1772 GURL
url3("http://www.thepage.com");
1773 main_test_rfh()->NavigateAndCommitRendererInitiated(2, true, url3
);
1775 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1776 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1777 entry
= controller().GetVisibleEntry();
1778 ASSERT_NE(nullptr, entry
);
1779 EXPECT_TRUE(entry
->GetURL() == url3
);
1781 EXPECT_EQ(2, controller().GetEntryCount());
1783 RunAllPendingInMessageLoop();
1784 EXPECT_TRUE(deleted
);
1787 // Test navigating to a page that shows an interstitial without creating a new
1788 // navigation entry (this happens when the interstitial is triggered by a
1789 // sub-resource in the page), then proceeding.
1790 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1791 // Navigate to a page so we have a navigation entry in the controller.
1792 GURL
url1("http://www.google.com");
1793 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1794 EXPECT_EQ(1, controller().GetEntryCount());
1796 // Show an interstitial.
1797 TestInterstitialPage::InterstitialState state
=
1798 TestInterstitialPage::INVALID
;
1799 bool deleted
= false;
1800 GURL
url2("http://interstitial");
1801 TestInterstitialPage
* interstitial
=
1802 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1803 TestInterstitialPageStateGuard
state_guard(interstitial
);
1804 interstitial
->Show();
1805 // The interstitial should not show until its navigation has committed.
1806 EXPECT_FALSE(interstitial
->is_showing());
1807 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1808 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1809 // Let's commit the interstitial navigation.
1810 interstitial
->TestDidNavigate(1, 0, true, url2
);
1811 EXPECT_TRUE(interstitial
->is_showing());
1812 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1813 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1814 NavigationEntry
* entry
= controller().GetVisibleEntry();
1815 ASSERT_NE(nullptr, entry
);
1816 // The URL specified to the interstitial should have been ignored.
1817 EXPECT_TRUE(entry
->GetURL() == url1
);
1820 interstitial
->Proceed();
1821 // Since this is not a new navigation, the previous page is dismissed right
1822 // away and shows the original page.
1823 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1824 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1825 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1826 entry
= controller().GetVisibleEntry();
1827 ASSERT_NE(nullptr, entry
);
1828 EXPECT_TRUE(entry
->GetURL() == url1
);
1830 EXPECT_EQ(1, controller().GetEntryCount());
1832 RunAllPendingInMessageLoop();
1833 EXPECT_TRUE(deleted
);
1836 // Test navigating to a page that shows an interstitial, then navigating away.
1837 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1838 // Show interstitial.
1839 TestInterstitialPage::InterstitialState state
=
1840 TestInterstitialPage::INVALID
;
1841 bool deleted
= false;
1842 GURL
url("http://interstitial");
1843 TestInterstitialPage
* interstitial
=
1844 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1845 TestInterstitialPageStateGuard
state_guard(interstitial
);
1846 interstitial
->Show();
1847 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1848 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
1850 // While interstitial showing, navigate to a new URL.
1851 const GURL
url2("http://www.yahoo.com");
1852 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2
);
1854 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1856 RunAllPendingInMessageLoop();
1857 EXPECT_TRUE(deleted
);
1860 // Test navigating to a page that shows an interstitial, then going back.
1861 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1862 // Navigate to a page so we have a navigation entry in the controller.
1863 GURL
url1("http://www.google.com");
1864 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1865 EXPECT_EQ(1, controller().GetEntryCount());
1866 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1868 // Show interstitial.
1869 TestInterstitialPage::InterstitialState state
=
1870 TestInterstitialPage::INVALID
;
1871 bool deleted
= false;
1872 GURL
interstitial_url("http://interstitial");
1873 TestInterstitialPage
* interstitial
=
1874 new TestInterstitialPage(contents(), true, interstitial_url
,
1876 TestInterstitialPageStateGuard
state_guard(interstitial
);
1877 interstitial
->Show();
1878 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1879 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1882 // While the interstitial is showing, go back.
1883 controller().GoBack();
1884 main_test_rfh()->PrepareForCommit();
1885 contents()->GetMainFrame()->SendNavigate(1, entry
->GetUniqueID(), false,
1888 // Make sure we are back to the original page and that the interstitial is
1890 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1891 entry
= controller().GetVisibleEntry();
1893 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1895 RunAllPendingInMessageLoop();
1896 EXPECT_TRUE(deleted
);
1899 // Test navigating to a page that shows an interstitial, has a renderer crash,
1900 // and then goes back.
1901 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1902 // Navigate to a page so we have a navigation entry in the controller.
1903 GURL
url1("http://www.google.com");
1904 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1905 EXPECT_EQ(1, controller().GetEntryCount());
1906 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1908 // Show interstitial.
1909 TestInterstitialPage::InterstitialState state
=
1910 TestInterstitialPage::INVALID
;
1911 bool deleted
= false;
1912 GURL
interstitial_url("http://interstitial");
1913 TestInterstitialPage
* interstitial
=
1914 new TestInterstitialPage(contents(), true, interstitial_url
,
1916 TestInterstitialPageStateGuard
state_guard(interstitial
);
1917 interstitial
->Show();
1918 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1919 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1922 // Crash the renderer
1923 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1925 // While the interstitial is showing, go back. This will dismiss the
1926 // interstitial and not initiate a navigation, but just show the existing
1928 controller().GoBack();
1930 // Make sure we are back to the original page and that the interstitial is
1932 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1933 entry
= controller().GetVisibleEntry();
1935 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1937 RunAllPendingInMessageLoop();
1938 EXPECT_TRUE(deleted
);
1941 // Test navigating to a page that shows an interstitial, has the renderer crash,
1942 // and then navigates to the interstitial.
1943 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1944 // Navigate to a page so we have a navigation entry in the controller.
1945 GURL
url1("http://www.google.com");
1946 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1947 EXPECT_EQ(1, controller().GetEntryCount());
1949 // Show interstitial.
1950 TestInterstitialPage::InterstitialState state
=
1951 TestInterstitialPage::INVALID
;
1952 bool deleted
= false;
1953 GURL
interstitial_url("http://interstitial");
1954 TestInterstitialPage
* interstitial
=
1955 new TestInterstitialPage(contents(), true, interstitial_url
,
1957 TestInterstitialPageStateGuard
state_guard(interstitial
);
1958 interstitial
->Show();
1959 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1961 // Crash the renderer
1962 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1964 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1968 // Test navigating to a page that shows an interstitial, then close the
1970 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1971 // Show interstitial.
1972 TestInterstitialPage::InterstitialState state
=
1973 TestInterstitialPage::INVALID
;
1974 bool deleted
= false;
1975 GURL
url("http://interstitial");
1976 TestInterstitialPage
* interstitial
=
1977 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1978 TestInterstitialPageStateGuard
state_guard(interstitial
);
1979 interstitial
->Show();
1980 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1981 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
1983 // Now close the contents.
1985 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1987 RunAllPendingInMessageLoop();
1988 EXPECT_TRUE(deleted
);
1991 // Test navigating to a page that shows an interstitial, then close the
1993 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
1994 // Show interstitial.
1995 TestInterstitialPage::InterstitialState state
=
1996 TestInterstitialPage::INVALID
;
1997 bool deleted
= false;
1998 GURL
url("http://interstitial");
1999 TestInterstitialPage
* interstitial
=
2000 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2001 TestInterstitialPageStateGuard
state_guard(interstitial
);
2002 interstitial
->Show();
2003 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2004 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2005 TestRenderFrameHost
* rfh
=
2006 static_cast<TestRenderFrameHost
*>(interstitial
->GetMainFrame());
2008 // Now close the contents.
2010 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2012 // Before the interstitial has a chance to process its shutdown task,
2013 // simulate quitting the browser. This goes through all processes and
2014 // tells them to destruct.
2015 rfh
->GetProcess()->SimulateCrash();
2017 RunAllPendingInMessageLoop();
2018 EXPECT_TRUE(deleted
);
2021 // Test that after Proceed is called and an interstitial is still shown, no more
2022 // commands get executed.
2023 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
2024 // Navigate to a page so we have a navigation entry in the controller.
2025 GURL
url1("http://www.google.com");
2026 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2027 EXPECT_EQ(1, controller().GetEntryCount());
2029 // Show an interstitial.
2030 TestInterstitialPage::InterstitialState state
=
2031 TestInterstitialPage::INVALID
;
2032 bool deleted
= false;
2033 GURL
url2("http://interstitial");
2034 TestInterstitialPage
* interstitial
=
2035 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2036 TestInterstitialPageStateGuard
state_guard(interstitial
);
2037 interstitial
->Show();
2038 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2039 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2042 EXPECT_EQ(0, interstitial
->command_received_count());
2043 interstitial
->TestDomOperationResponse("toto");
2044 EXPECT_EQ(1, interstitial
->command_received_count());
2047 interstitial
->Proceed();
2048 RunAllPendingInMessageLoop();
2049 ASSERT_FALSE(deleted
);
2051 // While the navigation to the new page is pending, send other commands, they
2052 // should be ignored.
2053 interstitial
->TestDomOperationResponse("hello");
2054 interstitial
->TestDomOperationResponse("hi");
2055 EXPECT_EQ(1, interstitial
->command_received_count());
2058 // Test showing an interstitial while another interstitial is already showing.
2059 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
2060 // Navigate to a page so we have a navigation entry in the controller.
2061 GURL
start_url("http://www.google.com");
2062 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2063 EXPECT_EQ(1, controller().GetEntryCount());
2065 // Show an interstitial.
2066 TestInterstitialPage::InterstitialState state1
=
2067 TestInterstitialPage::INVALID
;
2068 bool deleted1
= false;
2069 GURL
url1("http://interstitial1");
2070 TestInterstitialPage
* interstitial1
=
2071 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2072 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2073 interstitial1
->Show();
2074 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2075 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2077 // Now show another interstitial.
2078 TestInterstitialPage::InterstitialState state2
=
2079 TestInterstitialPage::INVALID
;
2080 bool deleted2
= false;
2081 GURL
url2("http://interstitial2");
2082 TestInterstitialPage
* interstitial2
=
2083 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2084 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2085 interstitial2
->Show();
2086 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2087 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2089 // Showing interstitial2 should have caused interstitial1 to go away.
2090 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2091 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2093 RunAllPendingInMessageLoop();
2094 EXPECT_TRUE(deleted1
);
2095 ASSERT_FALSE(deleted2
);
2097 // Let's make sure interstitial2 is working as intended.
2098 interstitial2
->Proceed();
2099 GURL
landing_url("http://www.thepage.com");
2100 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2102 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2103 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2104 NavigationEntry
* entry
= controller().GetVisibleEntry();
2105 ASSERT_NE(nullptr, entry
);
2106 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2107 EXPECT_EQ(2, controller().GetEntryCount());
2108 RunAllPendingInMessageLoop();
2109 EXPECT_TRUE(deleted2
);
2112 // Test showing an interstitial, proceeding and then navigating to another
2114 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2115 // Navigate to a page so we have a navigation entry in the controller.
2116 GURL
start_url("http://www.google.com");
2117 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2118 EXPECT_EQ(1, controller().GetEntryCount());
2120 // Show an interstitial.
2121 TestInterstitialPage::InterstitialState state1
=
2122 TestInterstitialPage::INVALID
;
2123 bool deleted1
= false;
2124 GURL
url1("http://interstitial1");
2125 TestInterstitialPage
* interstitial1
=
2126 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2127 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2128 interstitial1
->Show();
2129 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2130 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2132 // Take action. The interstitial won't be hidden until the navigation is
2134 interstitial1
->Proceed();
2135 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2137 // Now show another interstitial (simulating the navigation causing another
2139 TestInterstitialPage::InterstitialState state2
=
2140 TestInterstitialPage::INVALID
;
2141 bool deleted2
= false;
2142 GURL
url2("http://interstitial2");
2143 TestInterstitialPage
* interstitial2
=
2144 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2145 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2146 interstitial2
->Show();
2147 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2148 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2150 // Showing interstitial2 should have caused interstitial1 to go away.
2151 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2152 RunAllPendingInMessageLoop();
2153 EXPECT_TRUE(deleted1
);
2154 ASSERT_FALSE(deleted2
);
2156 // Let's make sure interstitial2 is working as intended.
2157 interstitial2
->Proceed();
2158 GURL
landing_url("http://www.thepage.com");
2159 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2161 RunAllPendingInMessageLoop();
2162 EXPECT_TRUE(deleted2
);
2163 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2164 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2165 NavigationEntry
* entry
= controller().GetVisibleEntry();
2166 ASSERT_NE(nullptr, entry
);
2167 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2168 EXPECT_EQ(2, controller().GetEntryCount());
2171 // Test that navigating away from an interstitial while it's loading cause it
2173 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2174 // Show an interstitial.
2175 TestInterstitialPage::InterstitialState state
=
2176 TestInterstitialPage::INVALID
;
2177 bool deleted
= false;
2178 GURL
interstitial_url("http://interstitial");
2179 TestInterstitialPage
* interstitial
=
2180 new TestInterstitialPage(contents(), true, interstitial_url
,
2182 TestInterstitialPageStateGuard
state_guard(interstitial
);
2183 interstitial
->Show();
2184 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2186 // Let's simulate a navigation initiated from the browser before the
2187 // interstitial finishes loading.
2188 const GURL
url("http://www.google.com");
2189 controller().LoadURL(
2190 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2191 EXPECT_FALSE(interstitial
->is_showing());
2192 RunAllPendingInMessageLoop();
2193 ASSERT_FALSE(deleted
);
2195 // Now let's make the interstitial navigation commit.
2196 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true,
2199 // After it loaded the interstitial should be gone.
2200 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2202 RunAllPendingInMessageLoop();
2203 EXPECT_TRUE(deleted
);
2206 // Test that a new request to show an interstitial while an interstitial is
2207 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2208 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2209 GURL
interstitial_url("http://interstitial");
2211 // Show a first interstitial.
2212 TestInterstitialPage::InterstitialState state1
=
2213 TestInterstitialPage::INVALID
;
2214 bool deleted1
= false;
2215 TestInterstitialPage
* interstitial1
=
2216 new TestInterstitialPage(contents(), true, interstitial_url
,
2217 &state1
, &deleted1
);
2218 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2219 interstitial1
->Show();
2221 // Show another interstitial on that same contents before the first one had
2223 TestInterstitialPage::InterstitialState state2
=
2224 TestInterstitialPage::INVALID
;
2225 bool deleted2
= false;
2226 TestInterstitialPage
* interstitial2
=
2227 new TestInterstitialPage(contents(), true, interstitial_url
,
2228 &state2
, &deleted2
);
2229 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2230 interstitial2
->Show();
2231 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2233 // The first interstitial should have been closed and deleted.
2234 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2235 // The 2nd one should still be OK.
2236 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2238 RunAllPendingInMessageLoop();
2239 EXPECT_TRUE(deleted1
);
2240 ASSERT_FALSE(deleted2
);
2242 // Make the interstitial navigation commit it should be showing.
2243 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true,
2245 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2248 // Test showing an interstitial and have its renderer crash.
2249 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2250 // Show an interstitial.
2251 TestInterstitialPage::InterstitialState state
=
2252 TestInterstitialPage::INVALID
;
2253 bool deleted
= false;
2254 GURL
url("http://interstitial");
2255 TestInterstitialPage
* interstitial
=
2256 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2257 TestInterstitialPageStateGuard
state_guard(interstitial
);
2258 interstitial
->Show();
2259 // Simulate a renderer crash before the interstitial is shown.
2260 interstitial
->TestRenderViewTerminated(
2261 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2262 // The interstitial should have been dismissed.
2263 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2264 RunAllPendingInMessageLoop();
2265 EXPECT_TRUE(deleted
);
2267 // Now try again but this time crash the intersitial after it was shown.
2269 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2270 interstitial
->Show();
2271 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2272 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2273 // Simulate a renderer crash.
2274 interstitial
->TestRenderViewTerminated(
2275 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2276 // The interstitial should have been dismissed.
2277 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2278 RunAllPendingInMessageLoop();
2279 EXPECT_TRUE(deleted
);
2282 // Tests that showing an interstitial as a result of a browser initiated
2283 // navigation while an interstitial is showing does not remove the pending
2284 // entry (see http://crbug.com/9791).
2285 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2286 const char kUrl
[] = "http://www.badguys.com/";
2287 const GURL
kGURL(kUrl
);
2289 // Start a navigation to a page
2290 contents()->GetController().LoadURL(
2291 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2293 // Simulate that navigation triggering an interstitial.
2294 TestInterstitialPage::InterstitialState state
=
2295 TestInterstitialPage::INVALID
;
2296 bool deleted
= false;
2297 TestInterstitialPage
* interstitial
=
2298 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2299 TestInterstitialPageStateGuard
state_guard(interstitial
);
2300 interstitial
->Show();
2301 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2302 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2304 // Initiate a new navigation from the browser that also triggers an
2306 contents()->GetController().LoadURL(
2307 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2308 TestInterstitialPage::InterstitialState state2
=
2309 TestInterstitialPage::INVALID
;
2310 bool deleted2
= false;
2311 TestInterstitialPage
* interstitial2
=
2312 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2313 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2314 interstitial2
->Show();
2315 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2316 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2318 // Make sure we still have an entry.
2319 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2321 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2323 // And that the first interstitial is gone, but not the second.
2324 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2325 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2326 RunAllPendingInMessageLoop();
2327 EXPECT_TRUE(deleted
);
2328 EXPECT_FALSE(deleted2
);
2331 // Tests that Javascript messages are not shown while an interstitial is
2333 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2334 const char kUrl
[] = "http://www.badguys.com/";
2335 const GURL
kGURL(kUrl
);
2337 // Start a navigation to a page
2338 contents()->GetController().LoadURL(
2339 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2340 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2341 main_test_rfh()->PrepareForCommit();
2342 // DidNavigate from the page
2343 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
2344 kGURL
, ui::PAGE_TRANSITION_TYPED
);
2346 // Simulate showing an interstitial while the page is showing.
2347 TestInterstitialPage::InterstitialState state
=
2348 TestInterstitialPage::INVALID
;
2349 bool deleted
= false;
2350 TestInterstitialPage
* interstitial
=
2351 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2352 TestInterstitialPageStateGuard
state_guard(interstitial
);
2353 interstitial
->Show();
2354 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2355 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2357 // While the interstitial is showing, let's simulate the hidden page
2358 // attempting to show a JS message.
2359 IPC::Message
* dummy_message
= new IPC::Message
;
2360 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2361 base::ASCIIToUTF16("This is an informative message"),
2362 base::ASCIIToUTF16("OK"),
2363 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2364 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2367 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2368 // interstitial it isn't copied over to the destination.
2369 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2370 // Navigate to a page.
2371 GURL
url1("http://www.google.com");
2372 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2373 EXPECT_EQ(1, controller().GetEntryCount());
2375 // Initiate a browser navigation that will trigger the interstitial
2376 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2377 ui::PAGE_TRANSITION_TYPED
, std::string());
2379 // Show an interstitial.
2380 TestInterstitialPage::InterstitialState state
=
2381 TestInterstitialPage::INVALID
;
2382 bool deleted
= false;
2383 GURL
url2("http://interstitial");
2384 TestInterstitialPage
* interstitial
=
2385 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2386 TestInterstitialPageStateGuard
state_guard(interstitial
);
2387 interstitial
->Show();
2388 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2389 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2390 EXPECT_TRUE(interstitial
->is_showing());
2391 EXPECT_EQ(2, controller().GetEntryCount());
2393 // Create another NavigationController.
2394 GURL
url3("http://foo2");
2395 scoped_ptr
<TestWebContents
> other_contents(
2396 static_cast<TestWebContents
*>(CreateTestWebContents()));
2397 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2398 other_contents
->NavigateAndCommit(url3
);
2399 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
2400 other_controller
.CopyStateFromAndPrune(&controller(), false);
2402 // The merged controller should only have two entries: url1 and url2.
2403 ASSERT_EQ(2, other_controller
.GetEntryCount());
2404 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2405 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2406 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2408 // And the merged controller shouldn't be showing an interstitial.
2409 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2412 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2413 // showing an interstitial.
2414 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2415 // Navigate to a page.
2416 GURL
url1("http://www.google.com");
2417 contents()->NavigateAndCommit(url1
);
2419 // Create another NavigationController.
2420 scoped_ptr
<TestWebContents
> other_contents(
2421 static_cast<TestWebContents
*>(CreateTestWebContents()));
2422 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2424 // Navigate it to url2.
2425 GURL
url2("http://foo2");
2426 other_contents
->NavigateAndCommit(url2
);
2428 // Show an interstitial.
2429 TestInterstitialPage::InterstitialState state
=
2430 TestInterstitialPage::INVALID
;
2431 bool deleted
= false;
2432 GURL
url3("http://interstitial");
2433 TestInterstitialPage
* interstitial
=
2434 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2436 TestInterstitialPageStateGuard
state_guard(interstitial
);
2437 interstitial
->Show();
2438 int interstitial_entry_id
=
2439 other_controller
.GetTransientEntry()->GetUniqueID();
2440 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url3
);
2441 EXPECT_TRUE(interstitial
->is_showing());
2442 EXPECT_EQ(2, other_controller
.GetEntryCount());
2444 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2445 // interstitial is showing in the target.
2446 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2449 // Regression test for http://crbug.com/168611 - the URLs passed by the
2450 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2451 TEST_F(WebContentsImplTest
, FilterURLs
) {
2452 TestWebContentsObserver
observer(contents());
2454 // A navigation to about:whatever should always look like a navigation to
2456 GURL
url_normalized(url::kAboutBlankURL
);
2457 GURL
url_from_ipc("about:whatever");
2459 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2460 // will use the given URL to create the NavigationEntry as well, and that
2461 // entry should contain the filtered URL.
2462 contents()->NavigateAndCommit(url_normalized
);
2464 // Check that an IPC with about:whatever is correctly normalized.
2465 contents()->TestDidFinishLoad(url_from_ipc
);
2467 EXPECT_EQ(url_normalized
, observer
.last_url());
2469 // Create and navigate another WebContents.
2470 scoped_ptr
<TestWebContents
> other_contents(
2471 static_cast<TestWebContents
*>(CreateTestWebContents()));
2472 TestWebContentsObserver
other_observer(other_contents
.get());
2473 other_contents
->NavigateAndCommit(url_normalized
);
2475 // Check that an IPC with about:whatever is correctly normalized.
2476 other_contents
->TestDidFailLoadWithError(
2477 url_from_ipc
, 1, base::string16());
2478 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2481 // Test that if a pending contents is deleted before it is shown, we don't
2483 TEST_F(WebContentsImplTest
, PendingContents
) {
2484 scoped_ptr
<TestWebContents
> other_contents(
2485 static_cast<TestWebContents
*>(CreateTestWebContents()));
2486 contents()->AddPendingContents(other_contents
.get());
2487 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2488 other_contents
.reset();
2489 EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id
));
2492 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2493 const gfx::Size
original_preferred_size(1024, 768);
2494 contents()->UpdatePreferredSize(original_preferred_size
);
2496 // With no capturers, expect the preferred size to be the one propagated into
2497 // WebContentsImpl via the RenderViewHostDelegate interface.
2498 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2499 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2501 // Increment capturer count, but without specifying a capture size. Expect
2502 // a "not set" preferred size.
2503 contents()->IncrementCapturerCount(gfx::Size());
2504 EXPECT_EQ(1, contents()->GetCapturerCount());
2505 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2507 // Increment capturer count again, but with an overriding capture size.
2508 // Expect preferred size to now be overridden to the capture size.
2509 const gfx::Size
capture_size(1280, 720);
2510 contents()->IncrementCapturerCount(capture_size
);
2511 EXPECT_EQ(2, contents()->GetCapturerCount());
2512 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2514 // Increment capturer count a third time, but the expect that the preferred
2515 // size is still the first capture size.
2516 const gfx::Size
another_capture_size(720, 480);
2517 contents()->IncrementCapturerCount(another_capture_size
);
2518 EXPECT_EQ(3, contents()->GetCapturerCount());
2519 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2521 // Decrement capturer count twice, but expect the preferred size to still be
2523 contents()->DecrementCapturerCount();
2524 contents()->DecrementCapturerCount();
2525 EXPECT_EQ(1, contents()->GetCapturerCount());
2526 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2528 // Decrement capturer count, and since the count has dropped to zero, the
2529 // original preferred size should be restored.
2530 contents()->DecrementCapturerCount();
2531 EXPECT_EQ(0, contents()->GetCapturerCount());
2532 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2535 TEST_F(WebContentsImplTest
, CapturerPreventsHiding
) {
2536 const gfx::Size
original_preferred_size(1024, 768);
2537 contents()->UpdatePreferredSize(original_preferred_size
);
2539 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2540 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2542 // With no capturers, setting and un-setting occlusion should change the
2543 // view's occlusion state.
2544 EXPECT_FALSE(view
->is_showing());
2545 contents()->WasShown();
2546 EXPECT_TRUE(view
->is_showing());
2547 contents()->WasHidden();
2548 EXPECT_FALSE(view
->is_showing());
2549 contents()->WasShown();
2550 EXPECT_TRUE(view
->is_showing());
2552 // Add a capturer and try to hide the contents. The view will remain visible.
2553 contents()->IncrementCapturerCount(gfx::Size());
2554 contents()->WasHidden();
2555 EXPECT_TRUE(view
->is_showing());
2557 // Remove the capturer, and the WasHidden should take effect.
2558 contents()->DecrementCapturerCount();
2559 EXPECT_FALSE(view
->is_showing());
2562 TEST_F(WebContentsImplTest
, CapturerPreventsOcclusion
) {
2563 const gfx::Size
original_preferred_size(1024, 768);
2564 contents()->UpdatePreferredSize(original_preferred_size
);
2566 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2567 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2569 // With no capturers, setting and un-setting occlusion should change the
2570 // view's occlusion state.
2571 EXPECT_FALSE(view
->is_occluded());
2572 contents()->WasOccluded();
2573 EXPECT_TRUE(view
->is_occluded());
2574 contents()->WasUnOccluded();
2575 EXPECT_FALSE(view
->is_occluded());
2576 contents()->WasOccluded();
2577 EXPECT_TRUE(view
->is_occluded());
2579 // Add a capturer. This should cause the view to be un-occluded.
2580 contents()->IncrementCapturerCount(gfx::Size());
2581 EXPECT_FALSE(view
->is_occluded());
2583 // Try to occlude the view. This will fail to propagate because of the
2585 contents()->WasOccluded();
2586 EXPECT_FALSE(view
->is_occluded());
2588 // Remove the capturer and try again.
2589 contents()->DecrementCapturerCount();
2590 EXPECT_FALSE(view
->is_occluded());
2591 contents()->WasOccluded();
2592 EXPECT_TRUE(view
->is_occluded());
2595 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2597 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2598 // The WebContents starts with a valid creation time.
2599 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2601 // Reset the last active time to a known-bad value.
2602 contents()->last_active_time_
= base::TimeTicks();
2603 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2605 // Simulate activating the WebContents. The active time should update.
2606 contents()->WasShown();
2607 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2610 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2612 ContentsZoomChangedDelegate() :
2613 contents_zoom_changed_call_count_(0),
2614 last_zoom_in_(false) {
2617 int GetAndResetContentsZoomChangedCallCount() {
2618 int count
= contents_zoom_changed_call_count_
;
2619 contents_zoom_changed_call_count_
= 0;
2623 bool last_zoom_in() const {
2624 return last_zoom_in_
;
2627 // WebContentsDelegate:
2628 void ContentsZoomChange(bool zoom_in
) override
{
2629 contents_zoom_changed_call_count_
++;
2630 last_zoom_in_
= zoom_in
;
2634 int contents_zoom_changed_call_count_
;
2637 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2640 // Tests that some mouseehweel events get turned into browser zoom requests.
2641 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2642 using blink::WebInputEvent
;
2644 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2645 new ContentsZoomChangedDelegate());
2646 contents()->SetDelegate(delegate
.get());
2649 // Verify that normal mouse wheel events do nothing to change the zoom level.
2650 blink::WebMouseWheelEvent event
=
2651 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2652 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2653 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2655 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
|
2656 WebInputEvent::ControlKey
;
2657 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2658 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2659 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2661 // But whenever the ctrl modifier is applied with canScroll=false, they can
2662 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2664 modifiers
= WebInputEvent::ControlKey
;
2665 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2666 event
.canScroll
= false;
2667 bool handled
= contents()->HandleWheelEvent(event
);
2668 #if defined(OS_MACOSX)
2669 EXPECT_FALSE(handled
);
2670 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2672 EXPECT_TRUE(handled
);
2673 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2674 EXPECT_TRUE(delegate
->last_zoom_in());
2677 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2678 WebInputEvent::AltKey
;
2679 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2680 event
.canScroll
= false;
2681 handled
= contents()->HandleWheelEvent(event
);
2682 #if defined(OS_MACOSX)
2683 EXPECT_FALSE(handled
);
2684 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2686 EXPECT_TRUE(handled
);
2687 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2688 EXPECT_FALSE(delegate
->last_zoom_in());
2691 // Unless there is no vertical movement.
2692 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2693 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2694 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2696 // Events containing precise scrolling deltas also shouldn't result in the
2697 // zoom being adjusted, to avoid accidental adjustments caused by
2698 // two-finger-scrolling on a touchpad.
2699 modifiers
= WebInputEvent::ControlKey
;
2700 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2701 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2702 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2704 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2705 contents()->SetDelegate(nullptr);
2708 // Tests that GetRelatedActiveContentsCount is shared between related
2709 // SiteInstances and includes WebContents that have not navigated yet.
2710 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2711 scoped_refptr
<SiteInstance
> instance1(
2712 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2713 scoped_refptr
<SiteInstance
> instance2(
2714 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2716 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2717 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2719 scoped_ptr
<TestWebContents
> contents1(
2720 TestWebContents::Create(browser_context(), instance1
.get()));
2721 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2722 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2724 scoped_ptr
<TestWebContents
> contents2(
2725 TestWebContents::Create(browser_context(), instance1
.get()));
2726 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2727 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2730 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2731 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2734 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2735 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2738 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2739 // same-site and cross-site navigations.
2740 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2741 scoped_refptr
<SiteInstance
> instance(
2742 SiteInstance::Create(browser_context()));
2744 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2746 scoped_ptr
<TestWebContents
> contents(
2747 TestWebContents::Create(browser_context(), instance
.get()));
2748 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2750 // Navigate to a URL.
2751 contents
->GetController().LoadURL(GURL("http://a.com/1"),
2753 ui::PAGE_TRANSITION_TYPED
,
2755 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2756 contents
->CommitPendingNavigation();
2757 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2759 // Navigate to a URL in the same site.
2760 contents
->GetController().LoadURL(GURL("http://a.com/2"),
2762 ui::PAGE_TRANSITION_TYPED
,
2764 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2765 contents
->CommitPendingNavigation();
2766 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2768 // Navigate to a URL in a different site.
2769 const GURL kUrl
= GURL("http://b.com");
2770 contents
->GetController().LoadURL(kUrl
,
2772 ui::PAGE_TRANSITION_TYPED
,
2774 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2775 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2776 switches::kEnableBrowserSideNavigation
)) {
2777 contents
->GetMainFrame()->PrepareForCommit();
2779 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2780 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2781 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kUrl
);
2782 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2785 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2788 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2790 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2791 scoped_refptr
<SiteInstance
> instance(
2792 SiteInstance::Create(browser_context()));
2794 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2796 scoped_ptr
<TestWebContents
> contents(
2797 TestWebContents::Create(browser_context(), instance
.get()));
2798 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2800 // Navigate to a URL.
2801 contents
->NavigateAndCommit(GURL("http://a.com"));
2802 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2804 // Navigate to a URL which sort of looks like a chrome:// url.
2805 contents
->NavigateAndCommit(GURL("http://gpu"));
2806 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2808 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2809 const GURL kWebUIUrl
= GURL("chrome://gpu");
2810 contents
->GetController().LoadURL(kWebUIUrl
,
2812 ui::PAGE_TRANSITION_TYPED
,
2814 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2815 contents
->GetMainFrame()->PrepareForCommit();
2816 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2817 scoped_refptr
<SiteInstance
> instance_webui(
2818 contents
->GetPendingMainFrame()->GetSiteInstance());
2819 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2821 // At this point, contents still counts for the old BrowsingInstance.
2822 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2823 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2825 // Commit and contents counts for the new one.
2826 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kWebUIUrl
);
2827 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2828 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2831 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2832 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2835 class LoadingWebContentsObserver
: public WebContentsObserver
{
2837 explicit LoadingWebContentsObserver(WebContents
* contents
)
2838 : WebContentsObserver(contents
),
2839 is_loading_(false) {
2841 ~LoadingWebContentsObserver() override
{}
2843 void DidStartLoading() override
{ is_loading_
= true; }
2844 void DidStopLoading() override
{ is_loading_
= false; }
2846 bool is_loading() const { return is_loading_
; }
2851 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver
);
2854 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2855 // interleaving cross-process navigations in multiple subframes.
2856 // See https://crbug.com/448601 for details of the underlying issue. The
2857 // sequence of events that reproduce it are as follows:
2858 // * Navigate top-level frame with one subframe.
2859 // * Subframe navigates more than once before the top-level frame has had a
2860 // chance to complete the load.
2861 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2862 // to 0, while the loading_progresses_ map is not reset.
2863 TEST_F(WebContentsImplTest
, StartStopEventsBalance
) {
2864 // The bug manifests itself in regular mode as well, but browser-initiated
2865 // navigation of subframes is only possible in --site-per-process mode within
2867 base::CommandLine::ForCurrentProcess()->AppendSwitch(
2868 switches::kSitePerProcess
);
2869 const GURL
initial_url("about:blank");
2870 const GURL
main_url("http://www.chromium.org");
2871 const GURL
foo_url("http://foo.chromium.org");
2872 const GURL
bar_url("http://bar.chromium.org");
2873 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
2875 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
2876 LoadingWebContentsObserver
observer(contents());
2878 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
2879 // The frame should still be loading.
2880 controller().LoadURL(
2881 main_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2882 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2883 orig_rfh
->PrepareForCommit();
2884 orig_rfh
->OnMessageReceived(
2885 FrameHostMsg_DidStartLoading(orig_rfh
->GetRoutingID(), false));
2886 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, main_url
,
2887 ui::PAGE_TRANSITION_TYPED
);
2888 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2889 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
2890 EXPECT_TRUE(contents()->IsLoading());
2891 EXPECT_TRUE(observer
.is_loading());
2893 // Create a child frame to navigate multiple times.
2894 TestRenderFrameHost
* subframe
= orig_rfh
->AppendChild("subframe");
2896 // Navigate the child frame to about:blank, which will send both
2897 // DidStartLoading and DidStopLoading messages.
2899 subframe
->SendRendererInitiatedNavigationRequest(initial_url
, false);
2900 subframe
->PrepareForCommit();
2901 subframe
->OnMessageReceived(
2902 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2903 subframe
->SendNavigateWithTransition(1, 0, false, initial_url
,
2904 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2905 subframe
->OnMessageReceived(
2906 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2909 // Navigate the frame to another URL, which will send again
2910 // DidStartLoading and DidStopLoading messages.
2912 subframe
->SendRendererInitiatedNavigationRequest(foo_url
, false);
2913 subframe
->PrepareForCommit();
2914 subframe
->OnMessageReceived(
2915 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2916 subframe
->SendNavigateWithTransition(1, 0, false, foo_url
,
2917 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2918 subframe
->OnMessageReceived(
2919 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2922 // Since the main frame hasn't sent any DidStopLoading messages, it is
2923 // expected that the WebContents is still in loading state.
2924 EXPECT_TRUE(contents()->IsLoading());
2925 EXPECT_TRUE(observer
.is_loading());
2927 // Navigate the frame again, this time using LoadURLWithParams. This causes
2928 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2931 NavigationController::LoadURLParams
load_params(bar_url
);
2932 load_params
.referrer
=
2933 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
2934 load_params
.transition_type
= ui::PAGE_TRANSITION_GENERATED
;
2935 load_params
.extra_headers
= "content-type: text/plain";
2936 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
2937 load_params
.is_renderer_initiated
= false;
2938 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
2939 load_params
.frame_tree_node_id
=
2940 subframe
->frame_tree_node()->frame_tree_node_id();
2941 controller().LoadURLWithParams(load_params
);
2942 entry_id
= controller().GetPendingEntry()->GetUniqueID();
2944 subframe
->OnMessageReceived(
2945 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2947 // Commit the navigation in the child frame and send the DidStopLoading
2949 subframe
->PrepareForCommit();
2950 contents()->TestDidNavigate(subframe
, 3, entry_id
, true, bar_url
,
2951 ui::PAGE_TRANSITION_MANUAL_SUBFRAME
);
2952 subframe
->OnMessageReceived(
2953 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2956 // At this point the status should still be loading, since the main frame
2957 // hasn't sent the DidstopLoading message yet.
2958 EXPECT_TRUE(contents()->IsLoading());
2959 EXPECT_TRUE(observer
.is_loading());
2961 // Send the DidStopLoading for the main frame and ensure it isn't loading
2963 orig_rfh
->OnMessageReceived(
2964 FrameHostMsg_DidStopLoading(orig_rfh
->GetRoutingID()));
2965 EXPECT_FALSE(contents()->IsLoading());
2966 EXPECT_FALSE(observer
.is_loading());
2969 // Ensure that WebContentsImpl does not stop loading too early when there still
2970 // is a pending renderer. This can happen if a same-process non user-initiated
2971 // navigation completes while there is an ongoing cross-process navigation.
2972 // TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
2973 // DidStopLoading are properly called.
2974 TEST_F(WebContentsImplTest
, NoEarlyStop
) {
2975 const GURL
kUrl1("http://www.chromium.org");
2976 const GURL
kUrl2("http://www.google.com");
2977 const GURL
kUrl3("http://www.wikipedia.org");
2979 contents()->NavigateAndCommit(kUrl1
);
2981 TestRenderFrameHost
* current_rfh
= contents()->GetMainFrame();
2983 // Start a browser-initiated cross-process navigation to |kUrl2|. There should
2984 // be a pending RenderFrameHost and the WebContents should be loading.
2985 controller().LoadURL(
2986 kUrl2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2987 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2988 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
2989 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
2990 ASSERT_TRUE(pending_rfh
);
2991 EXPECT_TRUE(contents()->IsLoading());
2993 // The current RenderFrameHost starts a non user-initiated render-initiated
2994 // navigation and sends a DidStartLoading IPC. The WebContents should still be
2996 current_rfh
->OnMessageReceived(
2997 FrameHostMsg_DidStartLoading(current_rfh
->GetRoutingID(), false));
2998 EXPECT_TRUE(contents()->IsLoading());
3000 // Simulate the pending RenderFrameHost DidStartLoading. There should still be
3001 // a pending RenderFrameHost and the WebContents should still be loading.
3002 pending_rfh
->PrepareForCommit();
3003 pending_rfh
->OnMessageReceived(
3004 FrameHostMsg_DidStartLoading(pending_rfh
->GetRoutingID(), false));
3005 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3006 EXPECT_TRUE(contents()->IsLoading());
3008 // Simulate the commit and DidStopLoading from the renderer-initiated
3009 // navigation in the current RenderFrameHost. There should still be a pending
3010 // RenderFrameHost and the WebContents should still be loading.
3011 current_rfh
->SendNavigateWithModificationCallback(
3012 1, 0, true, kUrl3
, base::Bind(SetAsNonUserGesture
));
3013 current_rfh
->OnMessageReceived(
3014 FrameHostMsg_DidStopLoading(current_rfh
->GetRoutingID()));
3015 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
3016 EXPECT_TRUE(contents()->IsLoading());
3017 // It should commit.
3018 ASSERT_EQ(2, controller().GetEntryCount());
3019 EXPECT_EQ(kUrl3
, controller().GetLastCommittedEntry()->GetURL());
3021 // Commit the navigation. The formerly pending RenderFrameHost should now be
3022 // the current RenderFrameHost and the WebContents should still be loading.
3023 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, kUrl2
,
3024 ui::PAGE_TRANSITION_TYPED
);
3025 EXPECT_FALSE(contents()->GetPendingMainFrame());
3026 TestRenderFrameHost
* new_current_rfh
= contents()->GetMainFrame();
3027 EXPECT_EQ(new_current_rfh
, pending_rfh
);
3028 EXPECT_TRUE(contents()->IsLoading());
3029 EXPECT_EQ(3, controller().GetEntryCount());
3031 // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
3032 // should now have stopped loading.
3033 new_current_rfh
->OnMessageReceived(
3034 FrameHostMsg_DidStopLoading(new_current_rfh
->GetRoutingID()));
3035 EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh
);
3036 EXPECT_FALSE(contents()->IsLoading());
3039 TEST_F(WebContentsImplTest
, MediaPowerSaveBlocking
) {
3040 // PlayerIDs are actually pointers cast to int64, so verify that both negative
3041 // and positive player ids don't blow up.
3042 const int kPlayerAudioVideoId
= 15;
3043 const int kPlayerAudioOnlyId
= -15;
3044 const int kPlayerVideoOnlyId
= 30;
3045 const int kPlayerRemoteId
= -30;
3047 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3048 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3050 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3051 AudioStateProvider
* audio_state
= contents()->audio_state_provider();
3053 // Ensure RenderFrame is initialized before simulating events coming from it.
3054 main_test_rfh()->InitializeRenderFrameIfNeeded();
3056 // The audio power save blocker should not be based on having a media player
3057 // when audio stream monitoring is available.
3058 if (audio_state
->IsAudioStateAvailable()) {
3059 // Send a fake audio stream monitor notification. The audio power save
3060 // blocker should be created.
3061 audio_state
->set_was_recently_audible_for_testing(true);
3062 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3063 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
3065 // Send another fake notification, this time when WasRecentlyAudible() will
3066 // be false. The power save blocker should be released.
3067 audio_state
->set_was_recently_audible_for_testing(false);
3068 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3069 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3072 // Start a player with both audio and video. A video power save blocker
3073 // should be created. If audio stream monitoring is available, an audio power
3074 // save blocker should be created too.
3075 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3076 0, kPlayerAudioVideoId
, true, true, false));
3077 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3078 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3079 !audio_state
->IsAudioStateAvailable());
3081 // Upon hiding the video power save blocker should be released.
3082 contents()->WasHidden();
3083 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3085 // Start another player that only has video. There should be no change in
3086 // the power save blockers. The notification should take into account the
3087 // visibility state of the WebContents.
3088 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3089 0, kPlayerVideoOnlyId
, true, false, false));
3090 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3091 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3092 !audio_state
->IsAudioStateAvailable());
3094 // Showing the WebContents should result in the creation of the blocker.
3095 contents()->WasShown();
3096 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3098 // Start another player that only has audio. There should be no change in
3099 // the power save blockers.
3100 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3101 0, kPlayerAudioOnlyId
, false, true, false));
3102 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3103 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3104 !audio_state
->IsAudioStateAvailable());
3106 // Start a remote player. There should be no change in the power save
3108 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3109 0, kPlayerRemoteId
, true, true, true));
3110 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3111 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3112 !audio_state
->IsAudioStateAvailable());
3114 // Destroy the original audio video player. Both power save blockers should
3116 rfh
->OnMessageReceived(
3117 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId
));
3118 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3119 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3120 !audio_state
->IsAudioStateAvailable());
3122 // Destroy the audio only player. The video power save blocker should remain.
3123 rfh
->OnMessageReceived(
3124 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId
));
3125 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3126 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3128 // Destroy the video only player. No power save blockers should remain.
3129 rfh
->OnMessageReceived(
3130 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId
));
3131 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3132 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3134 // Destroy the remote player. No power save blockers should remain.
3135 rfh
->OnMessageReceived(
3136 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId
));
3137 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3138 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3140 // Start a player with both audio and video. A video power save blocker
3141 // should be created. If audio stream monitoring is available, an audio power
3142 // save blocker should be created too.
3143 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3144 0, kPlayerAudioVideoId
, true, true, false));
3145 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3146 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3147 !audio_state
->IsAudioStateAvailable());
3149 // Crash the renderer.
3150 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
3152 // Verify that all the power save blockers have been released.
3153 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3154 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3157 TEST_F(WebContentsImplTest
, ThemeColorChangeDependingOnFirstVisiblePaint
) {
3158 TestWebContentsObserver
observer(contents());
3159 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3161 SkColor transparent
= SK_ColorTRANSPARENT
;
3163 EXPECT_EQ(transparent
, contents()->GetThemeColor());
3164 EXPECT_EQ(transparent
, observer
.last_theme_color());
3166 // Theme color changes should not propagate past the WebContentsImpl before
3167 // the first visually non-empty paint has occurred.
3168 RenderViewHostTester::TestOnMessageReceived(
3170 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorRED
));
3172 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3173 EXPECT_EQ(transparent
, observer
.last_theme_color());
3175 // Simulate that the first visually non-empty paint has occurred. This will
3176 // propagate the current theme color to the delegates.
3177 RenderViewHostTester::TestOnMessageReceived(
3179 FrameHostMsg_DidFirstVisuallyNonEmptyPaint(rfh
->GetRoutingID()));
3181 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3182 EXPECT_EQ(SK_ColorRED
, observer
.last_theme_color());
3184 // Additional changes made by the web contents should propagate as well.
3185 RenderViewHostTester::TestOnMessageReceived(
3187 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorGREEN
));
3189 EXPECT_EQ(SK_ColorGREEN
, contents()->GetThemeColor());
3190 EXPECT_EQ(SK_ColorGREEN
, observer
.last_theme_color());
3193 } // namespace content