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_stream_monitor.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/web_ui_controller_factory_registry.h"
16 #include "content/common/frame_messages.h"
17 #include "content/common/input/synthetic_web_input_event_builders.h"
18 #include "content/common/view_messages.h"
19 #include "content/public/browser/global_request_id.h"
20 #include "content/public/browser/interstitial_page_delegate.h"
21 #include "content/public/browser/navigation_details.h"
22 #include "content/public/browser/notification_details.h"
23 #include "content/public/browser/notification_source.h"
24 #include "content/public/browser/render_widget_host_view.h"
25 #include "content/public/browser/web_contents_delegate.h"
26 #include "content/public/browser/web_contents_observer.h"
27 #include "content/public/browser/web_ui_controller.h"
28 #include "content/public/common/bindings_policy.h"
29 #include "content/public/common/content_constants.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/common/url_constants.h"
32 #include "content/public/common/url_utils.h"
33 #include "content/public/test/mock_render_process_host.h"
34 #include "content/public/test/test_utils.h"
35 #include "content/test/test_content_browser_client.h"
36 #include "content/test/test_content_client.h"
37 #include "content/test/test_render_frame_host.h"
38 #include "content/test/test_render_view_host.h"
39 #include "content/test/test_web_contents.h"
40 #include "testing/gtest/include/gtest/gtest.h"
45 const char kTestWebUIUrl
[] = "chrome://blah";
47 class WebContentsImplTestWebUIControllerFactory
48 : public WebUIControllerFactory
{
50 WebUIController
* CreateWebUIControllerForURL(WebUI
* web_ui
,
51 const GURL
& url
) const override
{
54 return new WebUIController(web_ui
);
57 WebUI::TypeID
GetWebUIType(BrowserContext
* browser_context
,
58 const GURL
& url
) const override
{
59 return WebUI::kNoWebUI
;
62 bool UseWebUIForURL(BrowserContext
* browser_context
,
63 const GURL
& url
) const override
{
67 bool UseWebUIBindingsForURL(BrowserContext
* browser_context
,
68 const GURL
& url
) const override
{
73 bool UseWebUI(const GURL
& url
) const {
74 return url
== GURL(kTestWebUIUrl
);
78 class TestInterstitialPage
;
80 class TestInterstitialPageDelegate
: public InterstitialPageDelegate
{
82 explicit TestInterstitialPageDelegate(TestInterstitialPage
* interstitial_page
)
83 : interstitial_page_(interstitial_page
) {}
84 void CommandReceived(const std::string
& command
) override
;
85 std::string
GetHTMLContents() override
{ return std::string(); }
86 void OnDontProceed() override
;
87 void OnProceed() override
;
90 TestInterstitialPage
* interstitial_page_
;
93 class TestInterstitialPage
: public InterstitialPageImpl
{
95 enum InterstitialState
{
96 INVALID
= 0, // Hasn't yet been initialized.
97 UNDECIDED
, // Initialized, but no decision taken yet.
98 OKED
, // Proceed was called.
99 CANCELED
// DontProceed was called.
104 virtual void TestInterstitialPageDeleted(
105 TestInterstitialPage
* interstitial
) = 0;
108 virtual ~Delegate() {}
111 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
112 // |deleted| (like all interstitial related tests do at this point), make sure
113 // to create an instance of the TestInterstitialPageStateGuard class on the
114 // stack in your test. This will ensure that the TestInterstitialPage states
115 // are cleared when the test finishes.
116 // Not doing so will cause stack trashing if your test does not hide the
117 // interstitial, as in such a case it will be destroyed in the test TearDown
118 // method and will dereference the |deleted| local variable which by then is
120 TestInterstitialPage(WebContentsImpl
* contents
,
123 InterstitialState
* state
,
125 : InterstitialPageImpl(
127 static_cast<RenderWidgetHostDelegate
*>(contents
),
128 new_navigation
, url
, new TestInterstitialPageDelegate(this)),
131 command_received_count_(0),
137 ~TestInterstitialPage() override
{
141 delegate_
->TestInterstitialPageDeleted(this);
144 void OnDontProceed() {
153 int command_received_count() const {
154 return command_received_count_
;
157 void TestDomOperationResponse(const std::string
& json_string
) {
162 void TestDidNavigate(int page_id
, const GURL
& url
) {
163 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
164 InitNavigateParams(¶ms
, page_id
, url
, ui::PAGE_TRANSITION_TYPED
);
165 DidNavigate(GetMainFrame()->GetRenderViewHost(), params
);
168 void TestRenderViewTerminated(base::TerminationStatus status
,
170 RenderViewTerminated(GetMainFrame()->GetRenderViewHost(), status
,
174 bool is_showing() const {
175 return static_cast<TestRenderWidgetHostView
*>(
176 GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
185 void CommandReceived() {
186 command_received_count_
++;
189 void set_delegate(Delegate
* delegate
) {
190 delegate_
= delegate
;
194 WebContentsView
* CreateWebContentsView() override
{ return NULL
; }
197 InterstitialState
* state_
;
199 int command_received_count_
;
203 void TestInterstitialPageDelegate::CommandReceived(const std::string
& command
) {
204 interstitial_page_
->CommandReceived();
207 void TestInterstitialPageDelegate::OnDontProceed() {
208 interstitial_page_
->OnDontProceed();
211 void TestInterstitialPageDelegate::OnProceed() {
212 interstitial_page_
->OnProceed();
215 class TestInterstitialPageStateGuard
: public TestInterstitialPage::Delegate
{
217 explicit TestInterstitialPageStateGuard(
218 TestInterstitialPage
* interstitial_page
)
219 : interstitial_page_(interstitial_page
) {
220 DCHECK(interstitial_page_
);
221 interstitial_page_
->set_delegate(this);
223 ~TestInterstitialPageStateGuard() override
{
224 if (interstitial_page_
)
225 interstitial_page_
->ClearStates();
228 void TestInterstitialPageDeleted(
229 TestInterstitialPage
* interstitial
) override
{
230 DCHECK(interstitial_page_
== interstitial
);
231 interstitial_page_
= NULL
;
235 TestInterstitialPage
* interstitial_page_
;
238 class WebContentsImplTestBrowserClient
: public TestContentBrowserClient
{
240 WebContentsImplTestBrowserClient()
241 : assign_site_for_url_(false) {}
243 ~WebContentsImplTestBrowserClient() override
{}
245 bool ShouldAssignSiteForURL(const GURL
& url
) override
{
246 return assign_site_for_url_
;
249 void set_assign_site_for_url(bool assign
) {
250 assign_site_for_url_
= assign
;
254 bool assign_site_for_url_
;
257 class WebContentsImplTest
: public RenderViewHostImplTestHarness
{
259 void SetUp() override
{
260 RenderViewHostImplTestHarness::SetUp();
261 WebUIControllerFactory::RegisterFactory(&factory_
);
264 void TearDown() override
{
265 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_
);
266 RenderViewHostImplTestHarness::TearDown();
270 WebContentsImplTestWebUIControllerFactory factory_
;
273 class TestWebContentsObserver
: public WebContentsObserver
{
275 explicit TestWebContentsObserver(WebContents
* contents
)
276 : WebContentsObserver(contents
) {
278 ~TestWebContentsObserver() override
{}
280 void DidFinishLoad(RenderFrameHost
* render_frame_host
,
281 const GURL
& validated_url
) override
{
282 last_url_
= validated_url
;
284 void DidFailLoad(RenderFrameHost
* render_frame_host
,
285 const GURL
& validated_url
,
287 const base::string16
& error_description
) override
{
288 last_url_
= validated_url
;
291 const GURL
& last_url() const { return last_url_
; }
296 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver
);
299 // Pretends to be a normal browser that receives toggles and transitions to/from
300 // a fullscreened state.
301 class FakeFullscreenDelegate
: public WebContentsDelegate
{
303 FakeFullscreenDelegate() : fullscreened_contents_(NULL
) {}
304 ~FakeFullscreenDelegate() override
{}
306 void EnterFullscreenModeForTab(WebContents
* web_contents
,
307 const GURL
& origin
) override
{
308 fullscreened_contents_
= web_contents
;
311 void ExitFullscreenModeForTab(WebContents
* web_contents
) override
{
312 fullscreened_contents_
= NULL
;
315 bool IsFullscreenForTabOrPending(
316 const WebContents
* web_contents
) const override
{
317 return fullscreened_contents_
&& web_contents
== fullscreened_contents_
;
321 WebContents
* fullscreened_contents_
;
323 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate
);
326 class FakeValidationMessageDelegate
: public WebContentsDelegate
{
328 FakeValidationMessageDelegate()
329 : hide_validation_message_was_called_(false) {}
330 ~FakeValidationMessageDelegate() override
{}
332 void HideValidationMessage(WebContents
* web_contents
) override
{
333 hide_validation_message_was_called_
= true;
336 bool hide_validation_message_was_called() const {
337 return hide_validation_message_was_called_
;
341 bool hide_validation_message_was_called_
;
343 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate
);
348 // Test to make sure that title updates get stripped of whitespace.
349 TEST_F(WebContentsImplTest
, UpdateTitle
) {
350 NavigationControllerImpl
& cont
=
351 static_cast<NavigationControllerImpl
&>(controller());
352 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
354 ¶ms
, 0, GURL(url::kAboutBlankURL
), ui::PAGE_TRANSITION_TYPED
);
356 LoadCommittedDetails details
;
357 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
359 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
360 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
361 base::i18n::LEFT_TO_RIGHT
);
362 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
365 TEST_F(WebContentsImplTest
, DontUseTitleFromPendingEntry
) {
366 const GURL
kGURL("chrome://blah");
367 controller().LoadURL(
368 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
369 EXPECT_EQ(base::string16(), contents()->GetTitle());
372 TEST_F(WebContentsImplTest
, UseTitleFromPendingEntryIfSet
) {
373 const GURL
kGURL("chrome://blah");
374 const base::string16 title
= base::ASCIIToUTF16("My Title");
375 controller().LoadURL(
376 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
378 NavigationEntry
* entry
= controller().GetVisibleEntry();
379 ASSERT_EQ(kGURL
, entry
->GetURL());
380 entry
->SetTitle(title
);
382 EXPECT_EQ(title
, contents()->GetTitle());
385 // Test view source mode for a webui page.
386 TEST_F(WebContentsImplTest
, NTPViewSource
) {
387 NavigationControllerImpl
& cont
=
388 static_cast<NavigationControllerImpl
&>(controller());
389 const char kUrl
[] = "view-source:chrome://blah";
390 const GURL
kGURL(kUrl
);
392 process()->sink().ClearMessages();
395 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
396 rvh()->GetDelegate()->RenderViewCreated(rvh());
397 // Did we get the expected message?
398 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
399 ViewMsg_EnableViewSourceMode::ID
));
401 FrameHostMsg_DidCommitProvisionalLoad_Params params
;
402 InitNavigateParams(¶ms
, 0, kGURL
, ui::PAGE_TRANSITION_TYPED
);
403 LoadCommittedDetails details
;
404 cont
.RendererDidNavigate(contents()->GetMainFrame(), params
, &details
);
405 // Also check title and url.
406 EXPECT_EQ(base::ASCIIToUTF16(kUrl
), contents()->GetTitle());
409 // Test to ensure UpdateMaxPageID is working properly.
410 TEST_F(WebContentsImplTest
, UpdateMaxPageID
) {
411 SiteInstance
* instance1
= contents()->GetSiteInstance();
412 scoped_refptr
<SiteInstance
> instance2(SiteInstance::Create(NULL
));
415 EXPECT_EQ(-1, contents()->GetMaxPageID());
416 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1
));
417 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
419 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
420 contents()->UpdateMaxPageID(3);
421 contents()->UpdateMaxPageID(1);
422 EXPECT_EQ(3, contents()->GetMaxPageID());
423 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
424 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
426 contents()->UpdateMaxPageIDForSiteInstance(instance2
.get(), 7);
427 EXPECT_EQ(3, contents()->GetMaxPageID());
428 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1
));
429 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2
.get()));
432 // Test simple same-SiteInstance navigation.
433 TEST_F(WebContentsImplTest
, SimpleNavigation
) {
434 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
435 SiteInstance
* instance1
= contents()->GetSiteInstance();
436 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
439 const GURL
url("http://www.google.com");
440 controller().LoadURL(
441 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
442 EXPECT_FALSE(contents()->cross_navigation_pending());
443 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
444 // Controller's pending entry will have a NULL site instance until we assign
445 // it in DidNavigate.
447 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
448 site_instance() == NULL
);
450 // DidNavigate from the page
451 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
452 EXPECT_FALSE(contents()->cross_navigation_pending());
453 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
454 EXPECT_EQ(instance1
, orig_rfh
->GetSiteInstance());
455 // Controller's entry should now have the SiteInstance, or else we won't be
456 // able to find it later.
459 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
463 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
464 TEST_F(WebContentsImplTest
, NavigateToExcessivelyLongURL
) {
465 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
466 const GURL
url(std::string("http://example.org/").append(
467 GetMaxURLChars() + 1, 'a'));
469 controller().LoadURL(
470 url
, Referrer(), ui::PAGE_TRANSITION_GENERATED
, std::string());
471 EXPECT_TRUE(controller().GetVisibleEntry() == NULL
);
474 // Test that navigating across a site boundary creates a new RenderViewHost
475 // with a new SiteInstance. Going back should do the same.
476 TEST_F(WebContentsImplTest
, CrossSiteBoundaries
) {
477 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
478 int orig_rvh_delete_count
= 0;
479 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
480 SiteInstance
* instance1
= contents()->GetSiteInstance();
482 // Navigate to URL. First URL should use first RenderViewHost.
483 const GURL
url("http://www.google.com");
484 controller().LoadURL(
485 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
486 orig_rfh
->PrepareForCommit(url
);
487 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
489 // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
490 // that orig_rfh doesn't get deleted when it gets swapped out.
491 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
493 EXPECT_FALSE(contents()->cross_navigation_pending());
494 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
495 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
496 EXPECT_EQ(url
, contents()->GetVisibleURL());
498 // Navigate to new site
499 const GURL
url2("http://www.yahoo.com");
500 controller().LoadURL(
501 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
502 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
503 switches::kEnableBrowserSideNavigation
)) {
504 orig_rfh
->PrepareForCommit(url2
);
506 EXPECT_TRUE(contents()->cross_navigation_pending());
507 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
508 EXPECT_EQ(url2
, contents()->GetVisibleURL());
509 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
510 int pending_rvh_delete_count
= 0;
511 pending_rfh
->GetRenderViewHost()->set_delete_counter(
512 &pending_rvh_delete_count
);
514 // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
515 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
516 switches::kEnableBrowserSideNavigation
)) {
517 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
518 orig_rfh
->SendBeforeUnloadACK(true);
519 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
522 // DidNavigate from the pending page
523 pending_rfh
->PrepareForCommit(url2
);
524 contents()->TestDidNavigate(
525 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
526 SiteInstance
* instance2
= contents()->GetSiteInstance();
528 // Keep the number of active frames in pending_rfh's SiteInstance
529 // non-zero so that orig_rfh doesn't get deleted when it gets
531 pending_rfh
->GetSiteInstance()->increment_active_frame_count();
533 EXPECT_FALSE(contents()->cross_navigation_pending());
534 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
535 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
536 EXPECT_EQ(url2
, contents()->GetVisibleURL());
537 EXPECT_NE(instance1
, instance2
);
538 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
539 // We keep the original RFH around, swapped out.
540 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
542 EXPECT_EQ(orig_rvh_delete_count
, 0);
544 // Going back should switch SiteInstances again. The first SiteInstance is
545 // stored in the NavigationEntry, so it should be the same as at the start.
546 // We should use the same RFH as before, swapping it back in.
547 controller().GoBack();
548 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
549 switches::kEnableBrowserSideNavigation
)) {
550 contents()->GetMainFrame()->PrepareForCommit(url
);
552 TestRenderFrameHost
* goback_rfh
= contents()->GetPendingMainFrame();
553 EXPECT_EQ(orig_rfh
, goback_rfh
);
554 EXPECT_TRUE(contents()->cross_navigation_pending());
556 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
557 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
558 switches::kEnableBrowserSideNavigation
)) {
559 EXPECT_TRUE(goback_rfh
->are_navigations_suspended());
560 pending_rfh
->SendBeforeUnloadACK(true);
561 EXPECT_FALSE(goback_rfh
->are_navigations_suspended());
564 // DidNavigate from the back action
565 contents()->TestDidNavigate(goback_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
566 EXPECT_FALSE(contents()->cross_navigation_pending());
567 EXPECT_EQ(goback_rfh
, contents()->GetMainFrame());
568 EXPECT_EQ(instance1
, contents()->GetSiteInstance());
569 // The pending RFH should now be swapped out, not deleted.
570 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
571 IsOnSwappedOutList(pending_rfh
));
572 EXPECT_EQ(pending_rvh_delete_count
, 0);
573 pending_rfh
->OnSwappedOut();
575 // Close contents and ensure RVHs are deleted.
577 EXPECT_EQ(orig_rvh_delete_count
, 1);
578 EXPECT_EQ(pending_rvh_delete_count
, 1);
581 // Test that navigating across a site boundary after a crash creates a new
582 // RFH without requiring a cross-site transition (i.e., PENDING state).
583 TEST_F(WebContentsImplTest
, CrossSiteBoundariesAfterCrash
) {
584 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
586 int orig_rvh_delete_count
= 0;
587 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
588 SiteInstance
* instance1
= contents()->GetSiteInstance();
590 // Navigate to URL. First URL should use first RenderViewHost.
591 const GURL
url("http://www.google.com");
592 controller().LoadURL(
593 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
594 contents()->GetMainFrame()->PrepareForCommit(url
);
595 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
597 EXPECT_FALSE(contents()->cross_navigation_pending());
598 EXPECT_EQ(orig_rfh
->GetRenderViewHost(), contents()->GetRenderViewHost());
600 // Simulate a renderer crash.
601 orig_rfh
->GetRenderViewHost()->set_render_view_created(false);
602 orig_rfh
->SetRenderFrameCreated(false);
604 // Navigate to new site. We should not go into PENDING.
605 const GURL
url2("http://www.yahoo.com");
606 controller().LoadURL(
607 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
608 contents()->GetMainFrame()->PrepareForCommit(url2
);
609 TestRenderFrameHost
* new_rfh
= contents()->GetMainFrame();
610 EXPECT_FALSE(contents()->cross_navigation_pending());
611 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
612 EXPECT_NE(orig_rfh
, new_rfh
);
613 EXPECT_EQ(orig_rvh_delete_count
, 1);
615 // DidNavigate from the new page
616 contents()->TestDidNavigate(new_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
617 SiteInstance
* instance2
= contents()->GetSiteInstance();
619 EXPECT_FALSE(contents()->cross_navigation_pending());
620 EXPECT_EQ(new_rfh
, main_rfh());
621 EXPECT_NE(instance1
, instance2
);
622 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
624 // Close contents and ensure RVHs are deleted.
626 EXPECT_EQ(orig_rvh_delete_count
, 1);
629 // Test that opening a new contents in the same SiteInstance and then navigating
630 // both contentses to a new site will place both contentses in a single
632 TEST_F(WebContentsImplTest
, NavigateTwoTabsCrossSite
) {
633 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
634 SiteInstance
* instance1
= contents()->GetSiteInstance();
636 // Navigate to URL. First URL should use first RenderViewHost.
637 const GURL
url("http://www.google.com");
638 controller().LoadURL(
639 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
640 contents()->GetMainFrame()->PrepareForCommit(url
);
641 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
643 // Open a new contents with the same SiteInstance, navigated to the same site.
644 scoped_ptr
<TestWebContents
> contents2(
645 TestWebContents::Create(browser_context(), instance1
));
646 contents2
->GetController().LoadURL(url
, Referrer(),
647 ui::PAGE_TRANSITION_TYPED
,
649 contents2
->GetMainFrame()->PrepareForCommit(url
);
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(
653 contents2
->GetMainFrame(), 2, url
, 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 orig_rfh
->PrepareForCommit(url2a
);
660 TestRenderFrameHost
* pending_rfh_a
= contents()->GetPendingMainFrame();
661 contents()->TestDidNavigate(
662 pending_rfh_a
, 1, url2a
, ui::PAGE_TRANSITION_TYPED
);
663 SiteInstance
* instance2a
= contents()->GetSiteInstance();
664 EXPECT_NE(instance1
, instance2a
);
666 // Navigate second contents to the same site as the first tab.
667 const GURL
url2b("http://mail.yahoo.com");
668 contents2
->GetController().LoadURL(url2b
, Referrer(),
669 ui::PAGE_TRANSITION_TYPED
,
671 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
672 rfh2
->PrepareForCommit(url2b
);
673 TestRenderFrameHost
* pending_rfh_b
= contents2
->GetPendingMainFrame();
674 EXPECT_TRUE(pending_rfh_b
!= NULL
);
675 EXPECT_TRUE(contents2
->cross_navigation_pending());
677 // NOTE(creis): We used to be in danger of showing a crash page here if the
678 // second contents hadn't navigated somewhere first (bug 1145430). That case
679 // is now covered by the CrossSiteBoundariesAfterCrash test.
680 contents2
->TestDidNavigate(
681 pending_rfh_b
, 2, url2b
, ui::PAGE_TRANSITION_TYPED
);
682 SiteInstance
* instance2b
= contents2
->GetSiteInstance();
683 EXPECT_NE(instance1
, instance2b
);
685 // Both contentses should now be in the same SiteInstance.
686 EXPECT_EQ(instance2a
, instance2b
);
689 // The embedder can request sites for certain urls not be be assigned to the
690 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
691 // allowing to reuse the renderer backing certain chrome urls for subsequent
692 // navigation. The test verifies that the override is honored.
693 TEST_F(WebContentsImplTest
, NavigateFromSitelessUrl
) {
694 WebContentsImplTestBrowserClient browser_client
;
695 SetBrowserClientForTesting(&browser_client
);
697 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
698 int orig_rvh_delete_count
= 0;
699 orig_rfh
->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count
);
700 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
702 browser_client
.set_assign_site_for_url(false);
703 // Navigate to an URL that will not assign a new SiteInstance.
704 const GURL
native_url("non-site-url://stuffandthings");
705 controller().LoadURL(
706 native_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
707 contents()->GetMainFrame()->PrepareForCommit(native_url
);
708 contents()->TestDidNavigate(
709 orig_rfh
, 1, native_url
, ui::PAGE_TRANSITION_TYPED
);
711 EXPECT_FALSE(contents()->cross_navigation_pending());
712 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
713 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
714 EXPECT_EQ(native_url
, contents()->GetVisibleURL());
715 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
716 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
717 EXPECT_FALSE(orig_instance
->HasSite());
719 browser_client
.set_assign_site_for_url(true);
720 // Navigate to new site (should keep same site instance).
721 const GURL
url("http://www.google.com");
722 controller().LoadURL(
723 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
724 contents()->GetMainFrame()->PrepareForCommit(url
);
725 EXPECT_FALSE(contents()->cross_navigation_pending());
726 EXPECT_EQ(native_url
, contents()->GetLastCommittedURL());
727 EXPECT_EQ(url
, contents()->GetVisibleURL());
728 EXPECT_FALSE(contents()->GetPendingMainFrame());
729 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
731 // Keep the number of active frames in orig_rfh's SiteInstance
732 // non-zero so that orig_rfh doesn't get deleted when it gets
734 orig_rfh
->GetSiteInstance()->increment_active_frame_count();
736 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
738 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
739 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
741 // Navigate to another new site (should create a new site instance).
742 const GURL
url2("http://www.yahoo.com");
743 controller().LoadURL(
744 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
745 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
746 switches::kEnableBrowserSideNavigation
)) {
747 orig_rfh
->PrepareForCommit(url2
);
749 EXPECT_TRUE(contents()->cross_navigation_pending());
750 EXPECT_EQ(url
, contents()->GetLastCommittedURL());
751 EXPECT_EQ(url2
, contents()->GetVisibleURL());
752 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
753 int pending_rvh_delete_count
= 0;
754 pending_rfh
->GetRenderViewHost()->set_delete_counter(
755 &pending_rvh_delete_count
);
757 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
758 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
759 switches::kEnableBrowserSideNavigation
)) {
760 EXPECT_TRUE(pending_rfh
->are_navigations_suspended());
761 orig_rfh
->SendBeforeUnloadACK(true);
762 EXPECT_FALSE(pending_rfh
->are_navigations_suspended());
765 // DidNavigate from the pending page.
766 contents()->TestDidNavigate(
767 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
768 SiteInstance
* new_instance
= contents()->GetSiteInstance();
770 EXPECT_FALSE(contents()->cross_navigation_pending());
771 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
772 EXPECT_EQ(url2
, contents()->GetLastCommittedURL());
773 EXPECT_EQ(url2
, contents()->GetVisibleURL());
774 EXPECT_NE(new_instance
, orig_instance
);
775 EXPECT_FALSE(contents()->GetPendingMainFrame());
776 // We keep the original RFH around, swapped out.
777 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
779 EXPECT_EQ(orig_rvh_delete_count
, 0);
780 orig_rfh
->OnSwappedOut();
782 // Close contents and ensure RVHs are deleted.
784 EXPECT_EQ(orig_rvh_delete_count
, 1);
785 EXPECT_EQ(pending_rvh_delete_count
, 1);
788 // Regression test for http://crbug.com/386542 - variation of
789 // NavigateFromSitelessUrl in which the original navigation is a session
791 TEST_F(WebContentsImplTest
, NavigateFromRestoredSitelessUrl
) {
792 WebContentsImplTestBrowserClient browser_client
;
793 SetBrowserClientForTesting(&browser_client
);
794 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
795 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
797 // Restore a navigation entry for URL that should not assign site to the
799 browser_client
.set_assign_site_for_url(false);
800 const GURL
native_url("non-site-url://stuffandthings");
801 std::vector
<NavigationEntry
*> entries
;
802 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
803 native_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false, std::string(),
806 entries
.push_back(entry
);
807 controller().Restore(
809 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
811 ASSERT_EQ(0u, entries
.size());
812 ASSERT_EQ(1, controller().GetEntryCount());
813 controller().GoToIndex(0);
814 contents()->TestDidNavigate(
815 orig_rfh
, 0, native_url
, ui::PAGE_TRANSITION_RELOAD
);
816 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
817 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
818 EXPECT_FALSE(orig_instance
->HasSite());
820 // Navigate to a regular site and verify that the SiteInstance was kept.
821 browser_client
.set_assign_site_for_url(true);
822 const GURL
url("http://www.google.com");
823 controller().LoadURL(
824 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
825 contents()->TestDidNavigate(orig_rfh
, 2, url
, ui::PAGE_TRANSITION_TYPED
);
826 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
832 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
833 // tab is restored, the SiteInstance will change upon navigation.
834 TEST_F(WebContentsImplTest
, NavigateFromRestoredRegularUrl
) {
835 WebContentsImplTestBrowserClient browser_client
;
836 SetBrowserClientForTesting(&browser_client
);
837 SiteInstanceImpl
* orig_instance
= contents()->GetSiteInstance();
838 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
840 // Restore a navigation entry for a regular URL ensuring that the embedder
841 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
842 browser_client
.set_assign_site_for_url(true);
843 const GURL
regular_url("http://www.yahoo.com");
844 std::vector
<NavigationEntry
*> entries
;
845 NavigationEntry
* entry
= NavigationControllerImpl::CreateNavigationEntry(
846 regular_url
, Referrer(), ui::PAGE_TRANSITION_LINK
, false, std::string(),
849 entries
.push_back(entry
);
850 controller().Restore(
852 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY
,
854 ASSERT_EQ(0u, entries
.size());
855 ASSERT_EQ(1, controller().GetEntryCount());
856 controller().GoToIndex(0);
857 orig_rfh
->PrepareForCommit(regular_url
);
858 contents()->TestDidNavigate(
859 orig_rfh
, 0, regular_url
, ui::PAGE_TRANSITION_RELOAD
);
860 EXPECT_EQ(orig_instance
, contents()->GetSiteInstance());
861 EXPECT_TRUE(orig_instance
->HasSite());
863 // Navigate to another site and verify that a new SiteInstance was created.
864 const GURL
url("http://www.google.com");
865 controller().LoadURL(
866 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
867 orig_rfh
->PrepareForCommit(url
);
868 contents()->TestDidNavigate(
869 contents()->GetPendingMainFrame(), 2, url
, ui::PAGE_TRANSITION_TYPED
);
870 EXPECT_NE(orig_instance
, contents()->GetSiteInstance());
876 // Test that we can find an opener RVH even if it's pending.
877 // http://crbug.com/176252.
878 TEST_F(WebContentsImplTest
, FindOpenerRVHWhenPending
) {
879 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
881 // Navigate to a URL.
882 const GURL
url("http://www.google.com");
883 controller().LoadURL(
884 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
885 orig_rfh
->PrepareForCommit(url
);
886 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
888 // Start to navigate first tab to a new site, so that it has a pending RVH.
889 const GURL
url2("http://www.yahoo.com");
890 controller().LoadURL(
891 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
892 orig_rfh
->PrepareForCommit(url2
);
893 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
895 // While it is still pending, simulate opening a new tab with the first tab
896 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
897 // on the opener to ensure that an RVH exists.
898 int opener_routing_id
=
899 contents()->CreateOpenerRenderViews(pending_rfh
->GetSiteInstance());
901 // We should find the pending RVH and not create a new one.
902 EXPECT_EQ(pending_rfh
->GetRenderViewHost()->GetRoutingID(),
906 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
907 // to determine whether a navigation is cross-site.
908 TEST_F(WebContentsImplTest
, CrossSiteComparesAgainstCurrentPage
) {
909 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
910 SiteInstance
* instance1
= contents()->GetSiteInstance();
913 const GURL
url("http://www.google.com");
914 controller().LoadURL(
915 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
916 contents()->GetMainFrame()->PrepareForCommit(url
);
917 contents()->TestDidNavigate(
918 orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
920 // Open a related contents to a second site.
921 scoped_ptr
<TestWebContents
> contents2(
922 TestWebContents::Create(browser_context(), instance1
));
923 const GURL
url2("http://www.yahoo.com");
924 contents2
->GetController().LoadURL(url2
, Referrer(),
925 ui::PAGE_TRANSITION_TYPED
,
927 contents2
->GetMainFrame()->PrepareForCommit(url2
);
928 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
930 TestRenderFrameHost
* rfh2
= contents2
->GetMainFrame();
931 EXPECT_FALSE(contents2
->cross_navigation_pending());
932 contents2
->TestDidNavigate(rfh2
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
933 SiteInstance
* instance2
= contents2
->GetSiteInstance();
934 EXPECT_NE(instance1
, instance2
);
935 EXPECT_FALSE(contents2
->cross_navigation_pending());
937 // Simulate a link click in first contents to second site. Doesn't switch
938 // SiteInstances, because we don't intercept WebKit navigations.
939 contents()->TestDidNavigate(
940 orig_rfh
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
941 SiteInstance
* instance3
= contents()->GetSiteInstance();
942 EXPECT_EQ(instance1
, instance3
);
943 EXPECT_FALSE(contents()->cross_navigation_pending());
945 // Navigate to the new site. Doesn't switch SiteInstancees, because we
946 // compare against the current URL, not the SiteInstance's site.
947 const GURL
url3("http://mail.yahoo.com");
948 controller().LoadURL(
949 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
950 EXPECT_FALSE(contents()->cross_navigation_pending());
951 contents()->GetMainFrame()->PrepareForCommit(url3
);
952 contents()->TestDidNavigate(
953 orig_rfh
, 3, url3
, ui::PAGE_TRANSITION_TYPED
);
954 SiteInstance
* instance4
= contents()->GetSiteInstance();
955 EXPECT_EQ(instance1
, instance4
);
958 // Test that the onbeforeunload and onunload handlers run when navigating
959 // across site boundaries.
960 TEST_F(WebContentsImplTest
, CrossSiteUnloadHandlers
) {
961 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
962 SiteInstance
* instance1
= contents()->GetSiteInstance();
964 // Navigate to URL. First URL should use first RenderViewHost.
965 const GURL
url("http://www.google.com");
966 controller().LoadURL(
967 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
968 contents()->GetMainFrame()->PrepareForCommit(url
);
969 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
970 EXPECT_FALSE(contents()->cross_navigation_pending());
971 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
973 // Navigate to new site, but simulate an onbeforeunload denial.
974 const GURL
url2("http://www.yahoo.com");
975 controller().LoadURL(
976 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
977 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
978 base::TimeTicks now
= base::TimeTicks::Now();
979 orig_rfh
->OnMessageReceived(
980 FrameHostMsg_BeforeUnload_ACK(0, false, now
, now
));
981 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
982 EXPECT_FALSE(contents()->cross_navigation_pending());
983 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
985 // Navigate again, but simulate an onbeforeunload approval.
986 controller().LoadURL(
987 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
988 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
989 now
= base::TimeTicks::Now();
990 orig_rfh
->PrepareForCommit(url2
);
991 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
992 EXPECT_TRUE(contents()->cross_navigation_pending());
993 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
995 // We won't hear DidNavigate until the onunload handler has finished running.
997 // DidNavigate from the pending page.
998 contents()->TestDidNavigate(
999 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1000 SiteInstance
* instance2
= contents()->GetSiteInstance();
1001 EXPECT_FALSE(contents()->cross_navigation_pending());
1002 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1003 EXPECT_NE(instance1
, instance2
);
1004 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1007 // Test that during a slow cross-site navigation, the original renderer can
1008 // navigate to a different URL and have it displayed, canceling the slow
1010 TEST_F(WebContentsImplTest
, CrossSiteNavigationPreempted
) {
1011 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1012 SiteInstance
* instance1
= contents()->GetSiteInstance();
1014 // Navigate to URL. First URL should use first RenderFrameHost.
1015 const GURL
url("http://www.google.com");
1016 controller().LoadURL(
1017 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1018 contents()->GetMainFrame()->PrepareForCommit(url
);
1019 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1020 EXPECT_FALSE(contents()->cross_navigation_pending());
1021 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1023 // Navigate to new site, simulating an onbeforeunload approval.
1024 const GURL
url2("http://www.yahoo.com");
1025 controller().LoadURL(
1026 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1027 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1028 orig_rfh
->PrepareForCommit(url2
);
1029 EXPECT_TRUE(contents()->cross_navigation_pending());
1031 // Suppose the original renderer navigates before the new one is ready.
1032 orig_rfh
->SendNavigate(2, GURL("http://www.google.com/foo"));
1034 // Verify that the pending navigation is cancelled.
1035 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1036 SiteInstance
* instance2
= contents()->GetSiteInstance();
1037 EXPECT_FALSE(contents()->cross_navigation_pending());
1038 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1039 EXPECT_EQ(instance1
, instance2
);
1040 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1043 TEST_F(WebContentsImplTest
, CrossSiteNavigationBackPreempted
) {
1044 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1045 const GURL
url1("chrome://blah");
1046 controller().LoadURL(
1047 url1
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1048 TestRenderFrameHost
* ntp_rfh
= contents()->GetMainFrame();
1049 ntp_rfh
->PrepareForCommit(url1
);
1050 contents()->TestDidNavigate(ntp_rfh
, 1, url1
, ui::PAGE_TRANSITION_TYPED
);
1051 NavigationEntry
* entry1
= controller().GetLastCommittedEntry();
1052 SiteInstance
* instance1
= contents()->GetSiteInstance();
1054 EXPECT_FALSE(contents()->cross_navigation_pending());
1055 EXPECT_EQ(ntp_rfh
, contents()->GetMainFrame());
1056 EXPECT_EQ(url1
, entry1
->GetURL());
1057 EXPECT_EQ(instance1
,
1058 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1059 EXPECT_TRUE(ntp_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1060 BINDINGS_POLICY_WEB_UI
);
1062 // Navigate to new site.
1063 const GURL
url2("http://www.google.com");
1064 controller().LoadURL(
1065 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1066 EXPECT_TRUE(contents()->cross_navigation_pending());
1067 TestRenderFrameHost
* google_rfh
= contents()->GetPendingMainFrame();
1069 // Simulate beforeunload approval.
1070 EXPECT_TRUE(ntp_rfh
->IsWaitingForBeforeUnloadACK());
1071 base::TimeTicks now
= base::TimeTicks::Now();
1072 ntp_rfh
->PrepareForCommit(url2
);
1074 // DidNavigate from the pending page.
1075 contents()->TestDidNavigate(
1076 google_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1077 NavigationEntry
* entry2
= controller().GetLastCommittedEntry();
1078 SiteInstance
* instance2
= contents()->GetSiteInstance();
1080 EXPECT_FALSE(contents()->cross_navigation_pending());
1081 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1082 EXPECT_NE(instance1
, instance2
);
1083 EXPECT_FALSE(contents()->GetPendingMainFrame());
1084 EXPECT_EQ(url2
, entry2
->GetURL());
1085 EXPECT_EQ(instance2
,
1086 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1087 EXPECT_FALSE(google_rfh
->GetRenderViewHost()->GetEnabledBindings() &
1088 BINDINGS_POLICY_WEB_UI
);
1090 // Navigate to third page on same site.
1091 const GURL
url3("http://news.google.com");
1092 controller().LoadURL(
1093 url3
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1094 EXPECT_FALSE(contents()->cross_navigation_pending());
1095 contents()->GetMainFrame()->PrepareForCommit(url3
);
1096 contents()->TestDidNavigate(
1097 google_rfh
, 2, url3
, ui::PAGE_TRANSITION_TYPED
);
1098 NavigationEntry
* entry3
= controller().GetLastCommittedEntry();
1099 SiteInstance
* instance3
= contents()->GetSiteInstance();
1101 EXPECT_FALSE(contents()->cross_navigation_pending());
1102 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1103 EXPECT_EQ(instance2
, instance3
);
1104 EXPECT_FALSE(contents()->GetPendingMainFrame());
1105 EXPECT_EQ(url3
, entry3
->GetURL());
1106 EXPECT_EQ(instance3
,
1107 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1109 // Go back within the site.
1110 controller().GoBack();
1111 EXPECT_FALSE(contents()->cross_navigation_pending());
1112 EXPECT_EQ(entry2
, controller().GetPendingEntry());
1114 // Before that commits, go back again.
1115 controller().GoBack();
1116 EXPECT_TRUE(contents()->cross_navigation_pending());
1117 EXPECT_TRUE(contents()->GetPendingMainFrame());
1118 EXPECT_EQ(entry1
, controller().GetPendingEntry());
1120 // Simulate beforeunload approval.
1121 EXPECT_TRUE(google_rfh
->IsWaitingForBeforeUnloadACK());
1122 now
= base::TimeTicks::Now();
1123 google_rfh
->PrepareForCommit(url2
);
1124 google_rfh
->OnMessageReceived(
1125 FrameHostMsg_BeforeUnload_ACK(0, true, now
, now
));
1127 // DidNavigate from the first back. This aborts the second back's pending RFH.
1128 contents()->TestDidNavigate(google_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1130 // We should commit this page and forget about the second back.
1131 EXPECT_FALSE(contents()->cross_navigation_pending());
1132 EXPECT_FALSE(controller().GetPendingEntry());
1133 EXPECT_EQ(google_rfh
, contents()->GetMainFrame());
1134 EXPECT_EQ(url2
, controller().GetLastCommittedEntry()->GetURL());
1136 // We should not have corrupted the NTP entry.
1137 EXPECT_EQ(instance3
,
1138 NavigationEntryImpl::FromNavigationEntry(entry3
)->site_instance());
1139 EXPECT_EQ(instance2
,
1140 NavigationEntryImpl::FromNavigationEntry(entry2
)->site_instance());
1141 EXPECT_EQ(instance1
,
1142 NavigationEntryImpl::FromNavigationEntry(entry1
)->site_instance());
1143 EXPECT_EQ(url1
, entry1
->GetURL());
1146 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1147 // original renderer will not cancel the slow navigation (bug 42029).
1148 TEST_F(WebContentsImplTest
, CrossSiteNavigationNotPreemptedByFrame
) {
1149 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1151 // Navigate to URL. First URL should use the original RenderFrameHost.
1152 const GURL
url("http://www.google.com");
1153 controller().LoadURL(
1154 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1155 contents()->GetMainFrame()->PrepareForCommit(url
);
1156 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1157 EXPECT_FALSE(contents()->cross_navigation_pending());
1158 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1160 // Start navigating to new site.
1161 const GURL
url2("http://www.yahoo.com");
1162 controller().LoadURL(
1163 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1165 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1166 // waiting for a before unload response.
1167 TestRenderFrameHost
* child_rfh
= orig_rfh
->AppendChild("subframe");
1168 child_rfh
->SendNavigateWithTransition(
1169 1, GURL("http://google.com/frame"), ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
1170 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1172 // Now simulate the onbeforeunload approval and verify the navigation is
1174 orig_rfh
->PrepareForCommit(url2
);
1175 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1176 EXPECT_TRUE(contents()->cross_navigation_pending());
1179 // Test that a cross-site navigation is not preempted if the previous
1180 // renderer sends a FrameNavigate message just before being told to stop.
1181 // We should only preempt the cross-site navigation if the previous renderer
1182 // has started a new navigation. See http://crbug.com/79176.
1183 TEST_F(WebContentsImplTest
, CrossSiteNotPreemptedDuringBeforeUnload
) {
1184 // Navigate to NTP URL.
1185 const GURL
url("chrome://blah");
1186 controller().LoadURL(
1187 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1188 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1189 EXPECT_FALSE(contents()->cross_navigation_pending());
1191 // Navigate to new site, with the beforeunload request in flight.
1192 const GURL
url2("http://www.yahoo.com");
1193 controller().LoadURL(
1194 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1195 TestRenderFrameHost
* pending_rfh
= contents()->GetPendingMainFrame();
1196 EXPECT_TRUE(contents()->cross_navigation_pending());
1197 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1199 // Suppose the first navigation tries to commit now, with a
1200 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1201 // but it should act as if the beforeunload ack arrived.
1202 orig_rfh
->SendNavigate(1, GURL("chrome://blah"));
1203 EXPECT_TRUE(contents()->cross_navigation_pending());
1204 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1205 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1207 // The pending navigation should be able to commit successfully.
1208 contents()->TestDidNavigate(pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1209 EXPECT_FALSE(contents()->cross_navigation_pending());
1210 EXPECT_EQ(pending_rfh
, contents()->GetMainFrame());
1213 // Test that a cross-site navigation that doesn't commit after the unload
1214 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1215 TEST_F(WebContentsImplTest
, CrossSiteNavigationCanceled
) {
1216 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1217 SiteInstance
* instance1
= contents()->GetSiteInstance();
1219 // Navigate to URL. First URL should use original RenderFrameHost.
1220 const GURL
url("http://www.google.com");
1221 controller().LoadURL(
1222 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1223 contents()->GetMainFrame()->PrepareForCommit(url
);
1224 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1225 EXPECT_FALSE(contents()->cross_navigation_pending());
1226 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1228 // Navigate to new site, simulating an onbeforeunload approval.
1229 const GURL
url2("http://www.yahoo.com");
1230 controller().LoadURL(
1231 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1232 EXPECT_TRUE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1233 contents()->GetMainFrame()->PrepareForCommit(url2
);
1234 EXPECT_TRUE(contents()->cross_navigation_pending());
1236 // Simulate swap out message when the response arrives.
1237 orig_rfh
->OnSwappedOut();
1239 // Suppose the navigation doesn't get a chance to commit, and the user
1240 // navigates in the current RFH's SiteInstance.
1241 controller().LoadURL(
1242 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1244 // Verify that the pending navigation is cancelled and the renderer is no
1245 // longer swapped out.
1246 EXPECT_FALSE(orig_rfh
->IsWaitingForBeforeUnloadACK());
1247 SiteInstance
* instance2
= contents()->GetSiteInstance();
1248 EXPECT_FALSE(contents()->cross_navigation_pending());
1249 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1250 EXPECT_EQ(RenderFrameHostImpl::STATE_DEFAULT
, orig_rfh
->rfh_state());
1251 EXPECT_EQ(instance1
, instance2
);
1252 EXPECT_TRUE(contents()->GetPendingMainFrame() == NULL
);
1255 // Test that NavigationEntries have the correct page state after going
1256 // forward and back. Prevents regression for bug 1116137.
1257 TEST_F(WebContentsImplTest
, NavigationEntryContentState
) {
1258 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1260 // Navigate to URL. There should be no committed entry yet.
1261 const GURL
url("http://www.google.com");
1262 controller().LoadURL(
1263 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1264 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1265 EXPECT_TRUE(entry
== NULL
);
1267 // Committed entry should have page state after DidNavigate.
1268 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1269 entry
= controller().GetLastCommittedEntry();
1270 EXPECT_TRUE(entry
->GetPageState().IsValid());
1272 // Navigate to same site.
1273 const GURL
url2("http://images.google.com");
1274 controller().LoadURL(
1275 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1276 entry
= controller().GetLastCommittedEntry();
1277 EXPECT_TRUE(entry
->GetPageState().IsValid());
1279 // Committed entry should have page state after DidNavigate.
1280 contents()->TestDidNavigate(orig_rfh
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
1281 entry
= controller().GetLastCommittedEntry();
1282 EXPECT_TRUE(entry
->GetPageState().IsValid());
1284 // Now go back. Committed entry should still have page state.
1285 controller().GoBack();
1286 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1287 entry
= controller().GetLastCommittedEntry();
1288 EXPECT_TRUE(entry
->GetPageState().IsValid());
1291 // Test that NavigationEntries have the correct page state and SiteInstance
1292 // state after opening a new window to about:blank. Prevents regression for
1293 // bugs b/1116137 and http://crbug.com/111975.
1294 TEST_F(WebContentsImplTest
, NavigationEntryContentStateNewWindow
) {
1295 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1297 // When opening a new window, it is navigated to about:blank internally.
1298 // Currently, this results in two DidNavigate events.
1299 const GURL
url(url::kAboutBlankURL
);
1300 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1301 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1303 // Should have a page state here.
1304 NavigationEntry
* entry
= controller().GetLastCommittedEntry();
1305 EXPECT_TRUE(entry
->GetPageState().IsValid());
1307 // The SiteInstance should be available for other navigations to use.
1308 NavigationEntryImpl
* entry_impl
=
1309 NavigationEntryImpl::FromNavigationEntry(entry
);
1310 EXPECT_FALSE(entry_impl
->site_instance()->HasSite());
1311 int32 site_instance_id
= entry_impl
->site_instance()->GetId();
1313 // Navigating to a normal page should not cause a process swap.
1314 const GURL
new_url("http://www.google.com");
1315 controller().LoadURL(new_url
, Referrer(),
1316 ui::PAGE_TRANSITION_TYPED
, std::string());
1317 EXPECT_FALSE(contents()->cross_navigation_pending());
1318 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1319 contents()->TestDidNavigate(orig_rfh
, 1, new_url
, ui::PAGE_TRANSITION_TYPED
);
1320 NavigationEntryImpl
* entry_impl2
= NavigationEntryImpl::FromNavigationEntry(
1321 controller().GetLastCommittedEntry());
1322 EXPECT_EQ(site_instance_id
, entry_impl2
->site_instance()->GetId());
1323 EXPECT_TRUE(entry_impl2
->site_instance()->HasSite());
1326 // Tests that fullscreen is exited throughout the object hierarchy when
1327 // navigating to a new page.
1328 TEST_F(WebContentsImplTest
, NavigationExitsFullscreen
) {
1329 FakeFullscreenDelegate fake_delegate
;
1330 contents()->SetDelegate(&fake_delegate
);
1331 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
1332 TestRenderViewHost
* orig_rvh
= orig_rfh
->GetRenderViewHost();
1334 // Navigate to a site.
1335 const GURL
url("http://www.google.com");
1336 controller().LoadURL(
1337 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1338 contents()->GetMainFrame()->PrepareForCommit(url
);
1339 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1340 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1342 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1343 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1344 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1345 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1346 orig_rfh
->OnMessageReceived(
1347 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1348 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1349 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1350 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1352 // Navigate to a new site.
1353 const GURL
url2("http://www.yahoo.com");
1354 controller().LoadURL(
1355 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1356 contents()->GetMainFrame()->PrepareForCommit(url2
);
1357 TestRenderFrameHost
* const pending_rfh
= contents()->GetPendingMainFrame();
1358 contents()->TestDidNavigate(
1359 pending_rfh
, 1, url2
, ui::PAGE_TRANSITION_TYPED
);
1361 // Confirm fullscreen has exited.
1362 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1363 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1364 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1366 contents()->SetDelegate(NULL
);
1369 // Tests that fullscreen is exited throughout the object hierarchy when
1370 // instructing NavigationController to GoBack() or GoForward().
1371 TEST_F(WebContentsImplTest
, HistoryNavigationExitsFullscreen
) {
1372 FakeFullscreenDelegate fake_delegate
;
1373 contents()->SetDelegate(&fake_delegate
);
1374 TestRenderFrameHost
* const orig_rfh
= contents()->GetMainFrame();
1375 TestRenderViewHost
* const orig_rvh
= orig_rfh
->GetRenderViewHost();
1377 // Navigate to a site.
1378 const GURL
url("http://www.google.com");
1379 controller().LoadURL(
1380 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1381 contents()->TestDidNavigate(orig_rfh
, 1, url
, ui::PAGE_TRANSITION_TYPED
);
1382 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1384 // Now, navigate to another page on the same site.
1385 const GURL
url2("http://www.google.com/search?q=kittens");
1386 controller().LoadURL(
1387 url2
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1388 EXPECT_FALSE(contents()->cross_navigation_pending());
1389 contents()->TestDidNavigate(orig_rfh
, 2, url2
, ui::PAGE_TRANSITION_TYPED
);
1390 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1392 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1393 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1394 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1395 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1397 for (int i
= 0; i
< 2; ++i
) {
1398 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1399 orig_rfh
->OnMessageReceived(
1400 FrameHostMsg_ToggleFullscreen(orig_rfh
->GetRoutingID(), true));
1401 EXPECT_TRUE(orig_rvh
->IsFullscreen());
1402 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1403 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1405 // Navigate backward (or forward).
1407 controller().GoBack();
1409 controller().GoForward();
1410 EXPECT_FALSE(contents()->cross_navigation_pending());
1411 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
1412 contents()->TestDidNavigate(
1413 orig_rfh
, i
+ 1, url
, ui::PAGE_TRANSITION_FORWARD_BACK
);
1415 // Confirm fullscreen has exited.
1416 EXPECT_FALSE(orig_rvh
->IsFullscreen());
1417 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1418 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1421 contents()->SetDelegate(NULL
);
1424 TEST_F(WebContentsImplTest
, TerminateHidesValidationMessage
) {
1425 FakeValidationMessageDelegate fake_delegate
;
1426 contents()->SetDelegate(&fake_delegate
);
1427 EXPECT_FALSE(fake_delegate
.hide_validation_message_was_called());
1429 // Crash the renderer.
1430 contents()->GetMainFrame()->OnMessageReceived(
1431 FrameHostMsg_RenderProcessGone(
1432 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1434 // Confirm HideValidationMessage was called.
1435 EXPECT_TRUE(fake_delegate
.hide_validation_message_was_called());
1437 contents()->SetDelegate(NULL
);
1440 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1442 TEST_F(WebContentsImplTest
, CrashExitsFullscreen
) {
1443 FakeFullscreenDelegate fake_delegate
;
1444 contents()->SetDelegate(&fake_delegate
);
1446 // Navigate to a site.
1447 const GURL
url("http://www.google.com");
1448 controller().LoadURL(
1449 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
1450 contents()->TestDidNavigate(
1451 contents()->GetMainFrame(), 1, url
, ui::PAGE_TRANSITION_TYPED
);
1453 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1454 EXPECT_FALSE(test_rvh()->IsFullscreen());
1455 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1456 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1457 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1458 contents()->GetMainFrame()->GetRoutingID(), true));
1459 EXPECT_TRUE(test_rvh()->IsFullscreen());
1460 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1461 EXPECT_TRUE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1463 // Crash the renderer.
1464 main_rfh()->OnMessageReceived(
1465 FrameHostMsg_RenderProcessGone(
1466 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1468 // Confirm fullscreen has exited.
1469 EXPECT_FALSE(test_rvh()->IsFullscreen());
1470 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1471 EXPECT_FALSE(fake_delegate
.IsFullscreenForTabOrPending(contents()));
1473 contents()->SetDelegate(NULL
);
1476 ////////////////////////////////////////////////////////////////////////////////
1477 // Interstitial Tests
1478 ////////////////////////////////////////////////////////////////////////////////
1480 // Test navigating to a page (with the navigation initiated from the browser,
1481 // as when a URL is typed in the location bar) that shows an interstitial and
1482 // creates a new navigation entry, then hiding it without proceeding.
1483 TEST_F(WebContentsImplTest
,
1484 ShowInterstitialFromBrowserWithNewNavigationDontProceed
) {
1485 // Navigate to a page.
1486 GURL
url1("http://www.google.com");
1487 contents()->GetMainFrame()->SendNavigate(1, url1
);
1488 EXPECT_EQ(1, controller().GetEntryCount());
1490 // Initiate a browser navigation that will trigger the interstitial
1491 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1492 ui::PAGE_TRANSITION_TYPED
, std::string());
1494 // Show an interstitial.
1495 TestInterstitialPage::InterstitialState state
=
1496 TestInterstitialPage::INVALID
;
1497 bool deleted
= false;
1498 GURL
url2("http://interstitial");
1499 TestInterstitialPage
* interstitial
=
1500 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1501 TestInterstitialPageStateGuard
state_guard(interstitial
);
1502 interstitial
->Show();
1503 // The interstitial should not show until its navigation has committed.
1504 EXPECT_FALSE(interstitial
->is_showing());
1505 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1506 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1507 // Let's commit the interstitial navigation.
1508 interstitial
->TestDidNavigate(1, url2
);
1509 EXPECT_TRUE(interstitial
->is_showing());
1510 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1511 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1512 NavigationEntry
* entry
= controller().GetVisibleEntry();
1513 ASSERT_TRUE(entry
!= NULL
);
1514 EXPECT_TRUE(entry
->GetURL() == url2
);
1516 // Now don't proceed.
1517 interstitial
->DontProceed();
1518 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1519 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1520 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1521 entry
= controller().GetVisibleEntry();
1522 ASSERT_TRUE(entry
!= NULL
);
1523 EXPECT_TRUE(entry
->GetURL() == url1
);
1524 EXPECT_EQ(1, controller().GetEntryCount());
1526 RunAllPendingInMessageLoop();
1527 EXPECT_TRUE(deleted
);
1530 // Test navigating to a page (with the navigation initiated from the renderer,
1531 // as when clicking on a link in the page) that shows an interstitial and
1532 // creates a new navigation entry, then hiding it without proceeding.
1533 TEST_F(WebContentsImplTest
,
1534 ShowInterstitiaFromRendererlWithNewNavigationDontProceed
) {
1535 // Navigate to a page.
1536 GURL
url1("http://www.google.com");
1537 contents()->GetMainFrame()->SendNavigate(1, url1
);
1538 EXPECT_EQ(1, controller().GetEntryCount());
1540 // Show an interstitial (no pending entry, the interstitial would have been
1541 // triggered by clicking on a link).
1542 TestInterstitialPage::InterstitialState state
=
1543 TestInterstitialPage::INVALID
;
1544 bool deleted
= false;
1545 GURL
url2("http://interstitial");
1546 TestInterstitialPage
* interstitial
=
1547 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1548 TestInterstitialPageStateGuard
state_guard(interstitial
);
1549 interstitial
->Show();
1550 // The interstitial should not show until its navigation has committed.
1551 EXPECT_FALSE(interstitial
->is_showing());
1552 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1553 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1554 // Let's commit the interstitial navigation.
1555 interstitial
->TestDidNavigate(1, url2
);
1556 EXPECT_TRUE(interstitial
->is_showing());
1557 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1558 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1559 NavigationEntry
* entry
= controller().GetVisibleEntry();
1560 ASSERT_TRUE(entry
!= NULL
);
1561 EXPECT_TRUE(entry
->GetURL() == url2
);
1563 // Now don't proceed.
1564 interstitial
->DontProceed();
1565 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1566 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1567 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1568 entry
= controller().GetVisibleEntry();
1569 ASSERT_TRUE(entry
!= NULL
);
1570 EXPECT_TRUE(entry
->GetURL() == url1
);
1571 EXPECT_EQ(1, controller().GetEntryCount());
1573 RunAllPendingInMessageLoop();
1574 EXPECT_TRUE(deleted
);
1577 // Test navigating to a page that shows an interstitial without creating a new
1578 // navigation entry (this happens when the interstitial is triggered by a
1579 // sub-resource in the page), then hiding it without proceeding.
1580 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationDontProceed
) {
1581 // Navigate to a page.
1582 GURL
url1("http://www.google.com");
1583 contents()->GetMainFrame()->SendNavigate(1, url1
);
1584 EXPECT_EQ(1, controller().GetEntryCount());
1586 // Show an interstitial.
1587 TestInterstitialPage::InterstitialState state
=
1588 TestInterstitialPage::INVALID
;
1589 bool deleted
= false;
1590 GURL
url2("http://interstitial");
1591 TestInterstitialPage
* interstitial
=
1592 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1593 TestInterstitialPageStateGuard
state_guard(interstitial
);
1594 interstitial
->Show();
1595 // The interstitial should not show until its navigation has committed.
1596 EXPECT_FALSE(interstitial
->is_showing());
1597 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1598 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1599 // Let's commit the interstitial navigation.
1600 interstitial
->TestDidNavigate(1, url2
);
1601 EXPECT_TRUE(interstitial
->is_showing());
1602 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1603 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1604 NavigationEntry
* entry
= controller().GetVisibleEntry();
1605 ASSERT_TRUE(entry
!= NULL
);
1606 // The URL specified to the interstitial should have been ignored.
1607 EXPECT_TRUE(entry
->GetURL() == url1
);
1609 // Now don't proceed.
1610 interstitial
->DontProceed();
1611 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1612 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1613 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1614 entry
= controller().GetVisibleEntry();
1615 ASSERT_TRUE(entry
!= NULL
);
1616 EXPECT_TRUE(entry
->GetURL() == url1
);
1617 EXPECT_EQ(1, controller().GetEntryCount());
1619 RunAllPendingInMessageLoop();
1620 EXPECT_TRUE(deleted
);
1623 // Test navigating to a page (with the navigation initiated from the browser,
1624 // as when a URL is typed in the location bar) that shows an interstitial and
1625 // creates a new navigation entry, then proceeding.
1626 TEST_F(WebContentsImplTest
,
1627 ShowInterstitialFromBrowserNewNavigationProceed
) {
1628 // Navigate to a page.
1629 GURL
url1("http://www.google.com");
1630 contents()->GetMainFrame()->SendNavigate(1, url1
);
1631 EXPECT_EQ(1, controller().GetEntryCount());
1633 // Initiate a browser navigation that will trigger the interstitial
1634 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1635 ui::PAGE_TRANSITION_TYPED
, std::string());
1637 // Show an interstitial.
1638 TestInterstitialPage::InterstitialState state
=
1639 TestInterstitialPage::INVALID
;
1640 bool deleted
= false;
1641 GURL
url2("http://interstitial");
1642 TestInterstitialPage
* interstitial
=
1643 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1644 TestInterstitialPageStateGuard
state_guard(interstitial
);
1645 interstitial
->Show();
1646 // The interstitial should not show until its navigation has committed.
1647 EXPECT_FALSE(interstitial
->is_showing());
1648 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1649 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1650 // Let's commit the interstitial navigation.
1651 interstitial
->TestDidNavigate(1, url2
);
1652 EXPECT_TRUE(interstitial
->is_showing());
1653 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1654 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1655 NavigationEntry
* entry
= controller().GetVisibleEntry();
1656 ASSERT_TRUE(entry
!= NULL
);
1657 EXPECT_TRUE(entry
->GetURL() == url2
);
1660 interstitial
->Proceed();
1661 // The interstitial should show until the new navigation commits.
1662 RunAllPendingInMessageLoop();
1663 ASSERT_FALSE(deleted
);
1664 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1665 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1666 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1668 // Simulate the navigation to the page, that's when the interstitial gets
1670 GURL
url3("http://www.thepage.com");
1671 contents()->GetMainFrame()->SendNavigate(2, url3
);
1673 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1674 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1675 entry
= controller().GetVisibleEntry();
1676 ASSERT_TRUE(entry
!= NULL
);
1677 EXPECT_TRUE(entry
->GetURL() == url3
);
1679 EXPECT_EQ(2, controller().GetEntryCount());
1681 RunAllPendingInMessageLoop();
1682 EXPECT_TRUE(deleted
);
1685 // Test navigating to a page (with the navigation initiated from the renderer,
1686 // as when clicking on a link in the page) that shows an interstitial and
1687 // creates a new navigation entry, then proceeding.
1688 TEST_F(WebContentsImplTest
,
1689 ShowInterstitialFromRendererNewNavigationProceed
) {
1690 // Navigate to a page.
1691 GURL
url1("http://www.google.com");
1692 contents()->GetMainFrame()->SendNavigate(1, url1
);
1693 EXPECT_EQ(1, controller().GetEntryCount());
1695 // Show an interstitial.
1696 TestInterstitialPage::InterstitialState state
=
1697 TestInterstitialPage::INVALID
;
1698 bool deleted
= false;
1699 GURL
url2("http://interstitial");
1700 TestInterstitialPage
* interstitial
=
1701 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1702 TestInterstitialPageStateGuard
state_guard(interstitial
);
1703 interstitial
->Show();
1704 // The interstitial should not show until its navigation has committed.
1705 EXPECT_FALSE(interstitial
->is_showing());
1706 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1707 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1708 // Let's commit the interstitial navigation.
1709 interstitial
->TestDidNavigate(1, url2
);
1710 EXPECT_TRUE(interstitial
->is_showing());
1711 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1712 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1713 NavigationEntry
* entry
= controller().GetVisibleEntry();
1714 ASSERT_TRUE(entry
!= NULL
);
1715 EXPECT_TRUE(entry
->GetURL() == url2
);
1718 interstitial
->Proceed();
1719 // The interstitial should show until the new navigation commits.
1720 RunAllPendingInMessageLoop();
1721 ASSERT_FALSE(deleted
);
1722 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1723 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1724 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1726 // Simulate the navigation to the page, that's when the interstitial gets
1728 GURL
url3("http://www.thepage.com");
1729 contents()->GetMainFrame()->SendNavigate(2, url3
);
1731 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1732 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1733 entry
= controller().GetVisibleEntry();
1734 ASSERT_TRUE(entry
!= NULL
);
1735 EXPECT_TRUE(entry
->GetURL() == url3
);
1737 EXPECT_EQ(2, controller().GetEntryCount());
1739 RunAllPendingInMessageLoop();
1740 EXPECT_TRUE(deleted
);
1743 // Test navigating to a page that shows an interstitial without creating a new
1744 // navigation entry (this happens when the interstitial is triggered by a
1745 // sub-resource in the page), then proceeding.
1746 TEST_F(WebContentsImplTest
, ShowInterstitialNoNewNavigationProceed
) {
1747 // Navigate to a page so we have a navigation entry in the controller.
1748 GURL
url1("http://www.google.com");
1749 contents()->GetMainFrame()->SendNavigate(1, url1
);
1750 EXPECT_EQ(1, controller().GetEntryCount());
1752 // Show an interstitial.
1753 TestInterstitialPage::InterstitialState state
=
1754 TestInterstitialPage::INVALID
;
1755 bool deleted
= false;
1756 GURL
url2("http://interstitial");
1757 TestInterstitialPage
* interstitial
=
1758 new TestInterstitialPage(contents(), false, url2
, &state
, &deleted
);
1759 TestInterstitialPageStateGuard
state_guard(interstitial
);
1760 interstitial
->Show();
1761 // The interstitial should not show until its navigation has committed.
1762 EXPECT_FALSE(interstitial
->is_showing());
1763 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1764 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1765 // Let's commit the interstitial navigation.
1766 interstitial
->TestDidNavigate(1, url2
);
1767 EXPECT_TRUE(interstitial
->is_showing());
1768 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1769 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial
);
1770 NavigationEntry
* entry
= controller().GetVisibleEntry();
1771 ASSERT_TRUE(entry
!= NULL
);
1772 // The URL specified to the interstitial should have been ignored.
1773 EXPECT_TRUE(entry
->GetURL() == url1
);
1776 interstitial
->Proceed();
1777 // Since this is not a new navigation, the previous page is dismissed right
1778 // away and shows the original page.
1779 EXPECT_EQ(TestInterstitialPage::OKED
, state
);
1780 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1781 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
1782 entry
= controller().GetVisibleEntry();
1783 ASSERT_TRUE(entry
!= NULL
);
1784 EXPECT_TRUE(entry
->GetURL() == url1
);
1786 EXPECT_EQ(1, controller().GetEntryCount());
1788 RunAllPendingInMessageLoop();
1789 EXPECT_TRUE(deleted
);
1792 // Test navigating to a page that shows an interstitial, then navigating away.
1793 TEST_F(WebContentsImplTest
, ShowInterstitialThenNavigate
) {
1794 // Show interstitial.
1795 TestInterstitialPage::InterstitialState state
=
1796 TestInterstitialPage::INVALID
;
1797 bool deleted
= false;
1798 GURL
url("http://interstitial");
1799 TestInterstitialPage
* interstitial
=
1800 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1801 TestInterstitialPageStateGuard
state_guard(interstitial
);
1802 interstitial
->Show();
1803 interstitial
->TestDidNavigate(1, url
);
1805 // While interstitial showing, navigate to a new URL.
1806 const GURL
url2("http://www.yahoo.com");
1807 contents()->GetMainFrame()->SendNavigate(1, url2
);
1809 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1811 RunAllPendingInMessageLoop();
1812 EXPECT_TRUE(deleted
);
1815 // Test navigating to a page that shows an interstitial, then going back.
1816 TEST_F(WebContentsImplTest
, ShowInterstitialThenGoBack
) {
1817 // Navigate to a page so we have a navigation entry in the controller.
1818 GURL
url1("http://www.google.com");
1819 contents()->GetMainFrame()->SendNavigate(1, url1
);
1820 EXPECT_EQ(1, controller().GetEntryCount());
1822 // Show interstitial.
1823 TestInterstitialPage::InterstitialState state
=
1824 TestInterstitialPage::INVALID
;
1825 bool deleted
= false;
1826 GURL
interstitial_url("http://interstitial");
1827 TestInterstitialPage
* interstitial
=
1828 new TestInterstitialPage(contents(), true, interstitial_url
,
1830 TestInterstitialPageStateGuard
state_guard(interstitial
);
1831 interstitial
->Show();
1832 interstitial
->TestDidNavigate(2, interstitial_url
);
1834 // While the interstitial is showing, go back.
1835 controller().GoBack();
1836 contents()->GetMainFrame()->SendNavigate(1, url1
);
1838 // Make sure we are back to the original page and that the interstitial is
1840 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1841 NavigationEntry
* entry
= controller().GetVisibleEntry();
1843 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1845 RunAllPendingInMessageLoop();
1846 EXPECT_TRUE(deleted
);
1849 // Test navigating to a page that shows an interstitial, has a renderer crash,
1850 // and then goes back.
1851 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenGoBack
) {
1852 // Navigate to a page so we have a navigation entry in the controller.
1853 GURL
url1("http://www.google.com");
1854 contents()->GetMainFrame()->SendNavigate(1, url1
);
1855 EXPECT_EQ(1, controller().GetEntryCount());
1857 // Show interstitial.
1858 TestInterstitialPage::InterstitialState state
=
1859 TestInterstitialPage::INVALID
;
1860 bool deleted
= false;
1861 GURL
interstitial_url("http://interstitial");
1862 TestInterstitialPage
* interstitial
=
1863 new TestInterstitialPage(contents(), true, interstitial_url
,
1865 TestInterstitialPageStateGuard
state_guard(interstitial
);
1866 interstitial
->Show();
1867 interstitial
->TestDidNavigate(2, interstitial_url
);
1869 // Crash the renderer
1870 main_rfh()->OnMessageReceived(
1871 FrameHostMsg_RenderProcessGone(
1872 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1874 // While the interstitial is showing, go back.
1875 controller().GoBack();
1876 contents()->GetMainFrame()->SendNavigate(1, url1
);
1878 // Make sure we are back to the original page and that the interstitial is
1880 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1881 NavigationEntry
* entry
= controller().GetVisibleEntry();
1883 EXPECT_EQ(url1
.spec(), entry
->GetURL().spec());
1885 RunAllPendingInMessageLoop();
1886 EXPECT_TRUE(deleted
);
1889 // Test navigating to a page that shows an interstitial, has the renderer crash,
1890 // and then navigates to the interstitial.
1891 TEST_F(WebContentsImplTest
, ShowInterstitialCrashRendererThenNavigate
) {
1892 // Navigate to a page so we have a navigation entry in the controller.
1893 GURL
url1("http://www.google.com");
1894 contents()->GetMainFrame()->SendNavigate(1, url1
);
1895 EXPECT_EQ(1, controller().GetEntryCount());
1897 // Show interstitial.
1898 TestInterstitialPage::InterstitialState state
=
1899 TestInterstitialPage::INVALID
;
1900 bool deleted
= false;
1901 GURL
interstitial_url("http://interstitial");
1902 TestInterstitialPage
* interstitial
=
1903 new TestInterstitialPage(contents(), true, interstitial_url
,
1905 TestInterstitialPageStateGuard
state_guard(interstitial
);
1906 interstitial
->Show();
1908 // Crash the renderer
1909 main_rfh()->OnMessageReceived(
1910 FrameHostMsg_RenderProcessGone(
1911 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
1913 interstitial
->TestDidNavigate(2, interstitial_url
);
1916 // Test navigating to a page that shows an interstitial, then close the
1918 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseTab
) {
1919 // Show interstitial.
1920 TestInterstitialPage::InterstitialState state
=
1921 TestInterstitialPage::INVALID
;
1922 bool deleted
= false;
1923 GURL
url("http://interstitial");
1924 TestInterstitialPage
* interstitial
=
1925 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1926 TestInterstitialPageStateGuard
state_guard(interstitial
);
1927 interstitial
->Show();
1928 interstitial
->TestDidNavigate(1, url
);
1930 // Now close the contents.
1932 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1934 RunAllPendingInMessageLoop();
1935 EXPECT_TRUE(deleted
);
1938 // Test navigating to a page that shows an interstitial, then close the
1940 TEST_F(WebContentsImplTest
, ShowInterstitialThenCloseAndShutdown
) {
1941 // Show interstitial.
1942 TestInterstitialPage::InterstitialState state
=
1943 TestInterstitialPage::INVALID
;
1944 bool deleted
= false;
1945 GURL
url("http://interstitial");
1946 TestInterstitialPage
* interstitial
=
1947 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
1948 TestInterstitialPageStateGuard
state_guard(interstitial
);
1949 interstitial
->Show();
1950 interstitial
->TestDidNavigate(1, url
);
1951 RenderViewHostImpl
* rvh
= static_cast<RenderViewHostImpl
*>(
1952 interstitial
->GetMainFrame()->GetRenderViewHost());
1954 // Now close the contents.
1956 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
1958 // Before the interstitial has a chance to process its shutdown task,
1959 // simulate quitting the browser. This goes through all processes and
1960 // tells them to destruct.
1961 rvh
->GetMainFrame()->OnMessageReceived(
1962 FrameHostMsg_RenderProcessGone(0, 0, 0));
1964 RunAllPendingInMessageLoop();
1965 EXPECT_TRUE(deleted
);
1968 // Test that after Proceed is called and an interstitial is still shown, no more
1969 // commands get executed.
1970 TEST_F(WebContentsImplTest
, ShowInterstitialProceedMultipleCommands
) {
1971 // Navigate to a page so we have a navigation entry in the controller.
1972 GURL
url1("http://www.google.com");
1973 contents()->GetMainFrame()->SendNavigate(1, url1
);
1974 EXPECT_EQ(1, controller().GetEntryCount());
1976 // Show an interstitial.
1977 TestInterstitialPage::InterstitialState state
=
1978 TestInterstitialPage::INVALID
;
1979 bool deleted
= false;
1980 GURL
url2("http://interstitial");
1981 TestInterstitialPage
* interstitial
=
1982 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
1983 TestInterstitialPageStateGuard
state_guard(interstitial
);
1984 interstitial
->Show();
1985 interstitial
->TestDidNavigate(1, url2
);
1988 EXPECT_EQ(0, interstitial
->command_received_count());
1989 interstitial
->TestDomOperationResponse("toto");
1990 EXPECT_EQ(1, interstitial
->command_received_count());
1993 interstitial
->Proceed();
1994 RunAllPendingInMessageLoop();
1995 ASSERT_FALSE(deleted
);
1997 // While the navigation to the new page is pending, send other commands, they
1998 // should be ignored.
1999 interstitial
->TestDomOperationResponse("hello");
2000 interstitial
->TestDomOperationResponse("hi");
2001 EXPECT_EQ(1, interstitial
->command_received_count());
2004 // Test showing an interstitial while another interstitial is already showing.
2005 TEST_F(WebContentsImplTest
, ShowInterstitialOnInterstitial
) {
2006 // Navigate to a page so we have a navigation entry in the controller.
2007 GURL
start_url("http://www.google.com");
2008 contents()->GetMainFrame()->SendNavigate(1, start_url
);
2009 EXPECT_EQ(1, controller().GetEntryCount());
2011 // Show an interstitial.
2012 TestInterstitialPage::InterstitialState state1
=
2013 TestInterstitialPage::INVALID
;
2014 bool deleted1
= false;
2015 GURL
url1("http://interstitial1");
2016 TestInterstitialPage
* interstitial1
=
2017 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2018 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2019 interstitial1
->Show();
2020 interstitial1
->TestDidNavigate(1, url1
);
2022 // Now show another interstitial.
2023 TestInterstitialPage::InterstitialState state2
=
2024 TestInterstitialPage::INVALID
;
2025 bool deleted2
= false;
2026 GURL
url2("http://interstitial2");
2027 TestInterstitialPage
* interstitial2
=
2028 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2029 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2030 interstitial2
->Show();
2031 interstitial2
->TestDidNavigate(1, url2
);
2033 // Showing interstitial2 should have caused interstitial1 to go away.
2034 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2035 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2037 RunAllPendingInMessageLoop();
2038 EXPECT_TRUE(deleted1
);
2039 ASSERT_FALSE(deleted2
);
2041 // Let's make sure interstitial2 is working as intended.
2042 interstitial2
->Proceed();
2043 GURL
landing_url("http://www.thepage.com");
2044 contents()->GetMainFrame()->SendNavigate(2, landing_url
);
2046 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2047 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2048 NavigationEntry
* entry
= controller().GetVisibleEntry();
2049 ASSERT_TRUE(entry
!= NULL
);
2050 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2051 EXPECT_EQ(2, controller().GetEntryCount());
2052 RunAllPendingInMessageLoop();
2053 EXPECT_TRUE(deleted2
);
2056 // Test showing an interstitial, proceeding and then navigating to another
2058 TEST_F(WebContentsImplTest
, ShowInterstitialProceedShowInterstitial
) {
2059 // Navigate to a page so we have a navigation entry in the controller.
2060 GURL
start_url("http://www.google.com");
2061 contents()->GetMainFrame()->SendNavigate(1, start_url
);
2062 EXPECT_EQ(1, controller().GetEntryCount());
2064 // Show an interstitial.
2065 TestInterstitialPage::InterstitialState state1
=
2066 TestInterstitialPage::INVALID
;
2067 bool deleted1
= false;
2068 GURL
url1("http://interstitial1");
2069 TestInterstitialPage
* interstitial1
=
2070 new TestInterstitialPage(contents(), true, url1
, &state1
, &deleted1
);
2071 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2072 interstitial1
->Show();
2073 interstitial1
->TestDidNavigate(1, url1
);
2075 // Take action. The interstitial won't be hidden until the navigation is
2077 interstitial1
->Proceed();
2078 EXPECT_EQ(TestInterstitialPage::OKED
, state1
);
2080 // Now show another interstitial (simulating the navigation causing another
2082 TestInterstitialPage::InterstitialState state2
=
2083 TestInterstitialPage::INVALID
;
2084 bool deleted2
= false;
2085 GURL
url2("http://interstitial2");
2086 TestInterstitialPage
* interstitial2
=
2087 new TestInterstitialPage(contents(), true, url2
, &state2
, &deleted2
);
2088 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2089 interstitial2
->Show();
2090 interstitial2
->TestDidNavigate(1, url2
);
2092 // Showing interstitial2 should have caused interstitial1 to go away.
2093 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2094 RunAllPendingInMessageLoop();
2095 EXPECT_TRUE(deleted1
);
2096 ASSERT_FALSE(deleted2
);
2098 // Let's make sure interstitial2 is working as intended.
2099 interstitial2
->Proceed();
2100 GURL
landing_url("http://www.thepage.com");
2101 contents()->GetMainFrame()->SendNavigate(2, landing_url
);
2103 RunAllPendingInMessageLoop();
2104 EXPECT_TRUE(deleted2
);
2105 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2106 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL
);
2107 NavigationEntry
* entry
= controller().GetVisibleEntry();
2108 ASSERT_TRUE(entry
!= NULL
);
2109 EXPECT_TRUE(entry
->GetURL() == landing_url
);
2110 EXPECT_EQ(2, controller().GetEntryCount());
2113 // Test that navigating away from an interstitial while it's loading cause it
2115 TEST_F(WebContentsImplTest
, NavigateBeforeInterstitialShows
) {
2116 // Show an interstitial.
2117 TestInterstitialPage::InterstitialState state
=
2118 TestInterstitialPage::INVALID
;
2119 bool deleted
= false;
2120 GURL
interstitial_url("http://interstitial");
2121 TestInterstitialPage
* interstitial
=
2122 new TestInterstitialPage(contents(), true, interstitial_url
,
2124 TestInterstitialPageStateGuard
state_guard(interstitial
);
2125 interstitial
->Show();
2127 // Let's simulate a navigation initiated from the browser before the
2128 // interstitial finishes loading.
2129 const GURL
url("http://www.google.com");
2130 controller().LoadURL(
2131 url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2132 EXPECT_FALSE(interstitial
->is_showing());
2133 RunAllPendingInMessageLoop();
2134 ASSERT_FALSE(deleted
);
2136 // Now let's make the interstitial navigation commit.
2137 interstitial
->TestDidNavigate(1, interstitial_url
);
2139 // After it loaded the interstitial should be gone.
2140 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2142 RunAllPendingInMessageLoop();
2143 EXPECT_TRUE(deleted
);
2146 // Test that a new request to show an interstitial while an interstitial is
2147 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2148 TEST_F(WebContentsImplTest
, TwoQuickInterstitials
) {
2149 GURL
interstitial_url("http://interstitial");
2151 // Show a first interstitial.
2152 TestInterstitialPage::InterstitialState state1
=
2153 TestInterstitialPage::INVALID
;
2154 bool deleted1
= false;
2155 TestInterstitialPage
* interstitial1
=
2156 new TestInterstitialPage(contents(), true, interstitial_url
,
2157 &state1
, &deleted1
);
2158 TestInterstitialPageStateGuard
state_guard1(interstitial1
);
2159 interstitial1
->Show();
2161 // Show another interstitial on that same contents before the first one had
2163 TestInterstitialPage::InterstitialState state2
=
2164 TestInterstitialPage::INVALID
;
2165 bool deleted2
= false;
2166 TestInterstitialPage
* interstitial2
=
2167 new TestInterstitialPage(contents(), true, interstitial_url
,
2168 &state2
, &deleted2
);
2169 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2170 interstitial2
->Show();
2172 // The first interstitial should have been closed and deleted.
2173 EXPECT_EQ(TestInterstitialPage::CANCELED
, state1
);
2174 // The 2nd one should still be OK.
2175 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2177 RunAllPendingInMessageLoop();
2178 EXPECT_TRUE(deleted1
);
2179 ASSERT_FALSE(deleted2
);
2181 // Make the interstitial navigation commit it should be showing.
2182 interstitial2
->TestDidNavigate(1, interstitial_url
);
2183 EXPECT_EQ(interstitial2
, contents()->GetInterstitialPage());
2186 // Test showing an interstitial and have its renderer crash.
2187 TEST_F(WebContentsImplTest
, InterstitialCrasher
) {
2188 // Show an interstitial.
2189 TestInterstitialPage::InterstitialState state
=
2190 TestInterstitialPage::INVALID
;
2191 bool deleted
= false;
2192 GURL
url("http://interstitial");
2193 TestInterstitialPage
* interstitial
=
2194 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2195 TestInterstitialPageStateGuard
state_guard(interstitial
);
2196 interstitial
->Show();
2197 // Simulate a renderer crash before the interstitial is shown.
2198 interstitial
->TestRenderViewTerminated(
2199 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2200 // The interstitial should have been dismissed.
2201 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2202 RunAllPendingInMessageLoop();
2203 EXPECT_TRUE(deleted
);
2205 // Now try again but this time crash the intersitial after it was shown.
2207 new TestInterstitialPage(contents(), true, url
, &state
, &deleted
);
2208 interstitial
->Show();
2209 interstitial
->TestDidNavigate(1, url
);
2210 // Simulate a renderer crash.
2211 interstitial
->TestRenderViewTerminated(
2212 base::TERMINATION_STATUS_PROCESS_CRASHED
, -1);
2213 // The interstitial should have been dismissed.
2214 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2215 RunAllPendingInMessageLoop();
2216 EXPECT_TRUE(deleted
);
2219 // Tests that showing an interstitial as a result of a browser initiated
2220 // navigation while an interstitial is showing does not remove the pending
2221 // entry (see http://crbug.com/9791).
2222 TEST_F(WebContentsImplTest
, NewInterstitialDoesNotCancelPendingEntry
) {
2223 const char kUrl
[] = "http://www.badguys.com/";
2224 const GURL
kGURL(kUrl
);
2226 // Start a navigation to a page
2227 contents()->GetController().LoadURL(
2228 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2230 // Simulate that navigation triggering an interstitial.
2231 TestInterstitialPage::InterstitialState state
=
2232 TestInterstitialPage::INVALID
;
2233 bool deleted
= false;
2234 TestInterstitialPage
* interstitial
=
2235 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2236 TestInterstitialPageStateGuard
state_guard(interstitial
);
2237 interstitial
->Show();
2238 interstitial
->TestDidNavigate(1, kGURL
);
2240 // Initiate a new navigation from the browser that also triggers an
2242 contents()->GetController().LoadURL(
2243 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2244 TestInterstitialPage::InterstitialState state2
=
2245 TestInterstitialPage::INVALID
;
2246 bool deleted2
= false;
2247 TestInterstitialPage
* interstitial2
=
2248 new TestInterstitialPage(contents(), true, kGURL
, &state2
, &deleted2
);
2249 TestInterstitialPageStateGuard
state_guard2(interstitial2
);
2250 interstitial2
->Show();
2251 interstitial2
->TestDidNavigate(1, kGURL
);
2253 // Make sure we still have an entry.
2254 NavigationEntry
* entry
= contents()->GetController().GetPendingEntry();
2256 EXPECT_EQ(kUrl
, entry
->GetURL().spec());
2258 // And that the first interstitial is gone, but not the second.
2259 EXPECT_EQ(TestInterstitialPage::CANCELED
, state
);
2260 EXPECT_EQ(TestInterstitialPage::UNDECIDED
, state2
);
2261 RunAllPendingInMessageLoop();
2262 EXPECT_TRUE(deleted
);
2263 EXPECT_FALSE(deleted2
);
2266 // Tests that Javascript messages are not shown while an interstitial is
2268 TEST_F(WebContentsImplTest
, NoJSMessageOnInterstitials
) {
2269 const char kUrl
[] = "http://www.badguys.com/";
2270 const GURL
kGURL(kUrl
);
2272 // Start a navigation to a page
2273 contents()->GetController().LoadURL(
2274 kGURL
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2275 // DidNavigate from the page
2276 contents()->TestDidNavigate(
2277 contents()->GetMainFrame(), 1, kGURL
, ui::PAGE_TRANSITION_TYPED
);
2279 // Simulate showing an interstitial while the page is showing.
2280 TestInterstitialPage::InterstitialState state
=
2281 TestInterstitialPage::INVALID
;
2282 bool deleted
= false;
2283 TestInterstitialPage
* interstitial
=
2284 new TestInterstitialPage(contents(), true, kGURL
, &state
, &deleted
);
2285 TestInterstitialPageStateGuard
state_guard(interstitial
);
2286 interstitial
->Show();
2287 interstitial
->TestDidNavigate(1, kGURL
);
2289 // While the interstitial is showing, let's simulate the hidden page
2290 // attempting to show a JS message.
2291 IPC::Message
* dummy_message
= new IPC::Message
;
2292 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2293 base::ASCIIToUTF16("This is an informative message"),
2294 base::ASCIIToUTF16("OK"),
2295 kGURL
, JAVASCRIPT_MESSAGE_TYPE_ALERT
, dummy_message
);
2296 EXPECT_TRUE(contents()->last_dialog_suppressed_
);
2299 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2300 // interstitial it isn't copied over to the destination.
2301 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneSourceInterstitial
) {
2302 // Navigate to a page.
2303 GURL
url1("http://www.google.com");
2304 contents()->GetMainFrame()->SendNavigate(1, url1
);
2305 EXPECT_EQ(1, controller().GetEntryCount());
2307 // Initiate a browser navigation that will trigger the interstitial
2308 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2309 ui::PAGE_TRANSITION_TYPED
, std::string());
2311 // Show an interstitial.
2312 TestInterstitialPage::InterstitialState state
=
2313 TestInterstitialPage::INVALID
;
2314 bool deleted
= false;
2315 GURL
url2("http://interstitial");
2316 TestInterstitialPage
* interstitial
=
2317 new TestInterstitialPage(contents(), true, url2
, &state
, &deleted
);
2318 TestInterstitialPageStateGuard
state_guard(interstitial
);
2319 interstitial
->Show();
2320 interstitial
->TestDidNavigate(1, url2
);
2321 EXPECT_TRUE(interstitial
->is_showing());
2322 EXPECT_EQ(2, controller().GetEntryCount());
2324 // Create another NavigationController.
2325 GURL
url3("http://foo2");
2326 scoped_ptr
<TestWebContents
> other_contents(
2327 static_cast<TestWebContents
*>(CreateTestWebContents()));
2328 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2329 other_contents
->NavigateAndCommit(url3
);
2330 other_contents
->ExpectSetHistoryOffsetAndLength(1, 2);
2331 other_controller
.CopyStateFromAndPrune(&controller(), false);
2333 // The merged controller should only have two entries: url1 and url2.
2334 ASSERT_EQ(2, other_controller
.GetEntryCount());
2335 EXPECT_EQ(1, other_controller
.GetCurrentEntryIndex());
2336 EXPECT_EQ(url1
, other_controller
.GetEntryAtIndex(0)->GetURL());
2337 EXPECT_EQ(url3
, other_controller
.GetEntryAtIndex(1)->GetURL());
2339 // And the merged controller shouldn't be showing an interstitial.
2340 EXPECT_FALSE(other_contents
->ShowingInterstitialPage());
2343 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2344 // showing an interstitial.
2345 TEST_F(WebContentsImplTest
, CopyStateFromAndPruneTargetInterstitial
) {
2346 // Navigate to a page.
2347 GURL
url1("http://www.google.com");
2348 contents()->NavigateAndCommit(url1
);
2350 // Create another NavigationController.
2351 scoped_ptr
<TestWebContents
> other_contents(
2352 static_cast<TestWebContents
*>(CreateTestWebContents()));
2353 NavigationControllerImpl
& other_controller
= other_contents
->GetController();
2355 // Navigate it to url2.
2356 GURL
url2("http://foo2");
2357 other_contents
->NavigateAndCommit(url2
);
2359 // Show an interstitial.
2360 TestInterstitialPage::InterstitialState state
=
2361 TestInterstitialPage::INVALID
;
2362 bool deleted
= false;
2363 GURL
url3("http://interstitial");
2364 TestInterstitialPage
* interstitial
=
2365 new TestInterstitialPage(other_contents
.get(), true, url3
, &state
,
2367 TestInterstitialPageStateGuard
state_guard(interstitial
);
2368 interstitial
->Show();
2369 interstitial
->TestDidNavigate(1, url3
);
2370 EXPECT_TRUE(interstitial
->is_showing());
2371 EXPECT_EQ(2, other_controller
.GetEntryCount());
2373 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2374 // interstitial is showing in the target.
2375 EXPECT_FALSE(other_controller
.CanPruneAllButLastCommitted());
2378 // Regression test for http://crbug.com/168611 - the URLs passed by the
2379 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2380 TEST_F(WebContentsImplTest
, FilterURLs
) {
2381 TestWebContentsObserver
observer(contents());
2383 // A navigation to about:whatever should always look like a navigation to
2385 GURL
url_normalized(url::kAboutBlankURL
);
2386 GURL
url_from_ipc("about:whatever");
2388 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2389 // will use the given URL to create the NavigationEntry as well, and that
2390 // entry should contain the filtered URL.
2391 contents()->NavigateAndCommit(url_normalized
);
2393 // Check that an IPC with about:whatever is correctly normalized.
2394 contents()->TestDidFinishLoad(url_from_ipc
);
2396 EXPECT_EQ(url_normalized
, observer
.last_url());
2398 // Create and navigate another WebContents.
2399 scoped_ptr
<TestWebContents
> other_contents(
2400 static_cast<TestWebContents
*>(CreateTestWebContents()));
2401 TestWebContentsObserver
other_observer(other_contents
.get());
2402 other_contents
->NavigateAndCommit(url_normalized
);
2404 // Check that an IPC with about:whatever is correctly normalized.
2405 other_contents
->TestDidFailLoadWithError(
2406 url_from_ipc
, 1, base::string16());
2407 EXPECT_EQ(url_normalized
, other_observer
.last_url());
2410 // Test that if a pending contents is deleted before it is shown, we don't
2412 TEST_F(WebContentsImplTest
, PendingContents
) {
2413 scoped_ptr
<TestWebContents
> other_contents(
2414 static_cast<TestWebContents
*>(CreateTestWebContents()));
2415 contents()->AddPendingContents(other_contents
.get());
2416 int route_id
= other_contents
->GetRenderViewHost()->GetRoutingID();
2417 other_contents
.reset();
2418 EXPECT_EQ(NULL
, contents()->GetCreatedWindow(route_id
));
2421 TEST_F(WebContentsImplTest
, CapturerOverridesPreferredSize
) {
2422 const gfx::Size
original_preferred_size(1024, 768);
2423 contents()->UpdatePreferredSize(original_preferred_size
);
2425 // With no capturers, expect the preferred size to be the one propagated into
2426 // WebContentsImpl via the RenderViewHostDelegate interface.
2427 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2428 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2430 // Increment capturer count, but without specifying a capture size. Expect
2431 // a "not set" preferred size.
2432 contents()->IncrementCapturerCount(gfx::Size());
2433 EXPECT_EQ(1, contents()->GetCapturerCount());
2434 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2436 // Increment capturer count again, but with an overriding capture size.
2437 // Expect preferred size to now be overridden to the capture size.
2438 const gfx::Size
capture_size(1280, 720);
2439 contents()->IncrementCapturerCount(capture_size
);
2440 EXPECT_EQ(2, contents()->GetCapturerCount());
2441 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2443 // Increment capturer count a third time, but the expect that the preferred
2444 // size is still the first capture size.
2445 const gfx::Size
another_capture_size(720, 480);
2446 contents()->IncrementCapturerCount(another_capture_size
);
2447 EXPECT_EQ(3, contents()->GetCapturerCount());
2448 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2450 // Decrement capturer count twice, but expect the preferred size to still be
2452 contents()->DecrementCapturerCount();
2453 contents()->DecrementCapturerCount();
2454 EXPECT_EQ(1, contents()->GetCapturerCount());
2455 EXPECT_EQ(capture_size
, contents()->GetPreferredSize());
2457 // Decrement capturer count, and since the count has dropped to zero, the
2458 // original preferred size should be restored.
2459 contents()->DecrementCapturerCount();
2460 EXPECT_EQ(0, contents()->GetCapturerCount());
2461 EXPECT_EQ(original_preferred_size
, contents()->GetPreferredSize());
2464 TEST_F(WebContentsImplTest
, CapturerPreventsHiding
) {
2465 const gfx::Size
original_preferred_size(1024, 768);
2466 contents()->UpdatePreferredSize(original_preferred_size
);
2468 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2469 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2471 // With no capturers, setting and un-setting occlusion should change the
2472 // view's occlusion state.
2473 EXPECT_FALSE(view
->is_showing());
2474 contents()->WasShown();
2475 EXPECT_TRUE(view
->is_showing());
2476 contents()->WasHidden();
2477 EXPECT_FALSE(view
->is_showing());
2478 contents()->WasShown();
2479 EXPECT_TRUE(view
->is_showing());
2481 // Add a capturer and try to hide the contents. The view will remain visible.
2482 contents()->IncrementCapturerCount(gfx::Size());
2483 contents()->WasHidden();
2484 EXPECT_TRUE(view
->is_showing());
2486 // Remove the capturer, and the WasHidden should take effect.
2487 contents()->DecrementCapturerCount();
2488 EXPECT_FALSE(view
->is_showing());
2491 TEST_F(WebContentsImplTest
, CapturerPreventsOcclusion
) {
2492 const gfx::Size
original_preferred_size(1024, 768);
2493 contents()->UpdatePreferredSize(original_preferred_size
);
2495 TestRenderWidgetHostView
* view
= static_cast<TestRenderWidgetHostView
*>(
2496 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2498 // With no capturers, setting and un-setting occlusion should change the
2499 // view's occlusion state.
2500 EXPECT_FALSE(view
->is_occluded());
2501 contents()->WasOccluded();
2502 EXPECT_TRUE(view
->is_occluded());
2503 contents()->WasUnOccluded();
2504 EXPECT_FALSE(view
->is_occluded());
2505 contents()->WasOccluded();
2506 EXPECT_TRUE(view
->is_occluded());
2508 // Add a capturer. This should cause the view to be un-occluded.
2509 contents()->IncrementCapturerCount(gfx::Size());
2510 EXPECT_FALSE(view
->is_occluded());
2512 // Try to occlude the view. This will fail to propagate because of the
2514 contents()->WasOccluded();
2515 EXPECT_FALSE(view
->is_occluded());
2517 // Remove the capturer and try again.
2518 contents()->DecrementCapturerCount();
2519 EXPECT_FALSE(view
->is_occluded());
2520 contents()->WasOccluded();
2521 EXPECT_TRUE(view
->is_occluded());
2524 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2526 TEST_F(WebContentsImplTest
, GetLastActiveTime
) {
2527 // The WebContents starts with a valid creation time.
2528 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2530 // Reset the last active time to a known-bad value.
2531 contents()->last_active_time_
= base::TimeTicks();
2532 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2534 // Simulate activating the WebContents. The active time should update.
2535 contents()->WasShown();
2536 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2539 class ContentsZoomChangedDelegate
: public WebContentsDelegate
{
2541 ContentsZoomChangedDelegate() :
2542 contents_zoom_changed_call_count_(0),
2543 last_zoom_in_(false) {
2546 int GetAndResetContentsZoomChangedCallCount() {
2547 int count
= contents_zoom_changed_call_count_
;
2548 contents_zoom_changed_call_count_
= 0;
2552 bool last_zoom_in() const {
2553 return last_zoom_in_
;
2556 // WebContentsDelegate:
2557 void ContentsZoomChange(bool zoom_in
) override
{
2558 contents_zoom_changed_call_count_
++;
2559 last_zoom_in_
= zoom_in
;
2563 int contents_zoom_changed_call_count_
;
2566 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate
);
2569 // Tests that some mouseehweel events get turned into browser zoom requests.
2570 TEST_F(WebContentsImplTest
, HandleWheelEvent
) {
2571 using blink::WebInputEvent
;
2573 scoped_ptr
<ContentsZoomChangedDelegate
> delegate(
2574 new ContentsZoomChangedDelegate());
2575 contents()->SetDelegate(delegate
.get());
2578 // Verify that normal mouse wheel events do nothing to change the zoom level.
2579 blink::WebMouseWheelEvent event
=
2580 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2581 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2582 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2584 modifiers
= WebInputEvent::ShiftKey
| WebInputEvent::AltKey
|
2585 WebInputEvent::ControlKey
;
2586 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2587 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2588 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2590 // But whenever the ctrl modifier is applied with canScroll=false, they can
2591 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2593 modifiers
= WebInputEvent::ControlKey
;
2594 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers
, false);
2595 event
.canScroll
= false;
2596 bool handled
= contents()->HandleWheelEvent(event
);
2597 #if defined(OS_MACOSX)
2598 EXPECT_FALSE(handled
);
2599 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2601 EXPECT_TRUE(handled
);
2602 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2603 EXPECT_TRUE(delegate
->last_zoom_in());
2606 modifiers
= WebInputEvent::ControlKey
| WebInputEvent::ShiftKey
|
2607 WebInputEvent::AltKey
;
2608 event
= SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers
, false);
2609 event
.canScroll
= false;
2610 handled
= contents()->HandleWheelEvent(event
);
2611 #if defined(OS_MACOSX)
2612 EXPECT_FALSE(handled
);
2613 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2615 EXPECT_TRUE(handled
);
2616 EXPECT_EQ(1, delegate
->GetAndResetContentsZoomChangedCallCount());
2617 EXPECT_FALSE(delegate
->last_zoom_in());
2620 // Unless there is no vertical movement.
2621 event
= SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers
, false);
2622 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2623 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2625 // Events containing precise scrolling deltas also shouldn't result in the
2626 // zoom being adjusted, to avoid accidental adjustments caused by
2627 // two-finger-scrolling on a touchpad.
2628 modifiers
= WebInputEvent::ControlKey
;
2629 event
= SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers
, true);
2630 EXPECT_FALSE(contents()->HandleWheelEvent(event
));
2631 EXPECT_EQ(0, delegate
->GetAndResetContentsZoomChangedCallCount());
2633 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2634 contents()->SetDelegate(NULL
);
2637 // Tests that GetRelatedActiveContentsCount is shared between related
2638 // SiteInstances and includes WebContents that have not navigated yet.
2639 TEST_F(WebContentsImplTest
, ActiveContentsCountBasic
) {
2640 scoped_refptr
<SiteInstance
> instance1(
2641 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2642 scoped_refptr
<SiteInstance
> instance2(
2643 instance1
->GetRelatedSiteInstance(GURL("http://b.com")));
2645 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2646 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2648 scoped_ptr
<TestWebContents
> contents1(
2649 TestWebContents::Create(browser_context(), instance1
.get()));
2650 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2651 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2653 scoped_ptr
<TestWebContents
> contents2(
2654 TestWebContents::Create(browser_context(), instance1
.get()));
2655 EXPECT_EQ(2u, instance1
->GetRelatedActiveContentsCount());
2656 EXPECT_EQ(2u, instance2
->GetRelatedActiveContentsCount());
2659 EXPECT_EQ(1u, instance1
->GetRelatedActiveContentsCount());
2660 EXPECT_EQ(1u, instance2
->GetRelatedActiveContentsCount());
2663 EXPECT_EQ(0u, instance1
->GetRelatedActiveContentsCount());
2664 EXPECT_EQ(0u, instance2
->GetRelatedActiveContentsCount());
2667 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2668 // same-site and cross-site navigations.
2669 TEST_F(WebContentsImplTest
, ActiveContentsCountNavigate
) {
2670 scoped_refptr
<SiteInstance
> instance(
2671 SiteInstance::Create(browser_context()));
2673 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2675 scoped_ptr
<TestWebContents
> contents(
2676 TestWebContents::Create(browser_context(), instance
.get()));
2677 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2679 // Navigate to a URL.
2680 contents
->GetController().LoadURL(GURL("http://a.com/1"),
2682 ui::PAGE_TRANSITION_TYPED
,
2684 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2685 contents
->CommitPendingNavigation();
2686 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2688 // Navigate to a URL in the same site.
2689 contents
->GetController().LoadURL(GURL("http://a.com/2"),
2691 ui::PAGE_TRANSITION_TYPED
,
2693 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2694 contents
->CommitPendingNavigation();
2695 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2697 // Navigate to a URL in a different site.
2698 const GURL kUrl
= GURL("http://b.com");
2699 contents
->GetController().LoadURL(kUrl
,
2701 ui::PAGE_TRANSITION_TYPED
,
2703 contents
->GetMainFrame()->PrepareForCommit(kUrl
);
2704 EXPECT_TRUE(contents
->cross_navigation_pending());
2705 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2706 contents
->CommitPendingNavigation();
2707 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2710 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2713 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2715 TEST_F(WebContentsImplTest
, ActiveContentsCountChangeBrowsingInstance
) {
2716 scoped_refptr
<SiteInstance
> instance(
2717 SiteInstance::Create(browser_context()));
2719 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2721 scoped_ptr
<TestWebContents
> contents(
2722 TestWebContents::Create(browser_context(), instance
.get()));
2723 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2725 // Navigate to a URL.
2726 contents
->NavigateAndCommit(GURL("http://a.com"));
2727 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2729 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2730 contents
->GetController().LoadURL(GURL(kTestWebUIUrl
),
2732 ui::PAGE_TRANSITION_TYPED
,
2734 contents
->GetMainFrame()->PrepareForCommit(GURL(kTestWebUIUrl
));
2735 EXPECT_TRUE(contents
->cross_navigation_pending());
2736 scoped_refptr
<SiteInstance
> instance_webui(
2737 contents
->GetPendingMainFrame()->GetSiteInstance());
2738 EXPECT_FALSE(instance
->IsRelatedSiteInstance(instance_webui
.get()));
2740 // At this point, contents still counts for the old BrowsingInstance.
2741 EXPECT_EQ(1u, instance
->GetRelatedActiveContentsCount());
2742 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2744 // Commit and contents counts for the new one.
2745 contents
->CommitPendingNavigation();
2746 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2747 EXPECT_EQ(1u, instance_webui
->GetRelatedActiveContentsCount());
2750 EXPECT_EQ(0u, instance
->GetRelatedActiveContentsCount());
2751 EXPECT_EQ(0u, instance_webui
->GetRelatedActiveContentsCount());
2754 class LoadingWebContentsObserver
: public WebContentsObserver
{
2756 explicit LoadingWebContentsObserver(WebContents
* contents
)
2757 : WebContentsObserver(contents
),
2758 is_loading_(false) {
2760 ~LoadingWebContentsObserver() override
{}
2762 void DidStartLoading(RenderViewHost
* rvh
) override
{
2765 void DidStopLoading(RenderViewHost
* rvh
) override
{
2766 is_loading_
= false;
2769 bool is_loading() const { return is_loading_
; }
2774 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver
);
2777 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2778 // interleaving cross-process navigations in multiple subframes.
2779 // See https://crbug.com/448601 for details of the underlying issue. The
2780 // sequence of events that reproduce it are as follows:
2781 // * Navigate top-level frame with one subframe.
2782 // * Subframe navigates more than once before the top-level frame has had a
2783 // chance to complete the load.
2784 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2785 // to 0, while the loading_progresses_ map is not reset.
2786 TEST_F(WebContentsImplTest
, StartStopEventsBalance
) {
2787 // The bug manifests itself in regular mode as well, but browser-initiated
2788 // navigation of subframes is only possible in --site-per-process mode within
2790 base::CommandLine::ForCurrentProcess()->AppendSwitch(
2791 switches::kSitePerProcess
);
2792 const GURL
main_url("http://www.chromium.org");
2793 const GURL
foo_url("http://foo.chromium.org");
2794 const GURL
bar_url("http://bar.chromium.org");
2795 TestRenderFrameHost
* orig_rfh
= contents()->GetMainFrame();
2797 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
2798 LoadingWebContentsObserver
observer(contents());
2800 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
2801 // The frame should still be loading.
2802 controller().LoadURL(
2803 main_url
, Referrer(), ui::PAGE_TRANSITION_TYPED
, std::string());
2804 orig_rfh
->OnMessageReceived(
2805 FrameHostMsg_DidStartLoading(orig_rfh
->GetRoutingID(), false));
2806 contents()->TestDidNavigate(orig_rfh
, 1, main_url
, ui::PAGE_TRANSITION_TYPED
);
2807 EXPECT_FALSE(contents()->cross_navigation_pending());
2808 EXPECT_EQ(orig_rfh
, contents()->GetMainFrame());
2809 EXPECT_TRUE(contents()->IsLoading());
2810 EXPECT_TRUE(observer
.is_loading());
2812 // Create a child frame to navigate multiple times.
2813 TestRenderFrameHost
* subframe
= orig_rfh
->AppendChild("subframe");
2815 // Navigate the child frame to about:blank, which will send both
2816 // DidStartLoading and DidStopLoading messages.
2818 subframe
->OnMessageReceived(
2819 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2820 subframe
->SendNavigateWithTransition(
2821 1, GURL("about:blank"), ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2822 subframe
->OnMessageReceived(
2823 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2826 // Navigate the frame to another URL, which will send again
2827 // DidStartLoading and DidStopLoading messages.
2829 subframe
->OnMessageReceived(
2830 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2831 subframe
->SendNavigateWithTransition(
2832 1, foo_url
, ui::PAGE_TRANSITION_AUTO_SUBFRAME
);
2833 subframe
->OnMessageReceived(
2834 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2837 // Since the main frame hasn't sent any DidStopLoading messages, it is
2838 // expected that the WebContents is still in loading state.
2839 EXPECT_TRUE(contents()->IsLoading());
2840 EXPECT_TRUE(observer
.is_loading());
2842 // Navigate the frame again, this time using LoadURLWithParams. This causes
2843 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2846 NavigationController::LoadURLParams
load_params(bar_url
);
2847 load_params
.referrer
=
2848 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault
);
2849 load_params
.transition_type
= ui::PAGE_TRANSITION_GENERATED
;
2850 load_params
.extra_headers
= "content-type: text/plain";
2851 load_params
.load_type
= NavigationController::LOAD_TYPE_DEFAULT
;
2852 load_params
.is_renderer_initiated
= false;
2853 load_params
.override_user_agent
= NavigationController::UA_OVERRIDE_TRUE
;
2854 load_params
.frame_tree_node_id
=
2855 subframe
->frame_tree_node()->frame_tree_node_id();
2856 controller().LoadURLWithParams(load_params
);
2858 subframe
->OnMessageReceived(
2859 FrameHostMsg_DidStartLoading(subframe
->GetRoutingID(), true));
2861 // Commit the navigation in the child frame and send the DidStopLoading
2863 contents()->TestDidNavigate(
2864 subframe
, 3, bar_url
, ui::PAGE_TRANSITION_MANUAL_SUBFRAME
);
2865 subframe
->OnMessageReceived(
2866 FrameHostMsg_DidStopLoading(subframe
->GetRoutingID()));
2869 // At this point the status should still be loading, since the main frame
2870 // hasn't sent the DidstopLoading message yet.
2871 EXPECT_TRUE(contents()->IsLoading());
2872 EXPECT_TRUE(observer
.is_loading());
2874 // Send the DidStopLoading for the main frame and ensure it isn't loading
2876 orig_rfh
->OnMessageReceived(
2877 FrameHostMsg_DidStopLoading(orig_rfh
->GetRoutingID()));
2878 EXPECT_FALSE(contents()->IsLoading());
2879 EXPECT_FALSE(observer
.is_loading());
2882 TEST_F(WebContentsImplTest
, MediaPowerSaveBlocking
) {
2883 // PlayerIDs are actually pointers cast to int64, so verify that both negative
2884 // and positive player ids don't blow up.
2885 const int kPlayerAudioVideoId
= 15;
2886 const int kPlayerAudioOnlyId
= -15;
2887 const int kPlayerVideoOnlyId
= 30;
2888 const int kPlayerRemoteId
= -30;
2890 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2891 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2893 TestRenderFrameHost
* rfh
= contents()->GetMainFrame();
2894 AudioStreamMonitor
* monitor
= contents()->audio_stream_monitor();
2896 // The audio power save blocker should not be based on having a media player
2897 // when audio stream monitoring is available.
2898 if (AudioStreamMonitor::monitoring_available()) {
2899 // Send a fake audio stream monitor notification. The audio power save
2900 // blocker should be created.
2901 monitor
->set_was_recently_audible_for_testing(true);
2902 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
2903 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
2905 // Send another fake notification, this time when WasRecentlyAudible() will
2906 // be false. The power save blocker should be released.
2907 monitor
->set_was_recently_audible_for_testing(false);
2908 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB
);
2909 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2912 // Start a player with both audio and video. A video power save blocker
2913 // should be created. If audio stream monitoring is available, an audio power
2914 // save blocker should be created too.
2915 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2916 0, kPlayerAudioVideoId
, true, true, false));
2917 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2918 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2919 !AudioStreamMonitor::monitoring_available());
2921 // Upon hiding the video power save blocker should be released.
2922 contents()->WasHidden();
2923 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2925 // Start another player that only has video. There should be no change in
2926 // the power save blockers. The notification should take into account the
2927 // visibility state of the WebContents.
2928 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2929 0, kPlayerVideoOnlyId
, true, false, false));
2930 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2931 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2932 !AudioStreamMonitor::monitoring_available());
2934 // Showing the WebContents should result in the creation of the blocker.
2935 contents()->WasShown();
2936 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2938 // Start another player that only has audio. There should be no change in
2939 // the power save blockers.
2940 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2941 0, kPlayerAudioOnlyId
, false, true, false));
2942 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2943 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2944 !AudioStreamMonitor::monitoring_available());
2946 // Start a remote player. There should be no change in the power save
2948 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2949 0, kPlayerRemoteId
, true, true, true));
2950 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2951 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2952 !AudioStreamMonitor::monitoring_available());
2954 // Destroy the original audio video player. Both power save blockers should
2956 rfh
->OnMessageReceived(
2957 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId
));
2958 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2959 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2960 !AudioStreamMonitor::monitoring_available());
2962 // Destroy the audio only player. The video power save blocker should remain.
2963 rfh
->OnMessageReceived(
2964 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId
));
2965 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2966 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2968 // Destroy the video only player. No power save blockers should remain.
2969 rfh
->OnMessageReceived(
2970 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId
));
2971 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2972 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2974 // Destroy the remote player. No power save blockers should remain.
2975 rfh
->OnMessageReceived(
2976 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId
));
2977 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2978 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2980 // Start a player with both audio and video. A video power save blocker
2981 // should be created. If audio stream monitoring is available, an audio power
2982 // save blocker should be created too.
2983 rfh
->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
2984 0, kPlayerAudioVideoId
, true, true, false));
2985 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
2986 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
2987 !AudioStreamMonitor::monitoring_available());
2989 // Crash the renderer.
2990 contents()->GetMainFrame()->OnMessageReceived(
2991 FrameHostMsg_RenderProcessGone(
2992 0, base::TERMINATION_STATUS_PROCESS_CRASHED
, -1));
2994 // Verify that all the power save blockers have been released.
2995 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
2996 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
2999 // Test that sudden termination status is properly tracked for a frame.
3000 TEST_F(WebContentsImplTest
, SuddenTerminationForFrame
) {
3001 const GURL
url("http://www.chromium.org");
3002 contents()->NavigateAndCommit(url
);
3004 TestRenderFrameHost
* frame
= contents()->GetMainFrame();
3005 EXPECT_TRUE(frame
->SuddenTerminationAllowed());
3007 // Register a BeforeUnload handler.
3008 frame
->SendBeforeUnloadHandlersPresent(true);
3009 EXPECT_FALSE(frame
->SuddenTerminationAllowed());
3011 // Unregister the BeforeUnload handler.
3012 frame
->SendBeforeUnloadHandlersPresent(false);
3013 EXPECT_TRUE(frame
->SuddenTerminationAllowed());
3015 // Register an Unload handler.
3016 frame
->SendUnloadHandlersPresent(true);
3017 EXPECT_FALSE(frame
->SuddenTerminationAllowed());
3019 // Unregister the Unload handler.
3020 frame
->SendUnloadHandlersPresent(false);
3021 EXPECT_TRUE(frame
->SuddenTerminationAllowed());
3023 // Register a BeforeUnload handler and an Unload handler.
3024 frame
->SendBeforeUnloadHandlersPresent(true);
3025 frame
->SendUnloadHandlersPresent(true);
3026 EXPECT_FALSE(frame
->SuddenTerminationAllowed());
3028 // Override the sudden termination status.
3029 frame
->set_override_sudden_termination_status(true);
3030 EXPECT_TRUE(frame
->SuddenTerminationAllowed());
3031 frame
->set_override_sudden_termination_status(false);
3032 EXPECT_FALSE(frame
->SuddenTerminationAllowed());
3034 // Sudden termination should not be allowed unless there are no BeforeUnload
3035 // handlers and no Unload handlers in the RenderFrame.
3036 frame
->SendBeforeUnloadHandlersPresent(false);
3037 EXPECT_FALSE(frame
->SuddenTerminationAllowed());
3038 frame
->SendBeforeUnloadHandlersPresent(true);
3039 frame
->SendUnloadHandlersPresent(false);
3040 EXPECT_FALSE(frame
->SuddenTerminationAllowed());
3041 frame
->SendBeforeUnloadHandlersPresent(false);
3042 EXPECT_TRUE(frame
->SuddenTerminationAllowed());
3045 } // namespace content