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 std::vector
<NavigationEntry
*> entries
;
808 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
809 native_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false, std::string(),
812 entries
.push_back(entry
);
813 controller().Restore(
815 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
817 ASSERT_EQ(0u, entries
.size());
818 ASSERT_EQ(1, controller().GetEntryCount());
819 controller().GoToIndex(0);
820 entry
= controller().GetPendingEntry();
821 orig_rfh
->PrepareForCommit();
822 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
823 native_url
, ui::PAGE_TRANSITION_RELOAD
);
824 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
825 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
826 EXPECT_FALSE(orig_instance
->HasSite());
828 // Navigate to a regular site and verify that the SiteInstance was kept.
829 browser_client
.set_assign_site_for_url(true);
830 const GURL
url("http://www.google.com");
831 controller().LoadURL(
832 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
833 entry
= controller().GetPendingEntry();
834 orig_rfh
->PrepareForCommit();
835 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, url
,
836 ui::PAGE_TRANSITION_TYPED
);
837 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
843 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
844 // tab is restored, the SiteInstance will change upon navigation.
845 TEST_F(WebContentsImplTest
, NavigateFromRestoredRegularUrl
) {
846 WebContentsImplTestBrowserClient browser_client
;
847 SetBrowserClientForTesting(&browser_client
);
848 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
849 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
851 // Restore a navigation entry for a regular URL ensuring that the embedder
852 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
853 browser_client
.set_assign_site_for_url(true);
854 const GURL
regular_url("http://www.yahoo.com");
855 std::vector
<NavigationEntry
*> entries
;
856 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
857 regular_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false, std::string(),
860 entries
.push_back(entry
);
861 controller().Restore(
863 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
865 ASSERT_EQ(0u, entries
.size());
866 ASSERT_EQ(1, controller().GetEntryCount());
867 controller().GoToIndex(0);
868 entry
= controller().GetPendingEntry();
869 orig_rfh
->PrepareForCommit();
870 contents()->TestDidNavigate(orig_rfh
, 0, entry
->GetUniqueID(), false,
871 regular_url
, ui::PAGE_TRANSITION_RELOAD
);
872 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
873 EXPECT_TRUE(orig_instance
->HasSite());
875 // Navigate to another site and verify that a new SiteInstance was created.
876 const GURL
url("http://www.google.com");
877 controller().LoadURL(
878 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
879 entry
= controller().GetPendingEntry();
880 orig_rfh
->PrepareForCommit();
881 contents()->TestDidNavigate(contents()->GetPendingMainFrame(), 2,
882 entry
->GetUniqueID(), true, url
,
883 ui::PAGE_TRANSITION_TYPED
);
884 EXPECT_NE(orig_instance
, contents()->GetSiteInstance());
890 // Test that we can find an opener RVH even if it's pending.
891 // http://crbug.com/176252.
892 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
893 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
895 // Navigate to a URL.
896 const GURL
url("http://www.google.com");
897 controller().LoadURL(
898 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
899 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
900 orig_rfh
->PrepareForCommit();
901 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
902 ui::PAGE_TRANSITION_TYPED
);
904 // Start to navigate first tab to a new site, so that it has a pending RVH.
905 const GURL
url2("http://www.yahoo.com");
906 controller().LoadURL(
907 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
908 orig_rfh
->PrepareForCommit();
909 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
911 // While it is still pending, simulate opening a new tab with the first tab
912 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
913 // on the opener to ensure that an RVH exists.
914 int opener_routing_id
=
915 contents()->CreateOpenerRenderViews(pending_rfh
->GetSiteInstance());
917 // We should find the pending RVH and not create a new one.
918 EXPECT_EQ(pending_rfh
->GetRenderViewHost()->GetRoutingID(),
922 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
923 // to determine whether a navigation is cross-site.
924 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
925 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
926 SiteInstance
* instance1
= contents()->GetSiteInstance();
929 const GURL
url("http://www.google.com");
930 controller().LoadURL(
931 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
932 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
933 contents()->GetMainFrame()->PrepareForCommit();
934 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
935 ui::PAGE_TRANSITION_TYPED
);
937 // Open a related contents to a second site.
938 scoped_ptr
<TestWebContents
> contents2(
939 TestWebContents::Create(browser_context(), instance1
));
940 const GURL
url2("http://www.yahoo.com");
941 contents2
->GetController().LoadURL(url2
, Referrer(),
942 ui::PAGE_TRANSITION_TYPED
,
944 entry_id
= contents2
->GetController().GetPendingEntry()->GetUniqueID();
945 contents2
->GetMainFrame()->PrepareForCommit();
947 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
949 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
950 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
951 contents2
->TestDidNavigate(rfh2
, 2, entry_id
, true, url2
,
952 ui::PAGE_TRANSITION_TYPED
);
953 SiteInstance
* instance2
= contents2
->GetSiteInstance();
954 EXPECT_NE(instance1
, instance2
);
955 EXPECT_FALSE(contents2
->CrossProcessNavigationPending());
957 // Simulate a link click in first contents to second site. Doesn't switch
958 // SiteInstances, because we don't intercept Blink navigations.
959 orig_rfh
->SendRendererInitiatedNavigationRequest(url2
, true);
960 orig_rfh
->PrepareForCommit();
961 contents()->TestDidNavigate(orig_rfh
, 2, 0, true, url2
,
962 ui::PAGE_TRANSITION_TYPED
);
963 SiteInstance
* instance3
= contents()->GetSiteInstance();
964 EXPECT_EQ(instance1
, instance3
);
965 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
967 // Navigate to the new site. Doesn't switch SiteInstancees, because we
968 // compare against the current URL, not the SiteInstance's site.
969 const GURL
url3("http://mail.yahoo.com");
970 controller().LoadURL(
971 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
972 entry_id
= controller().GetPendingEntry()->GetUniqueID();
973 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
974 contents()->GetMainFrame()->PrepareForCommit();
975 contents()->TestDidNavigate(orig_rfh
, 3, entry_id
, true, url3
,
976 ui::PAGE_TRANSITION_TYPED
);
977 SiteInstance
* instance4
= contents()->GetSiteInstance();
978 EXPECT_EQ(instance1
, instance4
);
981 // Test that the onbeforeunload and onunload handlers run when navigating
982 // across site boundaries.
983 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
984 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
985 SiteInstance
* instance1
= contents()->GetSiteInstance();
987 // Navigate to URL. First URL should use first RenderViewHost.
988 const GURL
url("http://www.google.com");
989 controller().LoadURL(
990 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
991 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
992 contents()->GetMainFrame()->PrepareForCommit();
993 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
994 ui::PAGE_TRANSITION_TYPED
);
995 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
996 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
998 // Navigate to new site, but simulate an onbeforeunload denial.
999 const GURL
url2("http://www.yahoo.com");
1000 controller().LoadURL(
1001 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1002 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1003 base::TimeTicks now
= base::TimeTicks::Now();
1004 orig_rfh
->OnMessageReceived(
1005 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
1006 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1007 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1008 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1010 // Navigate again, but simulate an onbeforeunload approval.
1011 controller().LoadURL(
1012 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1013 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1014 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1015 now
= base::TimeTicks::Now();
1016 orig_rfh
->PrepareForCommit();
1017 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1018 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1019 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1021 // We won't hear DidNavigate until the onunload handler has finished running.
1023 // DidNavigate from the pending page.
1024 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1025 ui::PAGE_TRANSITION_TYPED
);
1026 SiteInstance
* instance2
= contents()->GetSiteInstance();
1027 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1028 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1029 EXPECT_NE(instance1
, instance2
);
1030 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1033 // Test that during a slow cross-site navigation, the original renderer can
1034 // navigate to a different URL and have it displayed, canceling the slow
1036 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
1037 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1038 SiteInstance
* instance1
= contents()->GetSiteInstance();
1040 // Navigate to URL. First URL should use first RenderFrameHost.
1041 const GURL
url("http://www.google.com");
1042 controller().LoadURL(
1043 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1044 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1045 contents()->GetMainFrame()->PrepareForCommit();
1046 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1047 ui::PAGE_TRANSITION_TYPED
);
1048 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1049 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1051 // Navigate to new site, simulating an onbeforeunload approval.
1052 const GURL
url2("http://www.yahoo.com");
1053 controller().LoadURL(
1054 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1055 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1056 orig_rfh
->PrepareForCommit();
1057 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1059 // Suppose the original renderer navigates before the new one is ready.
1060 orig_rfh
->SendNavigate(2, 0, true, GURL("http://www.google.com/foo"));
1062 // Verify that the pending navigation is cancelled.
1063 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1064 SiteInstance
* instance2
= contents()->GetSiteInstance();
1065 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1066 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1067 EXPECT_EQ(instance1
, instance2
);
1068 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1071 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1072 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1073 const GURL
url1("chrome://gpu");
1074 controller().LoadURL(
1075 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1076 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1077 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
1078 ntp_rfh
->PrepareForCommit();
1079 contents()->TestDidNavigate(ntp_rfh
, 1, entry_id
, true, url1
,
1080 ui::PAGE_TRANSITION_TYPED
);
1081 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1082 SiteInstance
* instance1
= contents()->GetSiteInstance();
1084 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1085 EXPECT_EQ(ntp_rfh
, contents()->GetMainFrame());
1086 EXPECT_EQ(url1
, entry1
->GetURL());
1087 EXPECT_EQ(instance1
,
1088 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1089 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1090 BINDINGS_POLICY_WEB_UI
);
1092 // Navigate to new site.
1093 const GURL
url2("http://www.google.com");
1094 controller().LoadURL(
1095 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1096 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1097 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1098 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1100 // Simulate beforeunload approval.
1101 EXPECT_TRUE(ntp_rfh
->IsWaitingForBeforeUnloadACK());
1102 base::TimeTicks now
= base::TimeTicks::Now();
1103 ntp_rfh
->PrepareForCommit();
1105 // DidNavigate from the pending page.
1106 contents()->TestDidNavigate(google_rfh
, 1, entry_id
, true, url2
,
1107 ui::PAGE_TRANSITION_TYPED
);
1108 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1109 SiteInstance
* instance2
= contents()->GetSiteInstance();
1111 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1112 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1113 EXPECT_NE(instance1
, instance2
);
1114 EXPECT_FALSE(contents()->GetPendingMainFrame());
1115 EXPECT_EQ(url2
, entry2
->GetURL());
1116 EXPECT_EQ(instance2
,
1117 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1118 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1119 BINDINGS_POLICY_WEB_UI
);
1121 // Navigate to third page on same site.
1122 const GURL
url3("http://news.google.com");
1123 controller().LoadURL(
1124 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1125 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1126 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1127 contents()->GetMainFrame()->PrepareForCommit();
1128 contents()->TestDidNavigate(google_rfh
, 2, entry_id
, true, url3
,
1129 ui::PAGE_TRANSITION_TYPED
);
1130 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1131 SiteInstance
* instance3
= contents()->GetSiteInstance();
1133 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1134 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1135 EXPECT_EQ(instance2
, instance3
);
1136 EXPECT_FALSE(contents()->GetPendingMainFrame());
1137 EXPECT_EQ(url3
, entry3
->GetURL());
1138 EXPECT_EQ(instance3
,
1139 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1141 // Go back within the site.
1142 controller().GoBack();
1143 NavigationEntry
* goback_entry
= controller().GetPendingEntry();
1144 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1145 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1147 // Before that commits, go back again.
1148 controller().GoBack();
1149 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1150 EXPECT_TRUE(contents()->GetPendingMainFrame());
1151 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1153 // Simulate beforeunload approval.
1154 EXPECT_TRUE(google_rfh
->IsWaitingForBeforeUnloadACK());
1155 now
= base::TimeTicks::Now();
1156 google_rfh
->PrepareForCommit();
1157 google_rfh
->OnMessageReceived(
1158 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1160 // DidNavigate from the first back. This aborts the second back's pending RFH.
1161 contents()->TestDidNavigate(google_rfh
, 1, goback_entry
->GetUniqueID(), false,
1162 url2
, ui::PAGE_TRANSITION_TYPED
);
1164 // We should commit this page and forget about the second back.
1165 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1166 EXPECT_FALSE(controller().GetPendingEntry());
1167 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1168 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1170 // We should not have corrupted the NTP entry.
1171 EXPECT_EQ(instance3
,
1172 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1173 EXPECT_EQ(instance2
,
1174 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1175 EXPECT_EQ(instance1
,
1176 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1177 EXPECT_EQ(url1
, entry1
->GetURL());
1180 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1181 // original renderer will not cancel the slow navigation (bug 42029).
1182 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1183 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1185 // Navigate to URL. First URL should use the original RenderFrameHost.
1186 const GURL
url("http://www.google.com");
1187 controller().LoadURL(
1188 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1189 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1190 contents()->GetMainFrame()->PrepareForCommit();
1191 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1192 ui::PAGE_TRANSITION_TYPED
);
1193 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1194 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1196 // Start navigating to new site.
1197 const GURL
url2("http://www.yahoo.com");
1198 controller().LoadURL(
1199 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1201 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1202 // waiting for a before unload response.
1203 TestRenderFrameHost
* child_rfh
= orig_rfh
->AppendChild("subframe");
1204 child_rfh
->SendNavigateWithTransition(1, 0, false,
1205 GURL("http://google.com/frame"),
1206 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
1207 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1209 // Now simulate the onbeforeunload approval and verify the navigation is
1211 orig_rfh
->PrepareForCommit();
1212 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1213 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1216 // Test that a cross-site navigation is not preempted if the previous
1217 // renderer sends a FrameNavigate message just before being told to stop.
1218 // We should only preempt the cross-site navigation if the previous renderer
1219 // has started a new navigation. See http://crbug.com/79176.
1220 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1221 // Navigate to WebUI URL.
1222 const GURL
url("chrome://gpu");
1223 controller().LoadURL(
1224 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1225 int entry1_id
= controller().GetPendingEntry()->GetUniqueID();
1226 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1227 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1229 // Navigate to new site, with the beforeunload request in flight.
1230 const GURL
url2("http://www.yahoo.com");
1231 controller().LoadURL(
1232 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1233 int entry2_id
= controller().GetPendingEntry()->GetUniqueID();
1234 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1235 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1236 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1238 // Suppose the first navigation tries to commit now, with a
1239 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1240 // but it should act as if the beforeunload ack arrived.
1241 orig_rfh
->SendNavigate(1, entry1_id
, true, GURL("chrome://gpu"));
1242 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1243 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1244 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1246 // The pending navigation should be able to commit successfully.
1247 contents()->TestDidNavigate(pending_rfh
, 1, entry2_id
, true, url2
,
1248 ui::PAGE_TRANSITION_TYPED
);
1249 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1250 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1253 // Test that NavigationEntries have the correct page state after going
1254 // forward and back. Prevents regression for bug 1116137.
1255 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1256 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1258 // Navigate to URL. There should be no committed entry yet.
1259 const GURL
url("http://www.google.com");
1260 controller().LoadURL(
1261 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1262 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1263 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1264 EXPECT_EQ(nullptr, entry
);
1266 // Committed entry should have page state after DidNavigate.
1267 orig_rfh
->PrepareForCommit();
1268 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1269 ui::PAGE_TRANSITION_TYPED
);
1270 entry
= controller().GetLastCommittedEntry();
1271 EXPECT_TRUE(entry
->GetPageState().IsValid());
1273 // Navigate to same site.
1274 const GURL
url2("http://images.google.com");
1275 controller().LoadURL(
1276 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1277 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1278 entry
= controller().GetLastCommittedEntry();
1279 EXPECT_TRUE(entry
->GetPageState().IsValid());
1281 // Committed entry should have page state after DidNavigate.
1282 orig_rfh
->PrepareForCommit();
1283 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1284 ui::PAGE_TRANSITION_TYPED
);
1285 entry
= controller().GetLastCommittedEntry();
1286 EXPECT_TRUE(entry
->GetPageState().IsValid());
1288 // Now go back. Committed entry should still have page state.
1289 controller().GoBack();
1290 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1291 orig_rfh
->PrepareForCommit();
1292 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, false, url
,
1293 ui::PAGE_TRANSITION_TYPED
);
1294 entry
= controller().GetLastCommittedEntry();
1295 EXPECT_TRUE(entry
->GetPageState().IsValid());
1298 // Test that NavigationEntries have the correct page state and SiteInstance
1299 // state after opening a new window to about:blank. Prevents regression for
1300 // bugs b/1116137 and http://crbug.com/111975.
1301 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1302 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1304 // Navigate to about:blank.
1305 const GURL
url(url::kAboutBlankURL
);
1306 orig_rfh
->SendRendererInitiatedNavigationRequest(url
, false);
1307 orig_rfh
->PrepareForCommit();
1308 contents()->TestDidNavigate(orig_rfh
, 1, 0, true, url
,
1309 ui::PAGE_TRANSITION_TYPED
);
1311 // Should have a page state here.
1312 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1313 EXPECT_TRUE(entry
->GetPageState().IsValid());
1315 // The SiteInstance should be available for other navigations to use.
1316 NavigationEntryImpl
* entry_impl
=
1317 NavigationEntryImpl::FromNavigationEntry(entry
);
1318 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1319 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1321 // Navigating to a normal page should not cause a process swap.
1322 const GURL
new_url("http://www.google.com");
1323 controller().LoadURL(new_url
, Referrer(),
1324 ui::PAGE_TRANSITION_TYPED
, std::string());
1325 entry
= controller().GetPendingEntry();
1326 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1327 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1328 orig_rfh
->PrepareForCommit();
1329 contents()->TestDidNavigate(orig_rfh
, 2, entry
->GetUniqueID(), true, new_url
,
1330 ui::PAGE_TRANSITION_TYPED
);
1331 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1332 controller().GetLastCommittedEntry());
1333 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1334 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1337 // Tests that fullscreen is exited throughout the object hierarchy when
1338 // navigating to a new page.
1339 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1340 FakeFullscreenDelegate fake_delegate
;
1341 contents()->SetDelegate(&fake_delegate
);
1342 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1343 TestRenderViewHost
* orig_rvh
= orig_rfh
->GetRenderViewHost();
1345 // Navigate to a site.
1346 const GURL
url("http://www.google.com");
1347 controller().LoadURL(
1348 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1349 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1350 contents()->GetMainFrame()->PrepareForCommit();
1351 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1352 ui::PAGE_TRANSITION_TYPED
);
1353 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1355 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1356 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1357 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1358 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1359 orig_rfh
->OnMessageReceived(
1360 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1361 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1362 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1363 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1365 // Navigate to a new site.
1366 const GURL
url2("http://www.yahoo.com");
1367 controller().LoadURL(
1368 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1369 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1370 contents()->GetMainFrame()->PrepareForCommit();
1371 TestRenderFrameHost
* const pending_rfh
= contents()->GetPendingMainFrame();
1372 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, url2
,
1373 ui::PAGE_TRANSITION_TYPED
);
1375 // Confirm fullscreen has exited.
1376 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1377 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1378 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1380 contents()->SetDelegate(nullptr);
1383 // Tests that fullscreen is exited throughout the object hierarchy when
1384 // instructing NavigationController to GoBack() or GoForward().
1385 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1386 FakeFullscreenDelegate fake_delegate
;
1387 contents()->SetDelegate(&fake_delegate
);
1388 TestRenderFrameHost
* const orig_rfh
= contents()->GetMainFrame();
1389 TestRenderViewHost
* const orig_rvh
= orig_rfh
->GetRenderViewHost();
1391 // Navigate to a site.
1392 const GURL
url("http://www.google.com");
1393 controller().LoadURL(
1394 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1395 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1396 orig_rfh
->PrepareForCommit();
1397 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, url
,
1398 ui::PAGE_TRANSITION_TYPED
);
1399 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1401 // Now, navigate to another page on the same site.
1402 const GURL
url2("http://www.google.com/search?q=kittens");
1403 controller().LoadURL(
1404 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1405 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1406 orig_rfh
->PrepareForCommit();
1407 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1408 contents()->TestDidNavigate(orig_rfh
, 2, entry_id
, true, url2
,
1409 ui::PAGE_TRANSITION_TYPED
);
1410 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1412 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1413 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1414 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1415 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1417 for (int i
= 0; i
< 2; ++i
) {
1418 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1419 orig_rfh
->OnMessageReceived(
1420 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1421 EXPECT_TRUE(orig_rvh
->IsFullscreenGranted());
1422 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1423 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1425 // Navigate backward (or forward).
1427 controller().GoBack();
1429 controller().GoForward();
1430 entry_id
= controller().GetPendingEntry()->GetUniqueID();
1431 orig_rfh
->PrepareForCommit();
1432 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1433 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1434 contents()->TestDidNavigate(orig_rfh
, i
+ 1, entry_id
, false, url
,
1435 ui::PAGE_TRANSITION_FORWARD_BACK
);
1437 // Confirm fullscreen has exited.
1438 EXPECT_FALSE(orig_rvh
->IsFullscreenGranted());
1439 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1440 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1443 contents()->SetDelegate(nullptr);
1446 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1447 FakeValidationMessageDelegate fake_delegate
;
1448 contents()->SetDelegate(&fake_delegate
);
1449 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1451 // Initialize the RenderFrame and then simulate crashing the renderer
1453 contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
1454 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1456 // Confirm HideValidationMessage was called.
1457 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1459 contents()->SetDelegate(nullptr);
1462 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1464 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1465 FakeFullscreenDelegate fake_delegate
;
1466 contents()->SetDelegate(&fake_delegate
);
1468 // Navigate to a site.
1469 const GURL
url("http://www.google.com");
1470 controller().LoadURL(
1471 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1472 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
1473 main_test_rfh()->PrepareForCommit();
1474 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
1475 url
, ui::PAGE_TRANSITION_TYPED
);
1477 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1478 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1479 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1480 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1481 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1482 contents()->GetMainFrame()->GetRoutingID(), true));
1483 EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
1484 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1485 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1487 // Crash the renderer.
1488 main_test_rfh()->GetProcess()->SimulateCrash();
1490 // Confirm fullscreen has exited.
1491 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1492 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1493 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1495 contents()->SetDelegate(nullptr);
1498 ////////////////////////////////////////////////////////////////////////////////
1499 // Interstitial Tests
1500 ////////////////////////////////////////////////////////////////////////////////
1502 // Test navigating to a page (with the navigation initiated from the browser,
1503 // as when a URL is typed in the location bar) that shows an interstitial and
1504 // creates a new navigation entry, then hiding it without proceeding.
1505 TEST_F(WebContentsImplTest
,
1506 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1507 // Navigate to a page.
1508 GURL
url1("http://www.google.com");
1509 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1510 EXPECT_EQ(1, controller().GetEntryCount());
1512 // Initiate a browser navigation that will trigger the interstitial.
1513 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1514 ui::PAGE_TRANSITION_TYPED
, std::string());
1515 NavigationEntry
* entry
= controller().GetPendingEntry();
1517 // Show an interstitial.
1518 TestInterstitialPage::InterstitialState state
=
1519 TestInterstitialPage::INVALID
;
1520 bool deleted
= false;
1521 GURL
url2("http://interstitial");
1522 TestInterstitialPage
* interstitial
=
1523 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1524 TestInterstitialPageStateGuard
state_guard(interstitial
);
1525 interstitial
->Show();
1526 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1527 // The interstitial should not show until its navigation has committed.
1528 EXPECT_FALSE(interstitial
->is_showing());
1529 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1530 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1531 // Let's commit the interstitial navigation.
1532 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1533 EXPECT_TRUE(interstitial
->is_showing());
1534 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1535 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1536 entry
= controller().GetVisibleEntry();
1537 ASSERT_NE(nullptr, entry
);
1538 EXPECT_TRUE(entry
->GetURL() == url2
);
1540 // Now don't proceed.
1541 interstitial
->DontProceed();
1542 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1543 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1544 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1545 entry
= controller().GetVisibleEntry();
1546 ASSERT_NE(nullptr, entry
);
1547 EXPECT_TRUE(entry
->GetURL() == url1
);
1548 EXPECT_EQ(1, controller().GetEntryCount());
1550 RunAllPendingInMessageLoop();
1551 EXPECT_TRUE(deleted
);
1554 // Test navigating to a page (with the navigation initiated from the renderer,
1555 // as when clicking on a link in the page) that shows an interstitial and
1556 // creates a new navigation entry, then hiding it without proceeding.
1557 TEST_F(WebContentsImplTest
,
1558 ShowInterstitialFromRendererWithNewNavigationDontProceed
) {
1559 // Navigate to a page.
1560 GURL
url1("http://www.google.com");
1561 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1562 EXPECT_EQ(1, controller().GetEntryCount());
1564 // Show an interstitial (no pending entry, the interstitial would have been
1565 // triggered by clicking on a link).
1566 TestInterstitialPage::InterstitialState state
=
1567 TestInterstitialPage::INVALID
;
1568 bool deleted
= false;
1569 GURL
url2("http://interstitial");
1570 TestInterstitialPage
* interstitial
=
1571 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1572 TestInterstitialPageStateGuard
state_guard(interstitial
);
1573 interstitial
->Show();
1574 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1575 // The interstitial should not show until its navigation has committed.
1576 EXPECT_FALSE(interstitial
->is_showing());
1577 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1578 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1579 // Let's commit the interstitial navigation.
1580 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1581 EXPECT_TRUE(interstitial
->is_showing());
1582 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1583 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1584 NavigationEntry
* entry
= controller().GetVisibleEntry();
1585 ASSERT_NE(nullptr, entry
);
1586 EXPECT_TRUE(entry
->GetURL() == url2
);
1588 // Now don't proceed.
1589 interstitial
->DontProceed();
1590 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1591 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1592 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1593 entry
= controller().GetVisibleEntry();
1594 ASSERT_NE(nullptr, entry
);
1595 EXPECT_TRUE(entry
->GetURL() == url1
);
1596 EXPECT_EQ(1, controller().GetEntryCount());
1598 RunAllPendingInMessageLoop();
1599 EXPECT_TRUE(deleted
);
1602 // Test navigating to a page that shows an interstitial without creating a new
1603 // navigation entry (this happens when the interstitial is triggered by a
1604 // sub-resource in the page), then hiding it without proceeding.
1605 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1606 // Navigate to a page.
1607 GURL
url1("http://www.google.com");
1608 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1609 EXPECT_EQ(1, controller().GetEntryCount());
1611 // Show an interstitial.
1612 TestInterstitialPage::InterstitialState state
=
1613 TestInterstitialPage::INVALID
;
1614 bool deleted
= false;
1615 GURL
url2("http://interstitial");
1616 TestInterstitialPage
* interstitial
=
1617 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1618 TestInterstitialPageStateGuard
state_guard(interstitial
);
1619 interstitial
->Show();
1620 // The interstitial should not show until its navigation has committed.
1621 EXPECT_FALSE(interstitial
->is_showing());
1622 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1623 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1624 // Let's commit the interstitial navigation.
1625 interstitial
->TestDidNavigate(1, 0, true, url2
);
1626 EXPECT_TRUE(interstitial
->is_showing());
1627 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1628 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1629 NavigationEntry
* entry
= controller().GetVisibleEntry();
1630 ASSERT_NE(nullptr, entry
);
1631 // The URL specified to the interstitial should have been ignored.
1632 EXPECT_TRUE(entry
->GetURL() == url1
);
1634 // Now don't proceed.
1635 interstitial
->DontProceed();
1636 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1637 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1638 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1639 entry
= controller().GetVisibleEntry();
1640 ASSERT_NE(nullptr, entry
);
1641 EXPECT_TRUE(entry
->GetURL() == url1
);
1642 EXPECT_EQ(1, controller().GetEntryCount());
1644 RunAllPendingInMessageLoop();
1645 EXPECT_TRUE(deleted
);
1648 // Test navigating to a page (with the navigation initiated from the browser,
1649 // as when a URL is typed in the location bar) that shows an interstitial and
1650 // creates a new navigation entry, then proceeding.
1651 TEST_F(WebContentsImplTest
,
1652 ShowInterstitialFromBrowserNewNavigationProceed
) {
1653 // Navigate to a page.
1654 GURL
url1("http://www.google.com");
1655 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1656 EXPECT_EQ(1, controller().GetEntryCount());
1658 // Initiate a browser navigation that will trigger the interstitial
1659 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1660 ui::PAGE_TRANSITION_TYPED
, std::string());
1662 // Show an interstitial.
1663 TestInterstitialPage::InterstitialState state
=
1664 TestInterstitialPage::INVALID
;
1665 bool deleted
= false;
1666 GURL
url2("http://interstitial");
1667 TestInterstitialPage
* interstitial
=
1668 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1669 TestInterstitialPageStateGuard
state_guard(interstitial
);
1670 interstitial
->Show();
1671 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1672 // The interstitial should not show until its navigation has committed.
1673 EXPECT_FALSE(interstitial
->is_showing());
1674 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1675 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1676 // Let's commit the interstitial navigation.
1677 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1678 EXPECT_TRUE(interstitial
->is_showing());
1679 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1680 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1681 NavigationEntry
* entry
= controller().GetVisibleEntry();
1682 ASSERT_NE(nullptr, entry
);
1683 EXPECT_TRUE(entry
->GetURL() == url2
);
1686 interstitial
->Proceed();
1687 // The interstitial should show until the new navigation commits.
1688 RunAllPendingInMessageLoop();
1689 ASSERT_FALSE(deleted
);
1690 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1691 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1692 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1694 // Simulate the navigation to the page, that's when the interstitial gets
1696 GURL
url3("http://www.thepage.com");
1697 contents()->GetMainFrame()->PrepareForCommit();
1698 contents()->GetMainFrame()->SendNavigate(2, 0, true, url3
);
1700 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1701 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1702 entry
= controller().GetVisibleEntry();
1703 ASSERT_NE(nullptr, entry
);
1704 EXPECT_TRUE(entry
->GetURL() == url3
);
1706 EXPECT_EQ(2, controller().GetEntryCount());
1708 RunAllPendingInMessageLoop();
1709 EXPECT_TRUE(deleted
);
1712 // Test navigating to a page (with the navigation initiated from the renderer,
1713 // as when clicking on a link in the page) that shows an interstitial and
1714 // creates a new navigation entry, then proceeding.
1715 TEST_F(WebContentsImplTest
,
1716 ShowInterstitialFromRendererNewNavigationProceed
) {
1717 // Navigate to a page.
1718 GURL
url1("http://www.google.com");
1719 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1720 EXPECT_EQ(1, controller().GetEntryCount());
1722 // Show an interstitial.
1723 TestInterstitialPage::InterstitialState state
=
1724 TestInterstitialPage::INVALID
;
1725 bool deleted
= false;
1726 GURL
url2("http://interstitial");
1727 TestInterstitialPage
* interstitial
=
1728 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1729 TestInterstitialPageStateGuard
state_guard(interstitial
);
1730 interstitial
->Show();
1731 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1732 // The interstitial should not show until its navigation has committed.
1733 EXPECT_FALSE(interstitial
->is_showing());
1734 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1735 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1736 // Let's commit the interstitial navigation.
1737 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
1738 EXPECT_TRUE(interstitial
->is_showing());
1739 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1740 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1741 NavigationEntry
* entry
= controller().GetVisibleEntry();
1742 ASSERT_NE(nullptr, entry
);
1743 EXPECT_TRUE(entry
->GetURL() == url2
);
1746 interstitial
->Proceed();
1747 // The interstitial should show until the new navigation commits.
1748 RunAllPendingInMessageLoop();
1749 ASSERT_FALSE(deleted
);
1750 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1751 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1752 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1754 // Simulate the navigation to the page, that's when the interstitial gets
1756 GURL
url3("http://www.thepage.com");
1757 main_test_rfh()->NavigateAndCommitRendererInitiated(2, true, url3
);
1759 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1760 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1761 entry
= controller().GetVisibleEntry();
1762 ASSERT_NE(nullptr, entry
);
1763 EXPECT_TRUE(entry
->GetURL() == url3
);
1765 EXPECT_EQ(2, controller().GetEntryCount());
1767 RunAllPendingInMessageLoop();
1768 EXPECT_TRUE(deleted
);
1771 // Test navigating to a page that shows an interstitial without creating a new
1772 // navigation entry (this happens when the interstitial is triggered by a
1773 // sub-resource in the page), then proceeding.
1774 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1775 // Navigate to a page so we have a navigation entry in the controller.
1776 GURL
url1("http://www.google.com");
1777 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1778 EXPECT_EQ(1, controller().GetEntryCount());
1780 // Show an interstitial.
1781 TestInterstitialPage::InterstitialState state
=
1782 TestInterstitialPage::INVALID
;
1783 bool deleted
= false;
1784 GURL
url2("http://interstitial");
1785 TestInterstitialPage
* interstitial
=
1786 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1787 TestInterstitialPageStateGuard
state_guard(interstitial
);
1788 interstitial
->Show();
1789 // The interstitial should not show until its navigation has committed.
1790 EXPECT_FALSE(interstitial
->is_showing());
1791 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1792 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1793 // Let's commit the interstitial navigation.
1794 interstitial
->TestDidNavigate(1, 0, true, url2
);
1795 EXPECT_TRUE(interstitial
->is_showing());
1796 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1797 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1798 NavigationEntry
* entry
= controller().GetVisibleEntry();
1799 ASSERT_NE(nullptr, entry
);
1800 // The URL specified to the interstitial should have been ignored.
1801 EXPECT_TRUE(entry
->GetURL() == url1
);
1804 interstitial
->Proceed();
1805 // Since this is not a new navigation, the previous page is dismissed right
1806 // away and shows the original page.
1807 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1808 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1809 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1810 entry
= controller().GetVisibleEntry();
1811 ASSERT_NE(nullptr, entry
);
1812 EXPECT_TRUE(entry
->GetURL() == url1
);
1814 EXPECT_EQ(1, controller().GetEntryCount());
1816 RunAllPendingInMessageLoop();
1817 EXPECT_TRUE(deleted
);
1820 // Test navigating to a page that shows an interstitial, then navigating away.
1821 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1822 // Show interstitial.
1823 TestInterstitialPage::InterstitialState state
=
1824 TestInterstitialPage::INVALID
;
1825 bool deleted
= false;
1826 GURL
url("http://interstitial");
1827 TestInterstitialPage
* interstitial
=
1828 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1829 TestInterstitialPageStateGuard
state_guard(interstitial
);
1830 interstitial
->Show();
1831 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1832 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
1834 // While interstitial showing, navigate to a new URL.
1835 const GURL
url2("http://www.yahoo.com");
1836 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2
);
1838 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1840 RunAllPendingInMessageLoop();
1841 EXPECT_TRUE(deleted
);
1844 // Test navigating to a page that shows an interstitial, then going back.
1845 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1846 // Navigate to a page so we have a navigation entry in the controller.
1847 GURL
url1("http://www.google.com");
1848 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1849 EXPECT_EQ(1, controller().GetEntryCount());
1850 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1852 // Show interstitial.
1853 TestInterstitialPage::InterstitialState state
=
1854 TestInterstitialPage::INVALID
;
1855 bool deleted
= false;
1856 GURL
interstitial_url("http://interstitial");
1857 TestInterstitialPage
* interstitial
=
1858 new TestInterstitialPage(contents(), true, interstitial_url
,
1860 TestInterstitialPageStateGuard
state_guard(interstitial
);
1861 interstitial
->Show();
1862 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1863 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1866 // While the interstitial is showing, go back.
1867 controller().GoBack();
1868 main_test_rfh()->PrepareForCommit();
1869 contents()->GetMainFrame()->SendNavigate(1, entry
->GetUniqueID(), false,
1872 // Make sure we are back to the original page and that the interstitial is
1874 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1875 entry
= controller().GetVisibleEntry();
1877 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1879 RunAllPendingInMessageLoop();
1880 EXPECT_TRUE(deleted
);
1883 // Test navigating to a page that shows an interstitial, has a renderer crash,
1884 // and then goes back.
1885 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1886 // Navigate to a page so we have a navigation entry in the controller.
1887 GURL
url1("http://www.google.com");
1888 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1889 EXPECT_EQ(1, controller().GetEntryCount());
1890 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1892 // Show interstitial.
1893 TestInterstitialPage::InterstitialState state
=
1894 TestInterstitialPage::INVALID
;
1895 bool deleted
= false;
1896 GURL
interstitial_url("http://interstitial");
1897 TestInterstitialPage
* interstitial
=
1898 new TestInterstitialPage(contents(), true, interstitial_url
,
1900 TestInterstitialPageStateGuard
state_guard(interstitial
);
1901 interstitial
->Show();
1902 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1903 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1906 // Crash the renderer
1907 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1909 // While the interstitial is showing, go back. This will dismiss the
1910 // interstitial and not initiate a navigation, but just show the existing
1912 controller().GoBack();
1914 // Make sure we are back to the original page and that the interstitial is
1916 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1917 entry
= controller().GetVisibleEntry();
1919 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1921 RunAllPendingInMessageLoop();
1922 EXPECT_TRUE(deleted
);
1925 // Test navigating to a page that shows an interstitial, has the renderer crash,
1926 // and then navigates to the interstitial.
1927 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1928 // Navigate to a page so we have a navigation entry in the controller.
1929 GURL
url1("http://www.google.com");
1930 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
1931 EXPECT_EQ(1, controller().GetEntryCount());
1933 // Show interstitial.
1934 TestInterstitialPage::InterstitialState state
=
1935 TestInterstitialPage::INVALID
;
1936 bool deleted
= false;
1937 GURL
interstitial_url("http://interstitial");
1938 TestInterstitialPage
* interstitial
=
1939 new TestInterstitialPage(contents(), true, interstitial_url
,
1941 TestInterstitialPageStateGuard
state_guard(interstitial
);
1942 interstitial
->Show();
1943 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1945 // Crash the renderer
1946 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1948 interstitial
->TestDidNavigate(2, interstitial_entry_id
, true,
1952 // Test navigating to a page that shows an interstitial, then close the
1954 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1955 // Show interstitial.
1956 TestInterstitialPage::InterstitialState state
=
1957 TestInterstitialPage::INVALID
;
1958 bool deleted
= false;
1959 GURL
url("http://interstitial");
1960 TestInterstitialPage
* interstitial
=
1961 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1962 TestInterstitialPageStateGuard
state_guard(interstitial
);
1963 interstitial
->Show();
1964 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1965 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
1967 // Now close the contents.
1969 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1971 RunAllPendingInMessageLoop();
1972 EXPECT_TRUE(deleted
);
1975 // Test navigating to a page that shows an interstitial, then close the
1977 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
1978 // Show interstitial.
1979 TestInterstitialPage::InterstitialState state
=
1980 TestInterstitialPage::INVALID
;
1981 bool deleted
= false;
1982 GURL
url("http://interstitial");
1983 TestInterstitialPage
* interstitial
=
1984 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1985 TestInterstitialPageStateGuard
state_guard(interstitial
);
1986 interstitial
->Show();
1987 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
1988 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
1989 TestRenderFrameHost
* rfh
=
1990 static_cast<TestRenderFrameHost
*>(interstitial
->GetMainFrame());
1992 // Now close the contents.
1994 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1996 // Before the interstitial has a chance to process its shutdown task,
1997 // simulate quitting the browser. This goes through all processes and
1998 // tells them to destruct.
1999 rfh
->GetProcess()->SimulateCrash();
2001 RunAllPendingInMessageLoop();
2002 EXPECT_TRUE(deleted
);
2005 // Test that after Proceed is called and an interstitial is still shown, no more
2006 // commands get executed.
2007 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
2008 // Navigate to a page so we have a navigation entry in the controller.
2009 GURL
url1("http://www.google.com");
2010 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2011 EXPECT_EQ(1, controller().GetEntryCount());
2013 // Show an interstitial.
2014 TestInterstitialPage::InterstitialState state
=
2015 TestInterstitialPage::INVALID
;
2016 bool deleted
= false;
2017 GURL
url2("http://interstitial");
2018 TestInterstitialPage
* interstitial
=
2019 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2020 TestInterstitialPageStateGuard
state_guard(interstitial
);
2021 interstitial
->Show();
2022 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2023 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2026 EXPECT_EQ(0, interstitial
->command_received_count());
2027 interstitial
->TestDomOperationResponse("toto");
2028 EXPECT_EQ(1, interstitial
->command_received_count());
2031 interstitial
->Proceed();
2032 RunAllPendingInMessageLoop();
2033 ASSERT_FALSE(deleted
);
2035 // While the navigation to the new page is pending, send other commands, they
2036 // should be ignored.
2037 interstitial
->TestDomOperationResponse("hello");
2038 interstitial
->TestDomOperationResponse("hi");
2039 EXPECT_EQ(1, interstitial
->command_received_count());
2042 // Test showing an interstitial while another interstitial is already showing.
2043 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
2044 // Navigate to a page so we have a navigation entry in the controller.
2045 GURL
start_url("http://www.google.com");
2046 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2047 EXPECT_EQ(1, controller().GetEntryCount());
2049 // Show an interstitial.
2050 TestInterstitialPage::InterstitialState state1
=
2051 TestInterstitialPage::INVALID
;
2052 bool deleted1
= false;
2053 GURL
url1("http://interstitial1");
2054 TestInterstitialPage
* interstitial1
=
2055 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2056 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2057 interstitial1
->Show();
2058 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2059 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2061 // Now show another interstitial.
2062 TestInterstitialPage::InterstitialState state2
=
2063 TestInterstitialPage::INVALID
;
2064 bool deleted2
= false;
2065 GURL
url2("http://interstitial2");
2066 TestInterstitialPage
* interstitial2
=
2067 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2068 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2069 interstitial2
->Show();
2070 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2071 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2073 // Showing interstitial2 should have caused interstitial1 to go away.
2074 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2075 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2077 RunAllPendingInMessageLoop();
2078 EXPECT_TRUE(deleted1
);
2079 ASSERT_FALSE(deleted2
);
2081 // Let's make sure interstitial2 is working as intended.
2082 interstitial2
->Proceed();
2083 GURL
landing_url("http://www.thepage.com");
2084 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2086 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2087 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2088 NavigationEntry
* entry
= controller().GetVisibleEntry();
2089 ASSERT_NE(nullptr, entry
);
2090 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2091 EXPECT_EQ(2, controller().GetEntryCount());
2092 RunAllPendingInMessageLoop();
2093 EXPECT_TRUE(deleted2
);
2096 // Test showing an interstitial, proceeding and then navigating to another
2098 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2099 // Navigate to a page so we have a navigation entry in the controller.
2100 GURL
start_url("http://www.google.com");
2101 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url
);
2102 EXPECT_EQ(1, controller().GetEntryCount());
2104 // Show an interstitial.
2105 TestInterstitialPage::InterstitialState state1
=
2106 TestInterstitialPage::INVALID
;
2107 bool deleted1
= false;
2108 GURL
url1("http://interstitial1");
2109 TestInterstitialPage
* interstitial1
=
2110 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2111 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2112 interstitial1
->Show();
2113 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2114 interstitial1
->TestDidNavigate(1, interstitial_entry_id
, true, url1
);
2116 // Take action. The interstitial won't be hidden until the navigation is
2118 interstitial1
->Proceed();
2119 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2121 // Now show another interstitial (simulating the navigation causing another
2123 TestInterstitialPage::InterstitialState state2
=
2124 TestInterstitialPage::INVALID
;
2125 bool deleted2
= false;
2126 GURL
url2("http://interstitial2");
2127 TestInterstitialPage
* interstitial2
=
2128 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2129 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2130 interstitial2
->Show();
2131 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2132 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2134 // Showing interstitial2 should have caused interstitial1 to go away.
2135 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2136 RunAllPendingInMessageLoop();
2137 EXPECT_TRUE(deleted1
);
2138 ASSERT_FALSE(deleted2
);
2140 // Let's make sure interstitial2 is working as intended.
2141 interstitial2
->Proceed();
2142 GURL
landing_url("http://www.thepage.com");
2143 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url
);
2145 RunAllPendingInMessageLoop();
2146 EXPECT_TRUE(deleted2
);
2147 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2148 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2149 NavigationEntry
* entry
= controller().GetVisibleEntry();
2150 ASSERT_NE(nullptr, entry
);
2151 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2152 EXPECT_EQ(2, controller().GetEntryCount());
2155 // Test that navigating away from an interstitial while it's loading cause it
2157 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2158 // Show an interstitial.
2159 TestInterstitialPage::InterstitialState state
=
2160 TestInterstitialPage::INVALID
;
2161 bool deleted
= false;
2162 GURL
interstitial_url("http://interstitial");
2163 TestInterstitialPage
* interstitial
=
2164 new TestInterstitialPage(contents(), true, interstitial_url
,
2166 TestInterstitialPageStateGuard
state_guard(interstitial
);
2167 interstitial
->Show();
2168 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2170 // Let's simulate a navigation initiated from the browser before the
2171 // interstitial finishes loading.
2172 const GURL
url("http://www.google.com");
2173 controller().LoadURL(
2174 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2175 EXPECT_FALSE(interstitial
->is_showing());
2176 RunAllPendingInMessageLoop();
2177 ASSERT_FALSE(deleted
);
2179 // Now let's make the interstitial navigation commit.
2180 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true,
2183 // After it loaded the interstitial should be gone.
2184 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2186 RunAllPendingInMessageLoop();
2187 EXPECT_TRUE(deleted
);
2190 // Test that a new request to show an interstitial while an interstitial is
2191 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2192 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2193 GURL
interstitial_url("http://interstitial");
2195 // Show a first interstitial.
2196 TestInterstitialPage::InterstitialState state1
=
2197 TestInterstitialPage::INVALID
;
2198 bool deleted1
= false;
2199 TestInterstitialPage
* interstitial1
=
2200 new TestInterstitialPage(contents(), true, interstitial_url
,
2201 &state1
, &deleted1
);
2202 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2203 interstitial1
->Show();
2205 // Show another interstitial on that same contents before the first one had
2207 TestInterstitialPage::InterstitialState state2
=
2208 TestInterstitialPage::INVALID
;
2209 bool deleted2
= false;
2210 TestInterstitialPage
* interstitial2
=
2211 new TestInterstitialPage(contents(), true, interstitial_url
,
2212 &state2
, &deleted2
);
2213 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2214 interstitial2
->Show();
2215 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2217 // The first interstitial should have been closed and deleted.
2218 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2219 // The 2nd one should still be OK.
2220 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2222 RunAllPendingInMessageLoop();
2223 EXPECT_TRUE(deleted1
);
2224 ASSERT_FALSE(deleted2
);
2226 // Make the interstitial navigation commit it should be showing.
2227 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true,
2229 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2232 // Test showing an interstitial and have its renderer crash.
2233 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2234 // Show an interstitial.
2235 TestInterstitialPage::InterstitialState state
=
2236 TestInterstitialPage::INVALID
;
2237 bool deleted
= false;
2238 GURL
url("http://interstitial");
2239 TestInterstitialPage
* interstitial
=
2240 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2241 TestInterstitialPageStateGuard
state_guard(interstitial
);
2242 interstitial
->Show();
2243 // Simulate a renderer crash before the interstitial is shown.
2244 interstitial
->TestRenderViewTerminated(
2245 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2246 // The interstitial should have been dismissed.
2247 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2248 RunAllPendingInMessageLoop();
2249 EXPECT_TRUE(deleted
);
2251 // Now try again but this time crash the intersitial after it was shown.
2253 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2254 interstitial
->Show();
2255 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2256 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url
);
2257 // Simulate a renderer crash.
2258 interstitial
->TestRenderViewTerminated(
2259 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2260 // The interstitial should have been dismissed.
2261 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2262 RunAllPendingInMessageLoop();
2263 EXPECT_TRUE(deleted
);
2266 // Tests that showing an interstitial as a result of a browser initiated
2267 // navigation while an interstitial is showing does not remove the pending
2268 // entry (see http://crbug.com/9791).
2269 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2270 const char kUrl
[] = "http://www.badguys.com/";
2271 const GURL
kGURL(kUrl
);
2273 // Start a navigation to a page
2274 contents()->GetController().LoadURL(
2275 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2277 // Simulate that navigation triggering an interstitial.
2278 TestInterstitialPage::InterstitialState state
=
2279 TestInterstitialPage::INVALID
;
2280 bool deleted
= false;
2281 TestInterstitialPage
* interstitial
=
2282 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2283 TestInterstitialPageStateGuard
state_guard(interstitial
);
2284 interstitial
->Show();
2285 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2286 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2288 // Initiate a new navigation from the browser that also triggers an
2290 contents()->GetController().LoadURL(
2291 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2292 TestInterstitialPage::InterstitialState state2
=
2293 TestInterstitialPage::INVALID
;
2294 bool deleted2
= false;
2295 TestInterstitialPage
* interstitial2
=
2296 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2297 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2298 interstitial2
->Show();
2299 interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2300 interstitial2
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2302 // Make sure we still have an entry.
2303 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2305 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2307 // And that the first interstitial is gone, but not the second.
2308 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2309 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2310 RunAllPendingInMessageLoop();
2311 EXPECT_TRUE(deleted
);
2312 EXPECT_FALSE(deleted2
);
2315 // Tests that Javascript messages are not shown while an interstitial is
2317 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2318 const char kUrl
[] = "http://www.badguys.com/";
2319 const GURL
kGURL(kUrl
);
2321 // Start a navigation to a page
2322 contents()->GetController().LoadURL(
2323 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2324 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2325 main_test_rfh()->PrepareForCommit();
2326 // DidNavigate from the page
2327 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id
, true,
2328 kGURL
, ui::PAGE_TRANSITION_TYPED
);
2330 // Simulate showing an interstitial while the page is showing.
2331 TestInterstitialPage::InterstitialState state
=
2332 TestInterstitialPage::INVALID
;
2333 bool deleted
= false;
2334 TestInterstitialPage
* interstitial
=
2335 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2336 TestInterstitialPageStateGuard
state_guard(interstitial
);
2337 interstitial
->Show();
2338 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2339 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, kGURL
);
2341 // While the interstitial is showing, let's simulate the hidden page
2342 // attempting to show a JS message.
2343 IPC::Message
* dummy_message
= new IPC::Message
;
2344 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2345 base::ASCIIToUTF16("This is an informative message"),
2346 base::ASCIIToUTF16("OK"),
2347 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2348 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2351 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2352 // interstitial it isn't copied over to the destination.
2353 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2354 // Navigate to a page.
2355 GURL
url1("http://www.google.com");
2356 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1
);
2357 EXPECT_EQ(1, controller().GetEntryCount());
2359 // Initiate a browser navigation that will trigger the interstitial
2360 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2361 ui::PAGE_TRANSITION_TYPED
, std::string());
2363 // Show an interstitial.
2364 TestInterstitialPage::InterstitialState state
=
2365 TestInterstitialPage::INVALID
;
2366 bool deleted
= false;
2367 GURL
url2("http://interstitial");
2368 TestInterstitialPage
* interstitial
=
2369 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2370 TestInterstitialPageStateGuard
state_guard(interstitial
);
2371 interstitial
->Show();
2372 int interstitial_entry_id
= controller().GetTransientEntry()->GetUniqueID();
2373 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url2
);
2374 EXPECT_TRUE(interstitial
->is_showing());
2375 EXPECT_EQ(2, controller().GetEntryCount());
2377 // Create another NavigationController.
2378 GURL
url3("http://foo2");
2379 scoped_ptr
<TestWebContents
> other_contents(
2380 static_cast<TestWebContents
*>(CreateTestWebContents()));
2381 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2382 other_contents
->NavigateAndCommit(url3
);
2383 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
2384 other_controller
.CopyStateFromAndPrune(&controller(), false);
2386 // The merged controller should only have two entries: url1 and url2.
2387 ASSERT_EQ(2, other_controller
.GetEntryCount());
2388 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2389 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2390 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2392 // And the merged controller shouldn't be showing an interstitial.
2393 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2396 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2397 // showing an interstitial.
2398 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2399 // Navigate to a page.
2400 GURL
url1("http://www.google.com");
2401 contents()->NavigateAndCommit(url1
);
2403 // Create another NavigationController.
2404 scoped_ptr
<TestWebContents
> other_contents(
2405 static_cast<TestWebContents
*>(CreateTestWebContents()));
2406 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2408 // Navigate it to url2.
2409 GURL
url2("http://foo2");
2410 other_contents
->NavigateAndCommit(url2
);
2412 // Show an interstitial.
2413 TestInterstitialPage::InterstitialState state
=
2414 TestInterstitialPage::INVALID
;
2415 bool deleted
= false;
2416 GURL
url3("http://interstitial");
2417 TestInterstitialPage
* interstitial
=
2418 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2420 TestInterstitialPageStateGuard
state_guard(interstitial
);
2421 interstitial
->Show();
2422 int interstitial_entry_id
=
2423 other_controller
.GetTransientEntry()->GetUniqueID();
2424 interstitial
->TestDidNavigate(1, interstitial_entry_id
, true, url3
);
2425 EXPECT_TRUE(interstitial
->is_showing());
2426 EXPECT_EQ(2, other_controller
.GetEntryCount());
2428 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2429 // interstitial is showing in the target.
2430 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2433 // Regression test for http://crbug.com/168611 - the URLs passed by the
2434 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2435 TEST_F(WebContentsImplTest
, FilterURLs
) {
2436 TestWebContentsObserver
observer(contents());
2438 // A navigation to about:whatever should always look like a navigation to
2440 GURL
url_normalized(url::kAboutBlankURL
);
2441 GURL
url_from_ipc("about:whatever");
2443 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2444 // will use the given URL to create the NavigationEntry as well, and that
2445 // entry should contain the filtered URL.
2446 contents()->NavigateAndCommit(url_normalized
);
2448 // Check that an IPC with about:whatever is correctly normalized.
2449 contents()->TestDidFinishLoad(url_from_ipc
);
2451 EXPECT_EQ(url_normalized
, observer
.last_url());
2453 // Create and navigate another WebContents.
2454 scoped_ptr
<TestWebContents
> other_contents(
2455 static_cast<TestWebContents
*>(CreateTestWebContents()));
2456 TestWebContentsObserver
other_observer(other_contents
.get());
2457 other_contents
->NavigateAndCommit(url_normalized
);
2459 // Check that an IPC with about:whatever is correctly normalized.
2460 other_contents
->TestDidFailLoadWithError(
2461 url_from_ipc
, 1, base::string16());
2462 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2465 // Test that if a pending contents is deleted before it is shown, we don't
2467 TEST_F(WebContentsImplTest
, PendingContents
) {
2468 scoped_ptr
<TestWebContents
> other_contents(
2469 static_cast<TestWebContents
*>(CreateTestWebContents()));
2470 contents()->AddPendingContents(other_contents
.get());
2471 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2472 other_contents
.reset();
2473 EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id
));
2476 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2477 const gfx::Size
original_preferred_size(1024, 768);
2478 contents()->UpdatePreferredSize(original_preferred_size
);
2480 // With no capturers, expect the preferred size to be the one propagated into
2481 // WebContentsImpl via the RenderViewHostDelegate interface.
2482 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2483 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2485 // Increment capturer count, but without specifying a capture size. Expect
2486 // a "not set" preferred size.
2487 contents()->IncrementCapturerCount(gfx::Size());
2488 EXPECT_EQ(1, contents()->GetCapturerCount());
2489 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2491 // Increment capturer count again, but with an overriding capture size.
2492 // Expect preferred size to now be overridden to the capture size.
2493 const gfx::Size
capture_size(1280, 720);
2494 contents()->IncrementCapturerCount(capture_size
);
2495 EXPECT_EQ(2, contents()->GetCapturerCount());
2496 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2498 // Increment capturer count a third time, but the expect that the preferred
2499 // size is still the first capture size.
2500 const gfx::Size
another_capture_size(720, 480);
2501 contents()->IncrementCapturerCount(another_capture_size
);
2502 EXPECT_EQ(3, contents()->GetCapturerCount());
2503 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2505 // Decrement capturer count twice, but expect the preferred size to still be
2507 contents()->DecrementCapturerCount();
2508 contents()->DecrementCapturerCount();
2509 EXPECT_EQ(1, contents()->GetCapturerCount());
2510 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2512 // Decrement capturer count, and since the count has dropped to zero, the
2513 // original preferred size should be restored.
2514 contents()->DecrementCapturerCount();
2515 EXPECT_EQ(0, contents()->GetCapturerCount());
2516 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2519 TEST_F(WebContentsImplTest
, CapturerPreventsHiding
) {
2520 const gfx::Size
original_preferred_size(1024, 768);
2521 contents()->UpdatePreferredSize(original_preferred_size
);
2523 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2524 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2526 // With no capturers, setting and un-setting occlusion should change the
2527 // view's occlusion state.
2528 EXPECT_FALSE(view
->is_showing());
2529 contents()->WasShown();
2530 EXPECT_TRUE(view
->is_showing());
2531 contents()->WasHidden();
2532 EXPECT_FALSE(view
->is_showing());
2533 contents()->WasShown();
2534 EXPECT_TRUE(view
->is_showing());
2536 // Add a capturer and try to hide the contents. The view will remain visible.
2537 contents()->IncrementCapturerCount(gfx::Size());
2538 contents()->WasHidden();
2539 EXPECT_TRUE(view
->is_showing());
2541 // Remove the capturer, and the WasHidden should take effect.
2542 contents()->DecrementCapturerCount();
2543 EXPECT_FALSE(view
->is_showing());
2546 TEST_F(WebContentsImplTest
, CapturerPreventsOcclusion
) {
2547 const gfx::Size
original_preferred_size(1024, 768);
2548 contents()->UpdatePreferredSize(original_preferred_size
);
2550 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2551 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2553 // With no capturers, setting and un-setting occlusion should change the
2554 // view's occlusion state.
2555 EXPECT_FALSE(view
->is_occluded());
2556 contents()->WasOccluded();
2557 EXPECT_TRUE(view
->is_occluded());
2558 contents()->WasUnOccluded();
2559 EXPECT_FALSE(view
->is_occluded());
2560 contents()->WasOccluded();
2561 EXPECT_TRUE(view
->is_occluded());
2563 // Add a capturer. This should cause the view to be un-occluded.
2564 contents()->IncrementCapturerCount(gfx::Size());
2565 EXPECT_FALSE(view
->is_occluded());
2567 // Try to occlude the view. This will fail to propagate because of the
2569 contents()->WasOccluded();
2570 EXPECT_FALSE(view
->is_occluded());
2572 // Remove the capturer and try again.
2573 contents()->DecrementCapturerCount();
2574 EXPECT_FALSE(view
->is_occluded());
2575 contents()->WasOccluded();
2576 EXPECT_TRUE(view
->is_occluded());
2579 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2581 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2582 // The WebContents starts with a valid creation time.
2583 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2585 // Reset the last active time to a known-bad value.
2586 contents()->last_active_time_
= base::TimeTicks();
2587 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2589 // Simulate activating the WebContents. The active time should update.
2590 contents()->WasShown();
2591 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2594 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2596 ContentsZoomChangedDelegate() :
2597 contents_zoom_changed_call_count_(0),
2598 last_zoom_in_(false) {
2601 int GetAndResetContentsZoomChangedCallCount() {
2602 int count
= contents_zoom_changed_call_count_
;
2603 contents_zoom_changed_call_count_
= 0;
2607 bool last_zoom_in() const {
2608 return last_zoom_in_
;
2611 // WebContentsDelegate:
2612 void ContentsZoomChange(bool zoom_in
) override
{
2613 contents_zoom_changed_call_count_
++;
2614 last_zoom_in_
= zoom_in
;
2618 int contents_zoom_changed_call_count_
;
2621 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2624 // Tests that some mouseehweel events get turned into browser zoom requests.
2625 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2626 using blink::WebInputEvent
;
2628 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2629 new ContentsZoomChangedDelegate());
2630 contents()->SetDelegate(delegate
.get());
2633 // Verify that normal mouse wheel events do nothing to change the zoom level.
2634 blink::WebMouseWheelEvent event
=
2635 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2636 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2637 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2639 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
|
2640 WebInputEvent::ControlKey
;
2641 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2642 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2643 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2645 // But whenever the ctrl modifier is applied with canScroll=false, they can
2646 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2648 modifiers
= WebInputEvent::ControlKey
;
2649 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2650 event
.canScroll
= false;
2651 bool handled
= contents()->HandleWheelEvent(event
);
2652 #if defined(OS_MACOSX)
2653 EXPECT_FALSE(handled
);
2654 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2656 EXPECT_TRUE(handled
);
2657 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2658 EXPECT_TRUE(delegate
->last_zoom_in());
2661 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2662 WebInputEvent::AltKey
;
2663 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2664 event
.canScroll
= false;
2665 handled
= contents()->HandleWheelEvent(event
);
2666 #if defined(OS_MACOSX)
2667 EXPECT_FALSE(handled
);
2668 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2670 EXPECT_TRUE(handled
);
2671 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2672 EXPECT_FALSE(delegate
->last_zoom_in());
2675 // Unless there is no vertical movement.
2676 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2677 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2678 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2680 // Events containing precise scrolling deltas also shouldn't result in the
2681 // zoom being adjusted, to avoid accidental adjustments caused by
2682 // two-finger-scrolling on a touchpad.
2683 modifiers
= WebInputEvent::ControlKey
;
2684 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2685 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2686 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2688 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2689 contents()->SetDelegate(nullptr);
2692 // Tests that GetRelatedActiveContentsCount is shared between related
2693 // SiteInstances and includes WebContents that have not navigated yet.
2694 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2695 scoped_refptr
<SiteInstance
> instance1(
2696 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2697 scoped_refptr
<SiteInstance
> instance2(
2698 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2700 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2701 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2703 scoped_ptr
<TestWebContents
> contents1(
2704 TestWebContents::Create(browser_context(), instance1
.get()));
2705 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2706 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2708 scoped_ptr
<TestWebContents
> contents2(
2709 TestWebContents::Create(browser_context(), instance1
.get()));
2710 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2711 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2714 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2715 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2718 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2719 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2722 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2723 // same-site and cross-site navigations.
2724 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2725 scoped_refptr
<SiteInstance
> instance(
2726 SiteInstance::Create(browser_context()));
2728 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2730 scoped_ptr
<TestWebContents
> contents(
2731 TestWebContents::Create(browser_context(), instance
.get()));
2732 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2734 // Navigate to a URL.
2735 contents
->GetController().LoadURL(GURL("http://a.com/1"),
2737 ui::PAGE_TRANSITION_TYPED
,
2739 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2740 contents
->CommitPendingNavigation();
2741 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2743 // Navigate to a URL in the same site.
2744 contents
->GetController().LoadURL(GURL("http://a.com/2"),
2746 ui::PAGE_TRANSITION_TYPED
,
2748 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2749 contents
->CommitPendingNavigation();
2750 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2752 // Navigate to a URL in a different site.
2753 const GURL kUrl
= GURL("http://b.com");
2754 contents
->GetController().LoadURL(kUrl
,
2756 ui::PAGE_TRANSITION_TYPED
,
2758 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2759 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2760 switches::kEnableBrowserSideNavigation
)) {
2761 contents
->GetMainFrame()->PrepareForCommit();
2763 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2764 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2765 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kUrl
);
2766 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2769 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2772 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2774 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2775 scoped_refptr
<SiteInstance
> instance(
2776 SiteInstance::Create(browser_context()));
2778 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2780 scoped_ptr
<TestWebContents
> contents(
2781 TestWebContents::Create(browser_context(), instance
.get()));
2782 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2784 // Navigate to a URL.
2785 contents
->NavigateAndCommit(GURL("http://a.com"));
2786 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2788 // Navigate to a URL which sort of looks like a chrome:// url.
2789 contents
->NavigateAndCommit(GURL("http://gpu"));
2790 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2792 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2793 const GURL kWebUIUrl
= GURL("chrome://gpu");
2794 contents
->GetController().LoadURL(kWebUIUrl
,
2796 ui::PAGE_TRANSITION_TYPED
,
2798 int entry_id
= contents
->GetController().GetPendingEntry()->GetUniqueID();
2799 contents
->GetMainFrame()->PrepareForCommit();
2800 EXPECT_TRUE(contents
->CrossProcessNavigationPending());
2801 scoped_refptr
<SiteInstance
> instance_webui(
2802 contents
->GetPendingMainFrame()->GetSiteInstance());
2803 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2805 // At this point, contents still counts for the old BrowsingInstance.
2806 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2807 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2809 // Commit and contents counts for the new one.
2810 contents
->GetPendingMainFrame()->SendNavigate(1, entry_id
, true, kWebUIUrl
);
2811 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2812 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2815 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2816 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2819 class LoadingWebContentsObserver
: public WebContentsObserver
{
2821 explicit LoadingWebContentsObserver(WebContents
* contents
)
2822 : WebContentsObserver(contents
),
2823 is_loading_(false) {
2825 ~LoadingWebContentsObserver() override
{}
2827 void DidStartLoading() override
{ is_loading_
= true; }
2828 void DidStopLoading() override
{ is_loading_
= false; }
2830 bool is_loading() const { return is_loading_
; }
2835 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver
);
2838 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2839 // interleaving cross-process navigations in multiple subframes.
2840 // See https://crbug.com/448601 for details of the underlying issue. The
2841 // sequence of events that reproduce it are as follows:
2842 // * Navigate top-level frame with one subframe.
2843 // * Subframe navigates more than once before the top-level frame has had a
2844 // chance to complete the load.
2845 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2846 // to 0, while the loading_progresses_ map is not reset.
2847 TEST_F(WebContentsImplTest
, StartStopEventsBalance
) {
2848 // The bug manifests itself in regular mode as well, but browser-initiated
2849 // navigation of subframes is only possible in --site-per-process mode within
2851 base::CommandLine::ForCurrentProcess()->AppendSwitch(
2852 switches::kSitePerProcess
);
2853 const GURL
initial_url("about:blank");
2854 const GURL
main_url("http://www.chromium.org");
2855 const GURL
foo_url("http://foo.chromium.org");
2856 const GURL
bar_url("http://bar.chromium.org");
2857 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
2859 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
2860 LoadingWebContentsObserver
observer(contents());
2862 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
2863 // The frame should still be loading.
2864 controller().LoadURL(
2865 main_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2866 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2867 orig_rfh
->PrepareForCommit();
2868 orig_rfh
->OnMessageReceived(
2869 FrameHostMsg_DidStartLoading(orig_rfh
->GetRoutingID(), false));
2870 contents()->TestDidNavigate(orig_rfh
, 1, entry_id
, true, main_url
,
2871 ui::PAGE_TRANSITION_TYPED
);
2872 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2873 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
2874 EXPECT_TRUE(contents()->IsLoading());
2875 EXPECT_TRUE(observer
.is_loading());
2877 // Create a child frame to navigate multiple times.
2878 TestRenderFrameHost
* subframe
= orig_rfh
->AppendChild("subframe");
2880 // Navigate the child frame to about:blank, which will send both
2881 // DidStartLoading and DidStopLoading messages.
2883 subframe
->SendRendererInitiatedNavigationRequest(initial_url
, false);
2884 subframe
->PrepareForCommit();
2885 subframe
->OnMessageReceived(
2886 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2887 subframe
->SendNavigateWithTransition(1, 0, false, initial_url
,
2888 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2889 subframe
->OnMessageReceived(
2890 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2893 // Navigate the frame to another URL, which will send again
2894 // DidStartLoading and DidStopLoading messages.
2896 subframe
->SendRendererInitiatedNavigationRequest(foo_url
, false);
2897 subframe
->PrepareForCommit();
2898 subframe
->OnMessageReceived(
2899 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2900 subframe
->SendNavigateWithTransition(1, 0, false, foo_url
,
2901 ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2902 subframe
->OnMessageReceived(
2903 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2906 // Since the main frame hasn't sent any DidStopLoading messages, it is
2907 // expected that the WebContents is still in loading state.
2908 EXPECT_TRUE(contents()->IsLoading());
2909 EXPECT_TRUE(observer
.is_loading());
2911 // Navigate the frame again, this time using LoadURLWithParams. This causes
2912 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2915 NavigationController::LoadURLParams
load_params(bar_url
);
2916 load_params
.referrer
=
2917 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
2918 load_params
.transition_type
= ui::PAGE_TRANSITION_GENERATED
;
2919 load_params
.extra_headers
= "content-type: text/plain";
2920 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
2921 load_params
.is_renderer_initiated
= false;
2922 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
2923 load_params
.frame_tree_node_id
=
2924 subframe
->frame_tree_node()->frame_tree_node_id();
2925 controller().LoadURLWithParams(load_params
);
2926 entry_id
= controller().GetPendingEntry()->GetUniqueID();
2928 subframe
->OnMessageReceived(
2929 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2931 // Commit the navigation in the child frame and send the DidStopLoading
2933 subframe
->PrepareForCommit();
2934 contents()->TestDidNavigate(subframe
, 3, entry_id
, true, bar_url
,
2935 ui::PAGE_TRANSITION_MANUAL_SUBFRAME
);
2936 subframe
->OnMessageReceived(
2937 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2940 // At this point the status should still be loading, since the main frame
2941 // hasn't sent the DidstopLoading message yet.
2942 EXPECT_TRUE(contents()->IsLoading());
2943 EXPECT_TRUE(observer
.is_loading());
2945 // Send the DidStopLoading for the main frame and ensure it isn't loading
2947 orig_rfh
->OnMessageReceived(
2948 FrameHostMsg_DidStopLoading(orig_rfh
->GetRoutingID()));
2949 EXPECT_FALSE(contents()->IsLoading());
2950 EXPECT_FALSE(observer
.is_loading());
2953 // Ensure that WebContentsImpl does not stop loading too early when there still
2954 // is a pending renderer. This can happen if a same-process non user-initiated
2955 // navigation completes while there is an ongoing cross-process navigation.
2956 // TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
2957 // DidStopLoading are properly called.
2958 TEST_F(WebContentsImplTest
, NoEarlyStop
) {
2959 const GURL
kUrl1("http://www.chromium.org");
2960 const GURL
kUrl2("http://www.google.com");
2961 const GURL
kUrl3("http://www.wikipedia.org");
2963 contents()->NavigateAndCommit(kUrl1
);
2965 TestRenderFrameHost
* current_rfh
= contents()->GetMainFrame();
2967 // Start a browser-initiated cross-process navigation to |kUrl2|. There should
2968 // be a pending RenderFrameHost and the WebContents should be loading.
2969 controller().LoadURL(
2970 kUrl2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2971 int entry_id
= controller().GetPendingEntry()->GetUniqueID();
2972 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
2973 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
2974 ASSERT_TRUE(pending_rfh
);
2975 EXPECT_TRUE(contents()->IsLoading());
2977 // The current RenderFrameHost starts a non user-initiated render-initiated
2978 // navigation and sends a DidStartLoading IPC. The WebContents should still be
2980 current_rfh
->OnMessageReceived(
2981 FrameHostMsg_DidStartLoading(current_rfh
->GetRoutingID(), false));
2982 EXPECT_TRUE(contents()->IsLoading());
2984 // Simulate the pending RenderFrameHost DidStartLoading. There should still be
2985 // a pending RenderFrameHost and the WebContents should still be loading.
2986 pending_rfh
->PrepareForCommit();
2987 pending_rfh
->OnMessageReceived(
2988 FrameHostMsg_DidStartLoading(pending_rfh
->GetRoutingID(), false));
2989 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
2990 EXPECT_TRUE(contents()->IsLoading());
2992 // Simulate the commit and DidStopLoading from the renderer-initiated
2993 // navigation in the current RenderFrameHost. There should still be a pending
2994 // RenderFrameHost and the WebContents should still be loading.
2995 current_rfh
->SendNavigate(1, 0, true, kUrl3
);
2996 current_rfh
->OnMessageReceived(
2997 FrameHostMsg_DidStopLoading(current_rfh
->GetRoutingID()));
2998 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh
);
2999 EXPECT_TRUE(contents()->IsLoading());
3001 // Commit the navigation. The formerly pending RenderFrameHost should now be
3002 // the current RenderFrameHost and the WebContents should still be loading.
3003 contents()->TestDidNavigate(pending_rfh
, 1, entry_id
, true, kUrl2
,
3004 ui::PAGE_TRANSITION_TYPED
);
3005 EXPECT_FALSE(contents()->GetPendingMainFrame());
3006 TestRenderFrameHost
* new_current_rfh
= contents()->GetMainFrame();
3007 EXPECT_EQ(new_current_rfh
, pending_rfh
);
3008 EXPECT_TRUE(contents()->IsLoading());
3010 // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
3011 // should now have stopped loading.
3012 new_current_rfh
->OnMessageReceived(
3013 FrameHostMsg_DidStopLoading(new_current_rfh
->GetRoutingID()));
3014 EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh
);
3015 EXPECT_FALSE(contents()->IsLoading());
3018 TEST_F(WebContentsImplTest
, MediaPowerSaveBlocking
) {
3019 // PlayerIDs are actually pointers cast to int64, so verify that both negative
3020 // and positive player ids don't blow up.
3021 const int kPlayerAudioVideoId
= 15;
3022 const int kPlayerAudioOnlyId
= -15;
3023 const int kPlayerVideoOnlyId
= 30;
3024 const int kPlayerRemoteId
= -30;
3026 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3027 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3029 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3030 AudioStateProvider
* audio_state
= contents()->audio_state_provider();
3032 // Ensure RenderFrame is initialized before simulating events coming from it.
3033 main_test_rfh()->InitializeRenderFrameIfNeeded();
3035 // The audio power save blocker should not be based on having a media player
3036 // when audio stream monitoring is available.
3037 if (audio_state
->IsAudioStateAvailable()) {
3038 // Send a fake audio stream monitor notification. The audio power save
3039 // blocker should be created.
3040 audio_state
->set_was_recently_audible_for_testing(true);
3041 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3042 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
3044 // Send another fake notification, this time when WasRecentlyAudible() will
3045 // be false. The power save blocker should be released.
3046 audio_state
->set_was_recently_audible_for_testing(false);
3047 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
3048 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3051 // Start a player with both audio and video. A video power save blocker
3052 // should be created. If audio stream monitoring is available, an audio power
3053 // save blocker should be created too.
3054 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3055 0, kPlayerAudioVideoId
, true, true, false));
3056 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3057 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3058 !audio_state
->IsAudioStateAvailable());
3060 // Upon hiding the video power save blocker should be released.
3061 contents()->WasHidden();
3062 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3064 // Start another player that only has video. There should be no change in
3065 // the power save blockers. The notification should take into account the
3066 // visibility state of the WebContents.
3067 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3068 0, kPlayerVideoOnlyId
, true, false, false));
3069 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3070 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3071 !audio_state
->IsAudioStateAvailable());
3073 // Showing the WebContents should result in the creation of the blocker.
3074 contents()->WasShown();
3075 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3077 // Start another player that only has audio. There should be no change in
3078 // the power save blockers.
3079 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3080 0, kPlayerAudioOnlyId
, false, true, false));
3081 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3082 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3083 !audio_state
->IsAudioStateAvailable());
3085 // Start a remote player. There should be no change in the power save
3087 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3088 0, kPlayerRemoteId
, true, true, true));
3089 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3090 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3091 !audio_state
->IsAudioStateAvailable());
3093 // Destroy the original audio video player. Both power save blockers should
3095 rfh
->OnMessageReceived(
3096 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId
));
3097 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3098 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3099 !audio_state
->IsAudioStateAvailable());
3101 // Destroy the audio only player. The video power save blocker should remain.
3102 rfh
->OnMessageReceived(
3103 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId
));
3104 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3105 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3107 // Destroy the video only player. No power save blockers should remain.
3108 rfh
->OnMessageReceived(
3109 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId
));
3110 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3111 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3113 // Destroy the remote player. No power save blockers should remain.
3114 rfh
->OnMessageReceived(
3115 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId
));
3116 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3117 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3119 // Start a player with both audio and video. A video power save blocker
3120 // should be created. If audio stream monitoring is available, an audio power
3121 // save blocker should be created too.
3122 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3123 0, kPlayerAudioVideoId
, true, true, false));
3124 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3125 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3126 !audio_state
->IsAudioStateAvailable());
3128 // Crash the renderer.
3129 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
3131 // Verify that all the power save blockers have been released.
3132 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3133 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3136 TEST_F(WebContentsImplTest
, ThemeColorChangeDependingOnFirstVisiblePaint
) {
3137 TestWebContentsObserver
observer(contents());
3138 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
3140 SkColor transparent
= SK_ColorTRANSPARENT
;
3142 EXPECT_EQ(transparent
, contents()->GetThemeColor());
3143 EXPECT_EQ(transparent
, observer
.last_theme_color());
3145 // Theme color changes should not propagate past the WebContentsImpl before
3146 // the first visually non-empty paint has occurred.
3147 RenderViewHostTester::TestOnMessageReceived(
3149 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorRED
));
3151 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3152 EXPECT_EQ(transparent
, observer
.last_theme_color());
3154 // Simulate that the first visually non-empty paint has occurred. This will
3155 // propagate the current theme color to the delegates.
3156 RenderViewHostTester::TestOnMessageReceived(
3158 FrameHostMsg_DidFirstVisuallyNonEmptyPaint(rfh
->GetRoutingID()));
3160 EXPECT_EQ(SK_ColorRED
, contents()->GetThemeColor());
3161 EXPECT_EQ(SK_ColorRED
, observer
.last_theme_color());
3163 // Additional changes made by the web contents should propagate as well.
3164 RenderViewHostTester::TestOnMessageReceived(
3166 FrameHostMsg_DidChangeThemeColor(rfh
->GetRoutingID(), SK_ColorGREEN
));
3168 EXPECT_EQ(SK_ColorGREEN
, contents()->GetThemeColor());
3169 EXPECT_EQ(SK_ColorGREEN
, observer
.last_theme_color());
3172 } // namespace content