Fix various typos, error handling for GN auto-roller.
[chromium-blink-merge.git] / content / browser / web_contents / web_contents_impl_unittest.cc
blob380e4f27e50160e864d78b230259be1dd9fdcea3
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/logging.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/frame_host/cross_site_transferring_request.h"
9 #include "content/browser/frame_host/interstitial_page_impl.h"
10 #include "content/browser/frame_host/navigation_entry_impl.h"
11 #include "content/browser/frame_host/render_frame_host_impl.h"
12 #include "content/browser/frame_host/render_frame_proxy_host.h"
13 #include "content/browser/media/audio_state_provider.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/browser/site_instance_impl.h"
16 #include "content/browser/webui/content_web_ui_controller_factory.h"
17 #include "content/browser/webui/web_ui_controller_factory_registry.h"
18 #include "content/common/frame_messages.h"
19 #include "content/common/input/synthetic_web_input_event_builders.h"
20 #include "content/common/view_messages.h"
21 #include "content/public/browser/global_request_id.h"
22 #include "content/public/browser/interstitial_page_delegate.h"
23 #include "content/public/browser/navigation_details.h"
24 #include "content/public/browser/notification_details.h"
25 #include "content/public/browser/notification_source.h"
26 #include "content/public/browser/render_widget_host_view.h"
27 #include "content/public/browser/web_contents_delegate.h"
28 #include "content/public/browser/web_contents_observer.h"
29 #include "content/public/browser/web_ui_controller.h"
30 #include "content/public/common/bindings_policy.h"
31 #include "content/public/common/content_constants.h"
32 #include "content/public/common/content_switches.h"
33 #include "content/public/common/url_constants.h"
34 #include "content/public/common/url_utils.h"
35 #include "content/public/test/browser_test_utils.h"
36 #include "content/public/test/mock_render_process_host.h"
37 #include "content/public/test/test_utils.h"
38 #include "content/test/test_content_browser_client.h"
39 #include "content/test/test_content_client.h"
40 #include "content/test/test_render_frame_host.h"
41 #include "content/test/test_render_view_host.h"
42 #include "content/test/test_web_contents.h"
43 #include "testing/gtest/include/gtest/gtest.h"
44 #include "third_party/skia/include/core/SkColor.h"
46 namespace content {
47 namespace {
49 class TestInterstitialPage;
51 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
52 public:
53 explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
54 : interstitial_page_(interstitial_page) {}
55 void CommandReceived(const std::string& command) override;
56 std::string GetHTMLContents() override { return std::string(); }
57 void OnDontProceed() override;
58 void OnProceed() override;
60 private:
61 TestInterstitialPage* interstitial_page_;
64 class TestInterstitialPage : public InterstitialPageImpl {
65 public:
66 enum InterstitialState {
67 INVALID = 0, // Hasn't yet been initialized.
68 UNDECIDED, // Initialized, but no decision taken yet.
69 OKED, // Proceed was called.
70 CANCELED // DontProceed was called.
73 class Delegate {
74 public:
75 virtual void TestInterstitialPageDeleted(
76 TestInterstitialPage* interstitial) = 0;
78 protected:
79 virtual ~Delegate() {}
82 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
83 // |deleted| (like all interstitial related tests do at this point), make sure
84 // to create an instance of the TestInterstitialPageStateGuard class on the
85 // stack in your test. This will ensure that the TestInterstitialPage states
86 // are cleared when the test finishes.
87 // Not doing so will cause stack trashing if your test does not hide the
88 // interstitial, as in such a case it will be destroyed in the test TearDown
89 // method and will dereference the |deleted| local variable which by then is
90 // out of scope.
91 TestInterstitialPage(WebContentsImpl* contents,
92 bool new_navigation,
93 const GURL& url,
94 InterstitialState* state,
95 bool* deleted)
96 : InterstitialPageImpl(
97 contents,
98 static_cast<RenderWidgetHostDelegate*>(contents),
99 new_navigation, url, new TestInterstitialPageDelegate(this)),
100 state_(state),
101 deleted_(deleted),
102 command_received_count_(0),
103 delegate_(nullptr) {
104 *state_ = UNDECIDED;
105 *deleted_ = false;
108 ~TestInterstitialPage() override {
109 if (deleted_)
110 *deleted_ = true;
111 if (delegate_)
112 delegate_->TestInterstitialPageDeleted(this);
115 void OnDontProceed() {
116 if (state_)
117 *state_ = CANCELED;
119 void OnProceed() {
120 if (state_)
121 *state_ = OKED;
124 int command_received_count() const {
125 return command_received_count_;
128 void TestDomOperationResponse(const std::string& json_string) {
129 if (enabled())
130 CommandReceived();
133 void TestDidNavigate(int page_id,
134 int nav_entry_id,
135 bool did_create_new_entry,
136 const GURL& url) {
137 FrameHostMsg_DidCommitProvisionalLoad_Params params;
138 InitNavigateParams(&params, page_id, nav_entry_id, did_create_new_entry,
139 url, ui::PAGE_TRANSITION_TYPED);
140 DidNavigate(GetMainFrame()->GetRenderViewHost(), params);
143 void TestRenderViewTerminated(base::TerminationStatus status,
144 int error_code) {
145 RenderViewTerminated(GetMainFrame()->GetRenderViewHost(), status,
146 error_code);
149 bool is_showing() const {
150 return static_cast<TestRenderWidgetHostView*>(
151 GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
154 void ClearStates() {
155 state_ = nullptr;
156 deleted_ = nullptr;
157 delegate_ = nullptr;
160 void CommandReceived() {
161 command_received_count_++;
164 void set_delegate(Delegate* delegate) {
165 delegate_ = delegate;
168 protected:
169 WebContentsView* CreateWebContentsView() override { return nullptr; }
171 private:
172 InterstitialState* state_;
173 bool* deleted_;
174 int command_received_count_;
175 Delegate* delegate_;
178 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
179 interstitial_page_->CommandReceived();
182 void TestInterstitialPageDelegate::OnDontProceed() {
183 interstitial_page_->OnDontProceed();
186 void TestInterstitialPageDelegate::OnProceed() {
187 interstitial_page_->OnProceed();
190 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
191 public:
192 explicit TestInterstitialPageStateGuard(
193 TestInterstitialPage* interstitial_page)
194 : interstitial_page_(interstitial_page) {
195 DCHECK(interstitial_page_);
196 interstitial_page_->set_delegate(this);
198 ~TestInterstitialPageStateGuard() override {
199 if (interstitial_page_)
200 interstitial_page_->ClearStates();
203 void TestInterstitialPageDeleted(
204 TestInterstitialPage* interstitial) override {
205 DCHECK(interstitial_page_ == interstitial);
206 interstitial_page_ = nullptr;
209 private:
210 TestInterstitialPage* interstitial_page_;
213 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
214 public:
215 WebContentsImplTestBrowserClient()
216 : assign_site_for_url_(false) {}
218 ~WebContentsImplTestBrowserClient() override {}
220 bool ShouldAssignSiteForURL(const GURL& url) override {
221 return assign_site_for_url_;
224 void set_assign_site_for_url(bool assign) {
225 assign_site_for_url_ = assign;
228 private:
229 bool assign_site_for_url_;
232 class WebContentsImplTest : public RenderViewHostImplTestHarness {
233 public:
234 void SetUp() override {
235 RenderViewHostImplTestHarness::SetUp();
236 WebUIControllerFactory::RegisterFactory(
237 ContentWebUIControllerFactory::GetInstance());
240 void TearDown() override {
241 WebUIControllerFactory::UnregisterFactoryForTesting(
242 ContentWebUIControllerFactory::GetInstance());
243 RenderViewHostImplTestHarness::TearDown();
247 class TestWebContentsObserver : public WebContentsObserver {
248 public:
249 explicit TestWebContentsObserver(WebContents* contents)
250 : WebContentsObserver(contents),
251 last_theme_color_(SK_ColorTRANSPARENT) {
253 ~TestWebContentsObserver() override {}
255 void DidFinishLoad(RenderFrameHost* render_frame_host,
256 const GURL& validated_url) override {
257 last_url_ = validated_url;
259 void DidFailLoad(RenderFrameHost* render_frame_host,
260 const GURL& validated_url,
261 int error_code,
262 const base::string16& error_description,
263 bool was_ignored_by_handler) override {
264 last_url_ = validated_url;
267 void DidChangeThemeColor(SkColor theme_color) override {
268 last_theme_color_ = theme_color;
271 const GURL& last_url() const { return last_url_; }
272 SkColor last_theme_color() const { return last_theme_color_; }
274 private:
275 GURL last_url_;
276 SkColor last_theme_color_;
278 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
281 // Pretends to be a normal browser that receives toggles and transitions to/from
282 // a fullscreened state.
283 class FakeFullscreenDelegate : public WebContentsDelegate {
284 public:
285 FakeFullscreenDelegate() : fullscreened_contents_(nullptr) {}
286 ~FakeFullscreenDelegate() override {}
288 void EnterFullscreenModeForTab(WebContents* web_contents,
289 const GURL& origin) override {
290 fullscreened_contents_ = web_contents;
293 void ExitFullscreenModeForTab(WebContents* web_contents) override {
294 fullscreened_contents_ = nullptr;
297 bool IsFullscreenForTabOrPending(
298 const WebContents* web_contents) const override {
299 return fullscreened_contents_ && web_contents == fullscreened_contents_;
302 private:
303 WebContents* fullscreened_contents_;
305 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate);
308 class FakeValidationMessageDelegate : public WebContentsDelegate {
309 public:
310 FakeValidationMessageDelegate()
311 : hide_validation_message_was_called_(false) {}
312 ~FakeValidationMessageDelegate() override {}
314 void HideValidationMessage(WebContents* web_contents) override {
315 hide_validation_message_was_called_ = true;
318 bool hide_validation_message_was_called() const {
319 return hide_validation_message_was_called_;
322 private:
323 bool hide_validation_message_was_called_;
325 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate);
328 } // namespace
330 // Test to make sure that title updates get stripped of whitespace.
331 TEST_F(WebContentsImplTest, UpdateTitle) {
332 NavigationControllerImpl& cont =
333 static_cast<NavigationControllerImpl&>(controller());
334 FrameHostMsg_DidCommitProvisionalLoad_Params params;
335 InitNavigateParams(&params, 0, 0, true, GURL(url::kAboutBlankURL),
336 ui::PAGE_TRANSITION_TYPED);
338 LoadCommittedDetails details;
339 cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
341 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
342 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
343 base::i18n::LEFT_TO_RIGHT);
344 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
347 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
348 const GURL kGURL("chrome://blah");
349 controller().LoadURL(
350 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
351 EXPECT_EQ(base::string16(), contents()->GetTitle());
354 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
355 const GURL kGURL("chrome://blah");
356 const base::string16 title = base::ASCIIToUTF16("My Title");
357 controller().LoadURL(
358 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
360 NavigationEntry* entry = controller().GetVisibleEntry();
361 ASSERT_EQ(kGURL, entry->GetURL());
362 entry->SetTitle(title);
364 EXPECT_EQ(title, contents()->GetTitle());
367 // Test view source mode for a webui page.
368 TEST_F(WebContentsImplTest, NTPViewSource) {
369 NavigationControllerImpl& cont =
370 static_cast<NavigationControllerImpl&>(controller());
371 const char kUrl[] = "view-source:chrome://blah";
372 const GURL kGURL(kUrl);
374 process()->sink().ClearMessages();
376 cont.LoadURL(
377 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
378 int entry_id = cont.GetPendingEntry()->GetUniqueID();
379 rvh()->GetDelegate()->RenderViewCreated(rvh());
380 // Did we get the expected message?
381 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
382 ViewMsg_EnableViewSourceMode::ID));
384 FrameHostMsg_DidCommitProvisionalLoad_Params params;
385 InitNavigateParams(&params, 0, entry_id, true, kGURL,
386 ui::PAGE_TRANSITION_TYPED);
387 LoadCommittedDetails details;
388 cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
389 // Also check title and url.
390 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
393 // Test to ensure UpdateMaxPageID is working properly.
394 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
395 SiteInstance* instance1 = contents()->GetSiteInstance();
396 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(nullptr));
398 // Starts at -1.
399 EXPECT_EQ(-1, contents()->GetMaxPageID());
400 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
401 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
403 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
404 contents()->UpdateMaxPageID(3);
405 contents()->UpdateMaxPageID(1);
406 EXPECT_EQ(3, contents()->GetMaxPageID());
407 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
408 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
410 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
411 EXPECT_EQ(3, contents()->GetMaxPageID());
412 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
413 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
416 // Test simple same-SiteInstance navigation.
417 TEST_F(WebContentsImplTest, SimpleNavigation) {
418 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
419 SiteInstance* instance1 = contents()->GetSiteInstance();
420 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
422 // Navigate to URL
423 const GURL url("http://www.google.com");
424 controller().LoadURL(
425 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
426 int entry_id = controller().GetPendingEntry()->GetUniqueID();
427 main_test_rfh()->PrepareForCommit();
428 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
429 EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
430 // Controller's pending entry will have a null site instance until we assign
431 // it in DidNavigate.
432 EXPECT_EQ(
433 nullptr,
434 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
435 site_instance());
437 // DidNavigate from the page
438 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
439 ui::PAGE_TRANSITION_TYPED);
440 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
441 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
442 EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
443 // Controller's entry should now have the SiteInstance, or else we won't be
444 // able to find it later.
445 EXPECT_EQ(
446 instance1,
447 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
448 site_instance());
451 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
452 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
453 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
454 const GURL url(std::string("http://example.org/").append(
455 GetMaxURLChars() + 1, 'a'));
457 controller().LoadURL(
458 url, Referrer(), ui::PAGE_TRANSITION_GENERATED, std::string());
459 EXPECT_EQ(nullptr, controller().GetVisibleEntry());
462 // Test that navigating across a site boundary creates a new RenderViewHost
463 // with a new SiteInstance. Going back should do the same.
464 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
465 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
466 int orig_rvh_delete_count = 0;
467 orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
468 SiteInstance* instance1 = contents()->GetSiteInstance();
470 // Navigate to URL. First URL should use first RenderViewHost.
471 const GURL url("http://www.google.com");
472 controller().LoadURL(
473 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
474 int entry_id = controller().GetPendingEntry()->GetUniqueID();
475 orig_rfh->PrepareForCommit();
476 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
477 ui::PAGE_TRANSITION_TYPED);
479 // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
480 // that orig_rfh doesn't get deleted when it gets swapped out.
481 orig_rfh->GetSiteInstance()->increment_active_frame_count();
483 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
484 EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
485 EXPECT_EQ(url, contents()->GetLastCommittedURL());
486 EXPECT_EQ(url, contents()->GetVisibleURL());
488 // Navigate to new site
489 const GURL url2("http://www.yahoo.com");
490 controller().LoadURL(
491 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
492 entry_id = controller().GetPendingEntry()->GetUniqueID();
493 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
494 switches::kEnableBrowserSideNavigation)) {
495 orig_rfh->PrepareForCommit();
497 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
498 EXPECT_EQ(url, contents()->GetLastCommittedURL());
499 EXPECT_EQ(url2, contents()->GetVisibleURL());
500 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
501 int pending_rvh_delete_count = 0;
502 pending_rfh->GetRenderViewHost()->set_delete_counter(
503 &pending_rvh_delete_count);
505 // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
506 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
507 switches::kEnableBrowserSideNavigation)) {
508 EXPECT_TRUE(pending_rfh->are_navigations_suspended());
509 orig_rfh->SendBeforeUnloadACK(true);
510 EXPECT_FALSE(pending_rfh->are_navigations_suspended());
513 // DidNavigate from the pending page
514 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
515 ui::PAGE_TRANSITION_TYPED);
516 SiteInstance* instance2 = contents()->GetSiteInstance();
518 // Keep the number of active frames in pending_rfh's SiteInstance
519 // non-zero so that orig_rfh doesn't get deleted when it gets
520 // swapped out.
521 pending_rfh->GetSiteInstance()->increment_active_frame_count();
523 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
524 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
525 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
526 EXPECT_EQ(url2, contents()->GetVisibleURL());
527 EXPECT_NE(instance1, instance2);
528 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
529 // We keep a proxy for the original RFH's SiteInstance.
530 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
531 orig_rfh->GetSiteInstance()));
532 EXPECT_EQ(orig_rvh_delete_count, 0);
534 // Going back should switch SiteInstances again. The first SiteInstance is
535 // stored in the NavigationEntry, so it should be the same as at the start.
536 // We should use the same RFH as before, swapping it back in.
537 controller().GoBack();
538 entry_id = controller().GetPendingEntry()->GetUniqueID();
539 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
540 switches::kEnableBrowserSideNavigation)) {
541 contents()->GetMainFrame()->PrepareForCommit();
543 TestRenderFrameHost* goback_rfh = contents()->GetPendingMainFrame();
544 if (!RenderFrameHostManager::IsSwappedOutStateForbidden()) {
545 // Recycling the rfh is a behavior specific to swappedout://
546 EXPECT_EQ(orig_rfh, goback_rfh);
548 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
550 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
551 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
552 switches::kEnableBrowserSideNavigation)) {
553 EXPECT_TRUE(goback_rfh->are_navigations_suspended());
554 pending_rfh->SendBeforeUnloadACK(true);
555 EXPECT_FALSE(goback_rfh->are_navigations_suspended());
558 // DidNavigate from the back action
559 contents()->TestDidNavigate(goback_rfh, 1, entry_id, false, url2,
560 ui::PAGE_TRANSITION_TYPED);
561 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
562 EXPECT_EQ(goback_rfh, contents()->GetMainFrame());
563 EXPECT_EQ(instance1, contents()->GetSiteInstance());
564 // There should be a proxy for the pending RFH SiteInstance.
565 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
566 GetRenderFrameProxyHost(pending_rfh->GetSiteInstance()));
567 EXPECT_EQ(pending_rvh_delete_count, 0);
568 pending_rfh->OnSwappedOut();
570 // Close contents and ensure RVHs are deleted.
571 DeleteContents();
572 EXPECT_EQ(orig_rvh_delete_count, 1);
573 EXPECT_EQ(pending_rvh_delete_count, 1);
576 // Test that navigating across a site boundary after a crash creates a new
577 // RFH without requiring a cross-site transition (i.e., PENDING state).
578 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
579 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
581 int orig_rvh_delete_count = 0;
582 orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
583 SiteInstance* instance1 = contents()->GetSiteInstance();
585 // Navigate to URL. First URL should use first RenderViewHost.
586 const GURL url("http://www.google.com");
587 controller().LoadURL(
588 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
589 int entry_id = controller().GetPendingEntry()->GetUniqueID();
590 contents()->GetMainFrame()->PrepareForCommit();
591 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
592 ui::PAGE_TRANSITION_TYPED);
594 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
595 EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
597 // Simulate a renderer crash.
598 EXPECT_TRUE(orig_rfh->IsRenderFrameLive());
599 orig_rfh->GetProcess()->SimulateCrash();
600 EXPECT_FALSE(orig_rfh->IsRenderFrameLive());
602 // Navigate to new site. We should not go into PENDING.
603 const GURL url2("http://www.yahoo.com");
604 controller().LoadURL(
605 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
606 entry_id = controller().GetPendingEntry()->GetUniqueID();
607 contents()->GetMainFrame()->PrepareForCommit();
608 TestRenderFrameHost* new_rfh = contents()->GetMainFrame();
609 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
610 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
611 EXPECT_NE(orig_rfh, new_rfh);
612 EXPECT_EQ(orig_rvh_delete_count, 1);
614 // DidNavigate from the new page
615 contents()->TestDidNavigate(new_rfh, 1, entry_id, true, url2,
616 ui::PAGE_TRANSITION_TYPED);
617 SiteInstance* instance2 = contents()->GetSiteInstance();
619 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
620 EXPECT_EQ(new_rfh, main_rfh());
621 EXPECT_NE(instance1, instance2);
622 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
624 // Close contents and ensure RVHs are deleted.
625 DeleteContents();
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
631 // SiteInstance.
632 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
633 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
634 SiteInstance* instance1 = contents()->GetSiteInstance();
636 // Navigate to URL. First URL should use first RenderViewHost.
637 const GURL url("http://www.google.com");
638 controller().LoadURL(
639 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
640 int entry_id = controller().GetPendingEntry()->GetUniqueID();
641 contents()->GetMainFrame()->PrepareForCommit();
642 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
643 ui::PAGE_TRANSITION_TYPED);
645 // Open a new contents with the same SiteInstance, navigated to the same site.
646 scoped_ptr<TestWebContents> contents2(
647 TestWebContents::Create(browser_context(), instance1));
648 contents2->GetController().LoadURL(url, Referrer(),
649 ui::PAGE_TRANSITION_TYPED,
650 std::string());
651 entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
652 contents2->GetMainFrame()->PrepareForCommit();
653 // Need this page id to be 2 since the site instance is the same (which is the
654 // scope of page IDs) and we want to consider this a new page.
655 contents2->TestDidNavigate(contents2->GetMainFrame(), 2, entry_id, true, url,
656 ui::PAGE_TRANSITION_TYPED);
658 // Navigate first contents to a new site.
659 const GURL url2a("http://www.yahoo.com");
660 controller().LoadURL(
661 url2a, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
662 entry_id = controller().GetPendingEntry()->GetUniqueID();
663 orig_rfh->PrepareForCommit();
664 TestRenderFrameHost* pending_rfh_a = contents()->GetPendingMainFrame();
665 contents()->TestDidNavigate(pending_rfh_a, 1, entry_id, true, url2a,
666 ui::PAGE_TRANSITION_TYPED);
667 SiteInstance* instance2a = contents()->GetSiteInstance();
668 EXPECT_NE(instance1, instance2a);
670 // Navigate second contents to the same site as the first tab.
671 const GURL url2b("http://mail.yahoo.com");
672 contents2->GetController().LoadURL(url2b, Referrer(),
673 ui::PAGE_TRANSITION_TYPED,
674 std::string());
675 entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
676 TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
677 rfh2->PrepareForCommit();
678 TestRenderFrameHost* pending_rfh_b = contents2->GetPendingMainFrame();
679 EXPECT_NE(nullptr, pending_rfh_b);
680 EXPECT_TRUE(contents2->CrossProcessNavigationPending());
682 // NOTE(creis): We used to be in danger of showing a crash page here if the
683 // second contents hadn't navigated somewhere first (bug 1145430). That case
684 // is now covered by the CrossSiteBoundariesAfterCrash test.
685 contents2->TestDidNavigate(pending_rfh_b, 2, entry_id, true, url2b,
686 ui::PAGE_TRANSITION_TYPED);
687 SiteInstance* instance2b = contents2->GetSiteInstance();
688 EXPECT_NE(instance1, instance2b);
690 // Both contentses should now be in the same SiteInstance.
691 EXPECT_EQ(instance2a, instance2b);
694 // The embedder can request sites for certain urls not be be assigned to the
695 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
696 // allowing to reuse the renderer backing certain chrome urls for subsequent
697 // navigation. The test verifies that the override is honored.
698 TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
699 WebContentsImplTestBrowserClient browser_client;
700 SetBrowserClientForTesting(&browser_client);
702 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
703 int orig_rvh_delete_count = 0;
704 orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
705 SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
707 browser_client.set_assign_site_for_url(false);
708 // Navigate to an URL that will not assign a new SiteInstance.
709 const GURL native_url("non-site-url://stuffandthings");
710 controller().LoadURL(
711 native_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
712 int entry_id = controller().GetPendingEntry()->GetUniqueID();
713 contents()->GetMainFrame()->PrepareForCommit();
714 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, native_url,
715 ui::PAGE_TRANSITION_TYPED);
717 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
718 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
719 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
720 EXPECT_EQ(native_url, contents()->GetVisibleURL());
721 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
722 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
723 EXPECT_FALSE(orig_instance->HasSite());
725 browser_client.set_assign_site_for_url(true);
726 // Navigate to new site (should keep same site instance).
727 const GURL url("http://www.google.com");
728 controller().LoadURL(
729 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
730 entry_id = controller().GetPendingEntry()->GetUniqueID();
731 contents()->GetMainFrame()->PrepareForCommit();
732 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
733 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
734 EXPECT_EQ(url, contents()->GetVisibleURL());
735 EXPECT_FALSE(contents()->GetPendingMainFrame());
736 contents()->TestDidNavigate(orig_rfh, 2, entry_id, true, url,
737 ui::PAGE_TRANSITION_TYPED);
739 // Keep the number of active frames in orig_rfh's SiteInstance
740 // non-zero so that orig_rfh doesn't get deleted when it gets
741 // swapped out.
742 orig_rfh->GetSiteInstance()->increment_active_frame_count();
744 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
745 EXPECT_TRUE(
746 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
747 EXPECT_EQ(url, contents()->GetLastCommittedURL());
749 // Navigate to another new site (should create a new site instance).
750 const GURL url2("http://www.yahoo.com");
751 controller().LoadURL(
752 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
753 entry_id = controller().GetPendingEntry()->GetUniqueID();
754 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
755 switches::kEnableBrowserSideNavigation)) {
756 orig_rfh->PrepareForCommit();
758 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
759 EXPECT_EQ(url, contents()->GetLastCommittedURL());
760 EXPECT_EQ(url2, contents()->GetVisibleURL());
761 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
762 int pending_rvh_delete_count = 0;
763 pending_rfh->GetRenderViewHost()->set_delete_counter(
764 &pending_rvh_delete_count);
766 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
767 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
768 switches::kEnableBrowserSideNavigation)) {
769 EXPECT_TRUE(pending_rfh->are_navigations_suspended());
770 orig_rfh->SendBeforeUnloadACK(true);
771 EXPECT_FALSE(pending_rfh->are_navigations_suspended());
774 // DidNavigate from the pending page.
775 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
776 ui::PAGE_TRANSITION_TYPED);
777 SiteInstance* new_instance = contents()->GetSiteInstance();
779 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
780 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
781 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
782 EXPECT_EQ(url2, contents()->GetVisibleURL());
783 EXPECT_NE(new_instance, orig_instance);
784 EXPECT_FALSE(contents()->GetPendingMainFrame());
785 // We keep a proxy for the original RFH's SiteInstance.
786 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
787 orig_rfh->GetSiteInstance()));
788 EXPECT_EQ(orig_rvh_delete_count, 0);
789 orig_rfh->OnSwappedOut();
791 // Close contents and ensure RVHs are deleted.
792 DeleteContents();
793 EXPECT_EQ(orig_rvh_delete_count, 1);
794 EXPECT_EQ(pending_rvh_delete_count, 1);
797 // Regression test for http://crbug.com/386542 - variation of
798 // NavigateFromSitelessUrl in which the original navigation is a session
799 // restore.
800 TEST_F(WebContentsImplTest, NavigateFromRestoredSitelessUrl) {
801 WebContentsImplTestBrowserClient browser_client;
802 SetBrowserClientForTesting(&browser_client);
803 SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
804 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
806 // Restore a navigation entry for URL that should not assign site to the
807 // SiteInstance.
808 browser_client.set_assign_site_for_url(false);
809 const GURL native_url("non-site-url://stuffandthings");
810 ScopedVector<NavigationEntry> entries;
811 scoped_ptr<NavigationEntry> new_entry =
812 NavigationControllerImpl::CreateNavigationEntry(
813 native_url, Referrer(), ui::PAGE_TRANSITION_LINK, false,
814 std::string(), browser_context());
815 new_entry->SetPageID(0);
816 entries.push_back(new_entry.Pass());
817 controller().Restore(
819 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
820 &entries);
821 ASSERT_EQ(0u, entries.size());
822 ASSERT_EQ(1, controller().GetEntryCount());
824 controller().GoToIndex(0);
825 NavigationEntry* entry = controller().GetPendingEntry();
826 orig_rfh->PrepareForCommit();
827 contents()->TestDidNavigate(orig_rfh, 0, entry->GetUniqueID(), false,
828 native_url, ui::PAGE_TRANSITION_RELOAD);
829 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
830 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
831 EXPECT_FALSE(orig_instance->HasSite());
833 // Navigate to a regular site and verify that the SiteInstance was kept.
834 browser_client.set_assign_site_for_url(true);
835 const GURL url("http://www.google.com");
836 controller().LoadURL(
837 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
838 entry = controller().GetPendingEntry();
839 orig_rfh->PrepareForCommit();
840 contents()->TestDidNavigate(orig_rfh, 2, entry->GetUniqueID(), true, url,
841 ui::PAGE_TRANSITION_TYPED);
842 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
844 // Cleanup.
845 DeleteContents();
848 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
849 // tab is restored, the SiteInstance will change upon navigation.
850 TEST_F(WebContentsImplTest, NavigateFromRestoredRegularUrl) {
851 WebContentsImplTestBrowserClient browser_client;
852 SetBrowserClientForTesting(&browser_client);
853 SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
854 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
856 // Restore a navigation entry for a regular URL ensuring that the embedder
857 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
858 browser_client.set_assign_site_for_url(true);
859 const GURL regular_url("http://www.yahoo.com");
860 ScopedVector<NavigationEntry> entries;
861 scoped_ptr<NavigationEntry> new_entry =
862 NavigationControllerImpl::CreateNavigationEntry(
863 regular_url, Referrer(), ui::PAGE_TRANSITION_LINK, false,
864 std::string(), browser_context());
865 new_entry->SetPageID(0);
866 entries.push_back(new_entry.Pass());
867 controller().Restore(
869 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
870 &entries);
871 ASSERT_EQ(0u, entries.size());
873 ASSERT_EQ(1, controller().GetEntryCount());
874 controller().GoToIndex(0);
875 NavigationEntry* entry = controller().GetPendingEntry();
876 orig_rfh->PrepareForCommit();
877 contents()->TestDidNavigate(orig_rfh, 0, entry->GetUniqueID(), false,
878 regular_url, ui::PAGE_TRANSITION_RELOAD);
879 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
880 EXPECT_TRUE(orig_instance->HasSite());
882 // Navigate to another site and verify that a new SiteInstance was created.
883 const GURL url("http://www.google.com");
884 controller().LoadURL(
885 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
886 entry = controller().GetPendingEntry();
887 orig_rfh->PrepareForCommit();
888 contents()->TestDidNavigate(contents()->GetPendingMainFrame(), 2,
889 entry->GetUniqueID(), true, url,
890 ui::PAGE_TRANSITION_TYPED);
891 EXPECT_NE(orig_instance, contents()->GetSiteInstance());
893 // Cleanup.
894 DeleteContents();
897 // Test that we can find an opener RVH even if it's pending.
898 // http://crbug.com/176252.
899 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
900 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
902 // Navigate to a URL.
903 const GURL url("http://www.google.com");
904 controller().LoadURL(
905 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
906 int entry_id = controller().GetPendingEntry()->GetUniqueID();
907 orig_rfh->PrepareForCommit();
908 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
909 ui::PAGE_TRANSITION_TYPED);
911 // Start to navigate first tab to a new site, so that it has a pending RVH.
912 const GURL url2("http://www.yahoo.com");
913 controller().LoadURL(
914 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
915 orig_rfh->PrepareForCommit();
916 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
917 SiteInstance* instance = pending_rfh->GetSiteInstance();
919 // While it is still pending, simulate opening a new tab with the first tab
920 // as its opener. This will call CreateOpenerProxies on the opener to ensure
921 // that an RVH exists.
922 scoped_ptr<TestWebContents> popup(
923 TestWebContents::Create(browser_context(), instance));
924 popup->SetOpener(contents());
925 contents()->GetRenderManager()->CreateOpenerProxies(instance);
927 // If swapped out is forbidden, a new proxy should be created for the opener
928 // in |instance|, and we should ensure that its routing ID is returned here.
929 // Otherwise, we should find the pending RFH and not create a new proxy.
930 int opener_frame_routing_id =
931 popup->GetRenderManager()->GetOpenerRoutingID(instance);
932 RenderFrameProxyHost* proxy =
933 contents()->GetRenderManager()->GetRenderFrameProxyHost(instance);
934 if (RenderFrameHostManager::IsSwappedOutStateForbidden()) {
935 EXPECT_TRUE(proxy);
936 EXPECT_EQ(proxy->GetRoutingID(), opener_frame_routing_id);
938 // Ensure that committing the navigation removes the proxy.
939 int entry_id = controller().GetPendingEntry()->GetUniqueID();
940 contents()->TestDidNavigate(pending_rfh, 2, entry_id, true, url2,
941 ui::PAGE_TRANSITION_TYPED);
942 EXPECT_FALSE(
943 contents()->GetRenderManager()->GetRenderFrameProxyHost(instance));
944 } else {
945 EXPECT_FALSE(proxy);
946 EXPECT_EQ(pending_rfh->GetRoutingID(), opener_frame_routing_id);
950 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
951 // to determine whether a navigation is cross-site.
952 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
953 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
954 SiteInstance* instance1 = contents()->GetSiteInstance();
956 // Navigate to URL.
957 const GURL url("http://www.google.com");
958 controller().LoadURL(
959 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
960 int entry_id = controller().GetPendingEntry()->GetUniqueID();
961 contents()->GetMainFrame()->PrepareForCommit();
962 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
963 ui::PAGE_TRANSITION_TYPED);
965 // Open a related contents to a second site.
966 scoped_ptr<TestWebContents> contents2(
967 TestWebContents::Create(browser_context(), instance1));
968 const GURL url2("http://www.yahoo.com");
969 contents2->GetController().LoadURL(url2, Referrer(),
970 ui::PAGE_TRANSITION_TYPED,
971 std::string());
972 entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
973 contents2->GetMainFrame()->PrepareForCommit();
975 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
976 // pending.
977 TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
978 EXPECT_FALSE(contents2->CrossProcessNavigationPending());
979 contents2->TestDidNavigate(rfh2, 2, entry_id, true, url2,
980 ui::PAGE_TRANSITION_TYPED);
981 SiteInstance* instance2 = contents2->GetSiteInstance();
982 EXPECT_NE(instance1, instance2);
983 EXPECT_FALSE(contents2->CrossProcessNavigationPending());
985 // Simulate a link click in first contents to second site. Doesn't switch
986 // SiteInstances, because we don't intercept Blink navigations.
987 orig_rfh->SendRendererInitiatedNavigationRequest(url2, true);
988 orig_rfh->PrepareForCommit();
989 contents()->TestDidNavigate(orig_rfh, 2, 0, true, url2,
990 ui::PAGE_TRANSITION_TYPED);
991 SiteInstance* instance3 = contents()->GetSiteInstance();
992 EXPECT_EQ(instance1, instance3);
993 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
995 // Navigate to the new site. Doesn't switch SiteInstancees, because we
996 // compare against the current URL, not the SiteInstance's site.
997 const GURL url3("http://mail.yahoo.com");
998 controller().LoadURL(
999 url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1000 entry_id = controller().GetPendingEntry()->GetUniqueID();
1001 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1002 contents()->GetMainFrame()->PrepareForCommit();
1003 contents()->TestDidNavigate(orig_rfh, 3, entry_id, true, url3,
1004 ui::PAGE_TRANSITION_TYPED);
1005 SiteInstance* instance4 = contents()->GetSiteInstance();
1006 EXPECT_EQ(instance1, instance4);
1009 // Test that the onbeforeunload and onunload handlers run when navigating
1010 // across site boundaries.
1011 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
1012 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1013 SiteInstance* instance1 = contents()->GetSiteInstance();
1015 // Navigate to URL. First URL should use first RenderViewHost.
1016 const GURL url("http://www.google.com");
1017 controller().LoadURL(
1018 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1019 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1020 contents()->GetMainFrame()->PrepareForCommit();
1021 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1022 ui::PAGE_TRANSITION_TYPED);
1023 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1024 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1026 // Navigate to new site, but simulate an onbeforeunload denial.
1027 const GURL url2("http://www.yahoo.com");
1028 controller().LoadURL(
1029 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1030 EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
1031 base::TimeTicks now = base::TimeTicks::Now();
1032 orig_rfh->OnMessageReceived(
1033 FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
1034 EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
1035 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1036 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1038 // Navigate again, but simulate an onbeforeunload approval.
1039 controller().LoadURL(
1040 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1041 entry_id = controller().GetPendingEntry()->GetUniqueID();
1042 EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
1043 now = base::TimeTicks::Now();
1044 orig_rfh->PrepareForCommit();
1045 EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
1046 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1047 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
1049 // We won't hear DidNavigate until the onunload handler has finished running.
1051 // DidNavigate from the pending page.
1052 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
1053 ui::PAGE_TRANSITION_TYPED);
1054 SiteInstance* instance2 = contents()->GetSiteInstance();
1055 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1056 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
1057 EXPECT_NE(instance1, instance2);
1058 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1061 // Test that during a slow cross-site navigation, the original renderer can
1062 // navigate to a different URL and have it displayed, canceling the slow
1063 // navigation.
1064 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
1065 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1066 SiteInstance* instance1 = contents()->GetSiteInstance();
1068 // Navigate to URL. First URL should use first RenderFrameHost.
1069 const GURL url("http://www.google.com");
1070 controller().LoadURL(
1071 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1072 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1073 contents()->GetMainFrame()->PrepareForCommit();
1074 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1075 ui::PAGE_TRANSITION_TYPED);
1076 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1077 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1079 // Navigate to new site, simulating an onbeforeunload approval.
1080 const GURL url2("http://www.yahoo.com");
1081 controller().LoadURL(
1082 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1083 EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
1084 orig_rfh->PrepareForCommit();
1085 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1087 // Suppose the original renderer navigates before the new one is ready.
1088 orig_rfh->SendNavigate(2, 0, true, GURL("http://www.google.com/foo"));
1090 // Verify that the pending navigation is cancelled.
1091 EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
1092 SiteInstance* instance2 = contents()->GetSiteInstance();
1093 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1094 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1095 EXPECT_EQ(instance1, instance2);
1096 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1099 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
1100 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1101 const GURL url1("chrome://gpu");
1102 controller().LoadURL(
1103 url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1104 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1105 TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
1106 ntp_rfh->PrepareForCommit();
1107 contents()->TestDidNavigate(ntp_rfh, 1, entry_id, true, url1,
1108 ui::PAGE_TRANSITION_TYPED);
1109 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
1110 SiteInstance* instance1 = contents()->GetSiteInstance();
1112 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1113 EXPECT_EQ(ntp_rfh, contents()->GetMainFrame());
1114 EXPECT_EQ(url1, entry1->GetURL());
1115 EXPECT_EQ(instance1,
1116 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1117 EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->GetEnabledBindings() &
1118 BINDINGS_POLICY_WEB_UI);
1120 // Navigate to new site.
1121 const GURL url2("http://www.google.com");
1122 controller().LoadURL(
1123 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1124 entry_id = controller().GetPendingEntry()->GetUniqueID();
1125 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1126 TestRenderFrameHost* google_rfh = contents()->GetPendingMainFrame();
1128 // Simulate beforeunload approval.
1129 EXPECT_TRUE(ntp_rfh->is_waiting_for_beforeunload_ack());
1130 base::TimeTicks now = base::TimeTicks::Now();
1131 ntp_rfh->PrepareForCommit();
1133 // DidNavigate from the pending page.
1134 contents()->TestDidNavigate(google_rfh, 1, entry_id, true, url2,
1135 ui::PAGE_TRANSITION_TYPED);
1136 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
1137 SiteInstance* instance2 = contents()->GetSiteInstance();
1139 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1140 EXPECT_EQ(google_rfh, contents()->GetMainFrame());
1141 EXPECT_NE(instance1, instance2);
1142 EXPECT_FALSE(contents()->GetPendingMainFrame());
1143 EXPECT_EQ(url2, entry2->GetURL());
1144 EXPECT_EQ(instance2,
1145 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1146 EXPECT_FALSE(google_rfh->GetRenderViewHost()->GetEnabledBindings() &
1147 BINDINGS_POLICY_WEB_UI);
1149 // Navigate to third page on same site.
1150 const GURL url3("http://news.google.com");
1151 controller().LoadURL(
1152 url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1153 entry_id = controller().GetPendingEntry()->GetUniqueID();
1154 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1155 contents()->GetMainFrame()->PrepareForCommit();
1156 contents()->TestDidNavigate(google_rfh, 2, entry_id, true, url3,
1157 ui::PAGE_TRANSITION_TYPED);
1158 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
1159 SiteInstance* instance3 = contents()->GetSiteInstance();
1161 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1162 EXPECT_EQ(google_rfh, contents()->GetMainFrame());
1163 EXPECT_EQ(instance2, instance3);
1164 EXPECT_FALSE(contents()->GetPendingMainFrame());
1165 EXPECT_EQ(url3, entry3->GetURL());
1166 EXPECT_EQ(instance3,
1167 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1169 // Go back within the site.
1170 controller().GoBack();
1171 NavigationEntry* goback_entry = controller().GetPendingEntry();
1172 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1173 EXPECT_EQ(entry2, controller().GetPendingEntry());
1175 // Before that commits, go back again.
1176 controller().GoBack();
1177 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1178 EXPECT_TRUE(contents()->GetPendingMainFrame());
1179 EXPECT_EQ(entry1, controller().GetPendingEntry());
1181 // Simulate beforeunload approval.
1182 EXPECT_TRUE(google_rfh->is_waiting_for_beforeunload_ack());
1183 now = base::TimeTicks::Now();
1184 google_rfh->PrepareForCommit();
1185 google_rfh->OnMessageReceived(
1186 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1188 // DidNavigate from the first back. This aborts the second back's pending RFH.
1189 contents()->TestDidNavigate(google_rfh, 1, goback_entry->GetUniqueID(), false,
1190 url2, ui::PAGE_TRANSITION_TYPED);
1192 // We should commit this page and forget about the second back.
1193 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1194 EXPECT_FALSE(controller().GetPendingEntry());
1195 EXPECT_EQ(google_rfh, contents()->GetMainFrame());
1196 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
1198 // We should not have corrupted the NTP entry.
1199 EXPECT_EQ(instance3,
1200 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1201 EXPECT_EQ(instance2,
1202 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1203 EXPECT_EQ(instance1,
1204 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1205 EXPECT_EQ(url1, entry1->GetURL());
1208 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1209 // original renderer will not cancel the slow navigation (bug 42029).
1210 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
1211 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1213 // Navigate to URL. First URL should use the original RenderFrameHost.
1214 const GURL url("http://www.google.com");
1215 controller().LoadURL(
1216 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1217 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1218 contents()->GetMainFrame()->PrepareForCommit();
1219 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1220 ui::PAGE_TRANSITION_TYPED);
1221 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1222 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1224 // Start navigating to new site.
1225 const GURL url2("http://www.yahoo.com");
1226 controller().LoadURL(
1227 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1229 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1230 // waiting for a before unload response.
1231 TestRenderFrameHost* child_rfh = orig_rfh->AppendChild("subframe");
1232 child_rfh->SendNavigateWithTransition(1, 0, false,
1233 GURL("http://google.com/frame"),
1234 ui::PAGE_TRANSITION_AUTO_SUBFRAME);
1235 EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
1237 // Now simulate the onbeforeunload approval and verify the navigation is
1238 // not canceled.
1239 orig_rfh->PrepareForCommit();
1240 EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
1241 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1244 namespace {
1245 void SetAsNonUserGesture(FrameHostMsg_DidCommitProvisionalLoad_Params* params) {
1246 params->gesture = NavigationGestureAuto;
1250 // Test that a cross-site navigation is not preempted if the previous
1251 // renderer sends a FrameNavigate message just before being told to stop.
1252 // We should only preempt the cross-site navigation if the previous renderer
1253 // has started a new navigation. See http://crbug.com/79176.
1254 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1255 // Navigate to WebUI URL.
1256 const GURL url("chrome://gpu");
1257 controller().LoadURL(
1258 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1259 int entry1_id = controller().GetPendingEntry()->GetUniqueID();
1260 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1261 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1263 // Navigate to new site, with the beforeunload request in flight.
1264 const GURL url2("http://www.yahoo.com");
1265 controller().LoadURL(
1266 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1267 int entry2_id = controller().GetPendingEntry()->GetUniqueID();
1268 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
1269 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1270 EXPECT_TRUE(orig_rfh->is_waiting_for_beforeunload_ack());
1271 EXPECT_NE(orig_rfh, pending_rfh);
1273 // Suppose the first navigation tries to commit now, with a
1274 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1275 // but it should act as if the beforeunload ack arrived.
1276 orig_rfh->SendNavigateWithModificationCallback(
1277 1, entry1_id, true, url, base::Bind(SetAsNonUserGesture));
1278 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1279 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1280 EXPECT_FALSE(orig_rfh->is_waiting_for_beforeunload_ack());
1281 // It should commit.
1282 ASSERT_EQ(1, controller().GetEntryCount());
1283 EXPECT_EQ(url, controller().GetLastCommittedEntry()->GetURL());
1285 // The pending navigation should be able to commit successfully.
1286 contents()->TestDidNavigate(pending_rfh, 1, entry2_id, true, url2,
1287 ui::PAGE_TRANSITION_TYPED);
1288 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1289 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
1290 EXPECT_EQ(2, controller().GetEntryCount());
1293 // Test that NavigationEntries have the correct page state after going
1294 // forward and back. Prevents regression for bug 1116137.
1295 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1296 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1298 // Navigate to URL. There should be no committed entry yet.
1299 const GURL url("http://www.google.com");
1300 controller().LoadURL(
1301 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1302 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1303 NavigationEntry* entry = controller().GetLastCommittedEntry();
1304 EXPECT_EQ(nullptr, entry);
1306 // Committed entry should have page state after DidNavigate.
1307 orig_rfh->PrepareForCommit();
1308 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1309 ui::PAGE_TRANSITION_TYPED);
1310 entry = controller().GetLastCommittedEntry();
1311 EXPECT_TRUE(entry->GetPageState().IsValid());
1313 // Navigate to same site.
1314 const GURL url2("http://images.google.com");
1315 controller().LoadURL(
1316 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1317 entry_id = controller().GetPendingEntry()->GetUniqueID();
1318 entry = controller().GetLastCommittedEntry();
1319 EXPECT_TRUE(entry->GetPageState().IsValid());
1321 // Committed entry should have page state after DidNavigate.
1322 orig_rfh->PrepareForCommit();
1323 contents()->TestDidNavigate(orig_rfh, 2, entry_id, true, url2,
1324 ui::PAGE_TRANSITION_TYPED);
1325 entry = controller().GetLastCommittedEntry();
1326 EXPECT_TRUE(entry->GetPageState().IsValid());
1328 // Now go back. Committed entry should still have page state.
1329 controller().GoBack();
1330 entry_id = controller().GetPendingEntry()->GetUniqueID();
1331 orig_rfh->PrepareForCommit();
1332 contents()->TestDidNavigate(orig_rfh, 1, entry_id, false, url,
1333 ui::PAGE_TRANSITION_TYPED);
1334 entry = controller().GetLastCommittedEntry();
1335 EXPECT_TRUE(entry->GetPageState().IsValid());
1338 // Test that NavigationEntries have the correct page state and SiteInstance
1339 // state after opening a new window to about:blank. Prevents regression for
1340 // bugs b/1116137 and http://crbug.com/111975.
1341 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1342 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1344 // Navigate to about:blank.
1345 const GURL url(url::kAboutBlankURL);
1346 orig_rfh->SendRendererInitiatedNavigationRequest(url, false);
1347 contents()->TestDidNavigate(orig_rfh, 1, 0, true, url,
1348 ui::PAGE_TRANSITION_TYPED);
1350 // Should have a page state here.
1351 NavigationEntry* entry = controller().GetLastCommittedEntry();
1352 EXPECT_TRUE(entry->GetPageState().IsValid());
1354 // The SiteInstance should be available for other navigations to use.
1355 NavigationEntryImpl* entry_impl =
1356 NavigationEntryImpl::FromNavigationEntry(entry);
1357 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1358 int32 site_instance_id = entry_impl->site_instance()->GetId();
1360 // Navigating to a normal page should not cause a process swap.
1361 const GURL new_url("http://www.google.com");
1362 controller().LoadURL(new_url, Referrer(),
1363 ui::PAGE_TRANSITION_TYPED, std::string());
1364 entry = controller().GetPendingEntry();
1365 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1366 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1367 orig_rfh->PrepareForCommit();
1368 contents()->TestDidNavigate(orig_rfh, 2, entry->GetUniqueID(), true, new_url,
1369 ui::PAGE_TRANSITION_TYPED);
1370 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1371 controller().GetLastCommittedEntry());
1372 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1373 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1376 // Tests that fullscreen is exited throughout the object hierarchy when
1377 // navigating to a new page.
1378 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
1379 FakeFullscreenDelegate fake_delegate;
1380 contents()->SetDelegate(&fake_delegate);
1381 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1382 TestRenderViewHost* orig_rvh = orig_rfh->GetRenderViewHost();
1384 // Navigate to a site.
1385 const GURL url("http://www.google.com");
1386 controller().LoadURL(
1387 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1388 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1389 contents()->GetMainFrame()->PrepareForCommit();
1390 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1391 ui::PAGE_TRANSITION_TYPED);
1392 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1394 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1395 EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
1396 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1397 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1398 orig_rfh->OnMessageReceived(
1399 FrameHostMsg_ToggleFullscreen(orig_rfh->GetRoutingID(), true));
1400 EXPECT_TRUE(orig_rvh->IsFullscreenGranted());
1401 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1402 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1404 // Navigate to a new site.
1405 const GURL url2("http://www.yahoo.com");
1406 controller().LoadURL(
1407 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1408 entry_id = controller().GetPendingEntry()->GetUniqueID();
1409 contents()->GetMainFrame()->PrepareForCommit();
1410 TestRenderFrameHost* const pending_rfh = contents()->GetPendingMainFrame();
1411 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
1412 ui::PAGE_TRANSITION_TYPED);
1414 // Confirm fullscreen has exited.
1415 EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
1416 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1417 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1419 contents()->SetDelegate(nullptr);
1422 // Tests that fullscreen is exited throughout the object hierarchy when
1423 // instructing NavigationController to GoBack() or GoForward().
1424 TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
1425 FakeFullscreenDelegate fake_delegate;
1426 contents()->SetDelegate(&fake_delegate);
1427 TestRenderFrameHost* const orig_rfh = contents()->GetMainFrame();
1428 TestRenderViewHost* const orig_rvh = orig_rfh->GetRenderViewHost();
1430 // Navigate to a site.
1431 const GURL url("http://www.google.com");
1432 controller().LoadURL(
1433 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1434 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1435 orig_rfh->PrepareForCommit();
1436 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1437 ui::PAGE_TRANSITION_TYPED);
1438 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1440 // Now, navigate to another page on the same site.
1441 const GURL url2("http://www.google.com/search?q=kittens");
1442 controller().LoadURL(
1443 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1444 entry_id = controller().GetPendingEntry()->GetUniqueID();
1445 orig_rfh->PrepareForCommit();
1446 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1447 contents()->TestDidNavigate(orig_rfh, 2, entry_id, true, url2,
1448 ui::PAGE_TRANSITION_TYPED);
1449 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1451 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1452 EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
1453 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1454 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1456 for (int i = 0; i < 2; ++i) {
1457 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1458 orig_rfh->OnMessageReceived(
1459 FrameHostMsg_ToggleFullscreen(orig_rfh->GetRoutingID(), true));
1460 EXPECT_TRUE(orig_rvh->IsFullscreenGranted());
1461 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1462 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1464 // Navigate backward (or forward).
1465 if (i == 0)
1466 controller().GoBack();
1467 else
1468 controller().GoForward();
1469 entry_id = controller().GetPendingEntry()->GetUniqueID();
1470 orig_rfh->PrepareForCommit();
1471 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1472 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1473 contents()->TestDidNavigate(orig_rfh, i + 1, entry_id, false, url,
1474 ui::PAGE_TRANSITION_FORWARD_BACK);
1476 // Confirm fullscreen has exited.
1477 EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
1478 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1479 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1482 contents()->SetDelegate(nullptr);
1485 TEST_F(WebContentsImplTest, TerminateHidesValidationMessage) {
1486 FakeValidationMessageDelegate fake_delegate;
1487 contents()->SetDelegate(&fake_delegate);
1488 EXPECT_FALSE(fake_delegate.hide_validation_message_was_called());
1490 // Initialize the RenderFrame and then simulate crashing the renderer
1491 // process.
1492 contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
1493 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1495 // Confirm HideValidationMessage was called.
1496 EXPECT_TRUE(fake_delegate.hide_validation_message_was_called());
1498 contents()->SetDelegate(nullptr);
1501 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1502 // crash.
1503 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
1504 FakeFullscreenDelegate fake_delegate;
1505 contents()->SetDelegate(&fake_delegate);
1507 // Navigate to a site.
1508 const GURL url("http://www.google.com");
1509 controller().LoadURL(
1510 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1511 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1512 main_test_rfh()->PrepareForCommit();
1513 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id, true,
1514 url, ui::PAGE_TRANSITION_TYPED);
1516 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1517 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1518 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1519 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1520 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1521 contents()->GetMainFrame()->GetRoutingID(), true));
1522 EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
1523 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1524 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1526 // Crash the renderer.
1527 main_test_rfh()->GetProcess()->SimulateCrash();
1529 // Confirm fullscreen has exited.
1530 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1531 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1532 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1534 contents()->SetDelegate(nullptr);
1537 ////////////////////////////////////////////////////////////////////////////////
1538 // Interstitial Tests
1539 ////////////////////////////////////////////////////////////////////////////////
1541 // Test navigating to a page (with the navigation initiated from the browser,
1542 // as when a URL is typed in the location bar) that shows an interstitial and
1543 // creates a new navigation entry, then hiding it without proceeding.
1544 TEST_F(WebContentsImplTest,
1545 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1546 // Navigate to a page.
1547 GURL url1("http://www.google.com");
1548 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1549 EXPECT_EQ(1, controller().GetEntryCount());
1551 // Initiate a browser navigation that will trigger the interstitial.
1552 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1553 ui::PAGE_TRANSITION_TYPED, std::string());
1554 NavigationEntry* entry = controller().GetPendingEntry();
1556 // Show an interstitial.
1557 TestInterstitialPage::InterstitialState state =
1558 TestInterstitialPage::INVALID;
1559 bool deleted = false;
1560 GURL url2("http://interstitial");
1561 TestInterstitialPage* interstitial =
1562 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1563 TestInterstitialPageStateGuard state_guard(interstitial);
1564 interstitial->Show();
1565 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1566 // The interstitial should not show until its navigation has committed.
1567 EXPECT_FALSE(interstitial->is_showing());
1568 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1569 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1570 // Let's commit the interstitial navigation.
1571 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
1572 EXPECT_TRUE(interstitial->is_showing());
1573 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1574 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1575 entry = controller().GetVisibleEntry();
1576 ASSERT_NE(nullptr, entry);
1577 EXPECT_TRUE(entry->GetURL() == url2);
1579 // Now don't proceed.
1580 interstitial->DontProceed();
1581 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1582 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1583 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1584 entry = controller().GetVisibleEntry();
1585 ASSERT_NE(nullptr, entry);
1586 EXPECT_TRUE(entry->GetURL() == url1);
1587 EXPECT_EQ(1, controller().GetEntryCount());
1589 RunAllPendingInMessageLoop();
1590 EXPECT_TRUE(deleted);
1593 // Test navigating to a page (with the navigation initiated from the renderer,
1594 // as when clicking on a link in the page) that shows an interstitial and
1595 // creates a new navigation entry, then hiding it without proceeding.
1596 TEST_F(WebContentsImplTest,
1597 ShowInterstitialFromRendererWithNewNavigationDontProceed) {
1598 // Navigate to a page.
1599 GURL url1("http://www.google.com");
1600 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1601 EXPECT_EQ(1, controller().GetEntryCount());
1603 // Show an interstitial (no pending entry, the interstitial would have been
1604 // triggered by clicking on a link).
1605 TestInterstitialPage::InterstitialState state =
1606 TestInterstitialPage::INVALID;
1607 bool deleted = false;
1608 GURL url2("http://interstitial");
1609 TestInterstitialPage* interstitial =
1610 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1611 TestInterstitialPageStateGuard state_guard(interstitial);
1612 interstitial->Show();
1613 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1614 // The interstitial should not show until its navigation has committed.
1615 EXPECT_FALSE(interstitial->is_showing());
1616 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1617 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1618 // Let's commit the interstitial navigation.
1619 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
1620 EXPECT_TRUE(interstitial->is_showing());
1621 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1622 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1623 NavigationEntry* entry = controller().GetVisibleEntry();
1624 ASSERT_NE(nullptr, entry);
1625 EXPECT_TRUE(entry->GetURL() == url2);
1627 // Now don't proceed.
1628 interstitial->DontProceed();
1629 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1630 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1631 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1632 entry = controller().GetVisibleEntry();
1633 ASSERT_NE(nullptr, entry);
1634 EXPECT_TRUE(entry->GetURL() == url1);
1635 EXPECT_EQ(1, controller().GetEntryCount());
1637 RunAllPendingInMessageLoop();
1638 EXPECT_TRUE(deleted);
1641 // Test navigating to a page that shows an interstitial without creating a new
1642 // navigation entry (this happens when the interstitial is triggered by a
1643 // sub-resource in the page), then hiding it without proceeding.
1644 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1645 // Navigate to a page.
1646 GURL url1("http://www.google.com");
1647 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1648 EXPECT_EQ(1, controller().GetEntryCount());
1650 // Show an interstitial.
1651 TestInterstitialPage::InterstitialState state =
1652 TestInterstitialPage::INVALID;
1653 bool deleted = false;
1654 GURL url2("http://interstitial");
1655 TestInterstitialPage* interstitial =
1656 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1657 TestInterstitialPageStateGuard state_guard(interstitial);
1658 interstitial->Show();
1659 // The interstitial should not show until its navigation has committed.
1660 EXPECT_FALSE(interstitial->is_showing());
1661 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1662 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1663 // Let's commit the interstitial navigation.
1664 interstitial->TestDidNavigate(1, 0, true, url2);
1665 EXPECT_TRUE(interstitial->is_showing());
1666 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1667 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1668 NavigationEntry* entry = controller().GetVisibleEntry();
1669 ASSERT_NE(nullptr, entry);
1670 // The URL specified to the interstitial should have been ignored.
1671 EXPECT_TRUE(entry->GetURL() == url1);
1673 // Now don't proceed.
1674 interstitial->DontProceed();
1675 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1676 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1677 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1678 entry = controller().GetVisibleEntry();
1679 ASSERT_NE(nullptr, entry);
1680 EXPECT_TRUE(entry->GetURL() == url1);
1681 EXPECT_EQ(1, controller().GetEntryCount());
1683 RunAllPendingInMessageLoop();
1684 EXPECT_TRUE(deleted);
1687 // Test navigating to a page (with the navigation initiated from the browser,
1688 // as when a URL is typed in the location bar) that shows an interstitial and
1689 // creates a new navigation entry, then proceeding.
1690 TEST_F(WebContentsImplTest,
1691 ShowInterstitialFromBrowserNewNavigationProceed) {
1692 // Navigate to a page.
1693 GURL url1("http://www.google.com");
1694 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1695 EXPECT_EQ(1, controller().GetEntryCount());
1697 // Initiate a browser navigation that will trigger the interstitial
1698 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1699 ui::PAGE_TRANSITION_TYPED, std::string());
1701 // Show an interstitial.
1702 TestInterstitialPage::InterstitialState state =
1703 TestInterstitialPage::INVALID;
1704 bool deleted = false;
1705 GURL url2("http://interstitial");
1706 TestInterstitialPage* interstitial =
1707 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1708 TestInterstitialPageStateGuard state_guard(interstitial);
1709 interstitial->Show();
1710 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1711 // The interstitial should not show until its navigation has committed.
1712 EXPECT_FALSE(interstitial->is_showing());
1713 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1714 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1715 // Let's commit the interstitial navigation.
1716 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
1717 EXPECT_TRUE(interstitial->is_showing());
1718 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1719 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1720 NavigationEntry* entry = controller().GetVisibleEntry();
1721 ASSERT_NE(nullptr, entry);
1722 EXPECT_TRUE(entry->GetURL() == url2);
1724 // Then proceed.
1725 interstitial->Proceed();
1726 // The interstitial should show until the new navigation commits.
1727 RunAllPendingInMessageLoop();
1728 ASSERT_FALSE(deleted);
1729 EXPECT_EQ(TestInterstitialPage::OKED, state);
1730 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1731 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1733 // Simulate the navigation to the page, that's when the interstitial gets
1734 // hidden.
1735 GURL url3("http://www.thepage.com");
1736 contents()->GetMainFrame()->PrepareForCommit();
1737 contents()->GetMainFrame()->SendNavigate(2, 0, true, url3);
1739 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1740 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1741 entry = controller().GetVisibleEntry();
1742 ASSERT_NE(nullptr, entry);
1743 EXPECT_TRUE(entry->GetURL() == url3);
1745 EXPECT_EQ(2, controller().GetEntryCount());
1747 RunAllPendingInMessageLoop();
1748 EXPECT_TRUE(deleted);
1751 // Test navigating to a page (with the navigation initiated from the renderer,
1752 // as when clicking on a link in the page) that shows an interstitial and
1753 // creates a new navigation entry, then proceeding.
1754 TEST_F(WebContentsImplTest,
1755 ShowInterstitialFromRendererNewNavigationProceed) {
1756 // Navigate to a page.
1757 GURL url1("http://www.google.com");
1758 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1759 EXPECT_EQ(1, controller().GetEntryCount());
1761 // Show an interstitial.
1762 TestInterstitialPage::InterstitialState state =
1763 TestInterstitialPage::INVALID;
1764 bool deleted = false;
1765 GURL url2("http://interstitial");
1766 TestInterstitialPage* interstitial =
1767 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1768 TestInterstitialPageStateGuard state_guard(interstitial);
1769 interstitial->Show();
1770 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1771 // The interstitial should not show until its navigation has committed.
1772 EXPECT_FALSE(interstitial->is_showing());
1773 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1774 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1775 // Let's commit the interstitial navigation.
1776 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
1777 EXPECT_TRUE(interstitial->is_showing());
1778 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1779 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1780 NavigationEntry* entry = controller().GetVisibleEntry();
1781 ASSERT_NE(nullptr, entry);
1782 EXPECT_TRUE(entry->GetURL() == url2);
1784 // Then proceed.
1785 interstitial->Proceed();
1786 // The interstitial should show until the new navigation commits.
1787 RunAllPendingInMessageLoop();
1788 ASSERT_FALSE(deleted);
1789 EXPECT_EQ(TestInterstitialPage::OKED, state);
1790 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1791 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1793 // Simulate the navigation to the page, that's when the interstitial gets
1794 // hidden.
1795 GURL url3("http://www.thepage.com");
1796 main_test_rfh()->NavigateAndCommitRendererInitiated(2, true, url3);
1798 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1799 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1800 entry = controller().GetVisibleEntry();
1801 ASSERT_NE(nullptr, entry);
1802 EXPECT_TRUE(entry->GetURL() == url3);
1804 EXPECT_EQ(2, controller().GetEntryCount());
1806 RunAllPendingInMessageLoop();
1807 EXPECT_TRUE(deleted);
1810 // Test navigating to a page that shows an interstitial without creating a new
1811 // navigation entry (this happens when the interstitial is triggered by a
1812 // sub-resource in the page), then proceeding.
1813 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1814 // Navigate to a page so we have a navigation entry in the controller.
1815 GURL url1("http://www.google.com");
1816 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1817 EXPECT_EQ(1, controller().GetEntryCount());
1819 // Show an interstitial.
1820 TestInterstitialPage::InterstitialState state =
1821 TestInterstitialPage::INVALID;
1822 bool deleted = false;
1823 GURL url2("http://interstitial");
1824 TestInterstitialPage* interstitial =
1825 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1826 TestInterstitialPageStateGuard state_guard(interstitial);
1827 interstitial->Show();
1828 // The interstitial should not show until its navigation has committed.
1829 EXPECT_FALSE(interstitial->is_showing());
1830 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1831 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1832 // Let's commit the interstitial navigation.
1833 interstitial->TestDidNavigate(1, 0, true, url2);
1834 EXPECT_TRUE(interstitial->is_showing());
1835 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1836 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1837 NavigationEntry* entry = controller().GetVisibleEntry();
1838 ASSERT_NE(nullptr, entry);
1839 // The URL specified to the interstitial should have been ignored.
1840 EXPECT_TRUE(entry->GetURL() == url1);
1842 // Then proceed.
1843 interstitial->Proceed();
1844 // Since this is not a new navigation, the previous page is dismissed right
1845 // away and shows the original page.
1846 EXPECT_EQ(TestInterstitialPage::OKED, state);
1847 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1848 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1849 entry = controller().GetVisibleEntry();
1850 ASSERT_NE(nullptr, entry);
1851 EXPECT_TRUE(entry->GetURL() == url1);
1853 EXPECT_EQ(1, controller().GetEntryCount());
1855 RunAllPendingInMessageLoop();
1856 EXPECT_TRUE(deleted);
1859 // Test navigating to a page that shows an interstitial, then navigating away.
1860 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1861 // Show interstitial.
1862 TestInterstitialPage::InterstitialState state =
1863 TestInterstitialPage::INVALID;
1864 bool deleted = false;
1865 GURL url("http://interstitial");
1866 TestInterstitialPage* interstitial =
1867 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1868 TestInterstitialPageStateGuard state_guard(interstitial);
1869 interstitial->Show();
1870 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1871 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
1873 // While interstitial showing, navigate to a new URL.
1874 const GURL url2("http://www.yahoo.com");
1875 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2);
1877 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1879 RunAllPendingInMessageLoop();
1880 EXPECT_TRUE(deleted);
1883 // Test navigating to a page that shows an interstitial, then going back.
1884 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1885 // Navigate to a page so we have a navigation entry in the controller.
1886 GURL url1("http://www.google.com");
1887 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1888 EXPECT_EQ(1, controller().GetEntryCount());
1890 // Show interstitial.
1891 TestInterstitialPage::InterstitialState state =
1892 TestInterstitialPage::INVALID;
1893 bool deleted = false;
1894 GURL interstitial_url("http://interstitial");
1895 TestInterstitialPage* interstitial =
1896 new TestInterstitialPage(contents(), true, interstitial_url,
1897 &state, &deleted);
1898 TestInterstitialPageStateGuard state_guard(interstitial);
1899 interstitial->Show();
1900 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1901 interstitial->TestDidNavigate(2, interstitial_entry_id, true,
1902 interstitial_url);
1903 EXPECT_EQ(2, controller().GetEntryCount());
1905 // While the interstitial is showing, go back. This will dismiss the
1906 // interstitial and not initiate a navigation, but just show the existing
1907 // RenderFrameHost.
1908 controller().GoBack();
1910 // Make sure we are back to the original page and that the interstitial is
1911 // gone.
1912 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1913 NavigationEntry* entry = controller().GetVisibleEntry();
1914 ASSERT_TRUE(entry);
1915 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1916 EXPECT_EQ(1, controller().GetEntryCount());
1918 RunAllPendingInMessageLoop();
1919 EXPECT_TRUE(deleted);
1922 // Test navigating to a page that shows an interstitial, has a renderer crash,
1923 // and then goes back.
1924 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1925 // Navigate to a page so we have a navigation entry in the controller.
1926 GURL url1("http://www.google.com");
1927 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1928 EXPECT_EQ(1, controller().GetEntryCount());
1929 NavigationEntry* entry = controller().GetLastCommittedEntry();
1931 // Show interstitial.
1932 TestInterstitialPage::InterstitialState state =
1933 TestInterstitialPage::INVALID;
1934 bool deleted = false;
1935 GURL interstitial_url("http://interstitial");
1936 TestInterstitialPage* interstitial =
1937 new TestInterstitialPage(contents(), true, interstitial_url,
1938 &state, &deleted);
1939 TestInterstitialPageStateGuard state_guard(interstitial);
1940 interstitial->Show();
1941 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1942 interstitial->TestDidNavigate(2, interstitial_entry_id, true,
1943 interstitial_url);
1945 // Crash the renderer
1946 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1948 // While the interstitial is showing, go back. This will dismiss the
1949 // interstitial and not initiate a navigation, but just show the existing
1950 // RenderFrameHost.
1951 controller().GoBack();
1953 // Make sure we are back to the original page and that the interstitial is
1954 // gone.
1955 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1956 entry = controller().GetVisibleEntry();
1957 ASSERT_TRUE(entry);
1958 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1960 RunAllPendingInMessageLoop();
1961 EXPECT_TRUE(deleted);
1964 // Test navigating to a page that shows an interstitial, has the renderer crash,
1965 // and then navigates to the interstitial.
1966 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1967 // Navigate to a page so we have a navigation entry in the controller.
1968 GURL url1("http://www.google.com");
1969 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1970 EXPECT_EQ(1, controller().GetEntryCount());
1972 // Show interstitial.
1973 TestInterstitialPage::InterstitialState state =
1974 TestInterstitialPage::INVALID;
1975 bool deleted = false;
1976 GURL interstitial_url("http://interstitial");
1977 TestInterstitialPage* interstitial =
1978 new TestInterstitialPage(contents(), true, interstitial_url,
1979 &state, &deleted);
1980 TestInterstitialPageStateGuard state_guard(interstitial);
1981 interstitial->Show();
1982 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1984 // Crash the renderer
1985 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1987 interstitial->TestDidNavigate(2, interstitial_entry_id, true,
1988 interstitial_url);
1991 // Test navigating to a page that shows an interstitial, then close the
1992 // contents.
1993 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1994 // Show interstitial.
1995 TestInterstitialPage::InterstitialState state =
1996 TestInterstitialPage::INVALID;
1997 bool deleted = false;
1998 GURL url("http://interstitial");
1999 TestInterstitialPage* interstitial =
2000 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2001 TestInterstitialPageStateGuard state_guard(interstitial);
2002 interstitial->Show();
2003 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2004 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
2006 // Now close the contents.
2007 DeleteContents();
2008 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2010 RunAllPendingInMessageLoop();
2011 EXPECT_TRUE(deleted);
2014 // Test navigating to a page that shows an interstitial, then close the
2015 // contents.
2016 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
2017 // Show interstitial.
2018 TestInterstitialPage::InterstitialState state =
2019 TestInterstitialPage::INVALID;
2020 bool deleted = false;
2021 GURL url("http://interstitial");
2022 TestInterstitialPage* interstitial =
2023 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2024 TestInterstitialPageStateGuard state_guard(interstitial);
2025 interstitial->Show();
2026 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2027 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
2028 TestRenderFrameHost* rfh =
2029 static_cast<TestRenderFrameHost*>(interstitial->GetMainFrame());
2031 // Now close the contents.
2032 DeleteContents();
2033 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2035 // Before the interstitial has a chance to process its shutdown task,
2036 // simulate quitting the browser. This goes through all processes and
2037 // tells them to destruct.
2038 rfh->GetProcess()->SimulateCrash();
2040 RunAllPendingInMessageLoop();
2041 EXPECT_TRUE(deleted);
2044 // Test that after Proceed is called and an interstitial is still shown, no more
2045 // commands get executed.
2046 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
2047 // Navigate to a page so we have a navigation entry in the controller.
2048 GURL url1("http://www.google.com");
2049 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
2050 EXPECT_EQ(1, controller().GetEntryCount());
2052 // Show an interstitial.
2053 TestInterstitialPage::InterstitialState state =
2054 TestInterstitialPage::INVALID;
2055 bool deleted = false;
2056 GURL url2("http://interstitial");
2057 TestInterstitialPage* interstitial =
2058 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2059 TestInterstitialPageStateGuard state_guard(interstitial);
2060 interstitial->Show();
2061 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2062 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
2064 // Run a command.
2065 EXPECT_EQ(0, interstitial->command_received_count());
2066 interstitial->TestDomOperationResponse("toto");
2067 EXPECT_EQ(1, interstitial->command_received_count());
2069 // Then proceed.
2070 interstitial->Proceed();
2071 RunAllPendingInMessageLoop();
2072 ASSERT_FALSE(deleted);
2074 // While the navigation to the new page is pending, send other commands, they
2075 // should be ignored.
2076 interstitial->TestDomOperationResponse("hello");
2077 interstitial->TestDomOperationResponse("hi");
2078 EXPECT_EQ(1, interstitial->command_received_count());
2081 // Test showing an interstitial while another interstitial is already showing.
2082 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
2083 // Navigate to a page so we have a navigation entry in the controller.
2084 GURL start_url("http://www.google.com");
2085 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url);
2086 EXPECT_EQ(1, controller().GetEntryCount());
2088 // Show an interstitial.
2089 TestInterstitialPage::InterstitialState state1 =
2090 TestInterstitialPage::INVALID;
2091 bool deleted1 = false;
2092 GURL url1("http://interstitial1");
2093 TestInterstitialPage* interstitial1 =
2094 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
2095 TestInterstitialPageStateGuard state_guard1(interstitial1);
2096 interstitial1->Show();
2097 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2098 interstitial1->TestDidNavigate(1, interstitial_entry_id, true, url1);
2100 // Now show another interstitial.
2101 TestInterstitialPage::InterstitialState state2 =
2102 TestInterstitialPage::INVALID;
2103 bool deleted2 = false;
2104 GURL url2("http://interstitial2");
2105 TestInterstitialPage* interstitial2 =
2106 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2107 TestInterstitialPageStateGuard state_guard2(interstitial2);
2108 interstitial2->Show();
2109 interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2110 interstitial2->TestDidNavigate(1, interstitial_entry_id, true, url2);
2112 // Showing interstitial2 should have caused interstitial1 to go away.
2113 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2114 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2116 RunAllPendingInMessageLoop();
2117 EXPECT_TRUE(deleted1);
2118 ASSERT_FALSE(deleted2);
2120 // Let's make sure interstitial2 is working as intended.
2121 interstitial2->Proceed();
2122 GURL landing_url("http://www.thepage.com");
2123 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url);
2125 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2126 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2127 NavigationEntry* entry = controller().GetVisibleEntry();
2128 ASSERT_NE(nullptr, entry);
2129 EXPECT_TRUE(entry->GetURL() == landing_url);
2130 EXPECT_EQ(2, controller().GetEntryCount());
2131 RunAllPendingInMessageLoop();
2132 EXPECT_TRUE(deleted2);
2135 // Test showing an interstitial, proceeding and then navigating to another
2136 // interstitial.
2137 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
2138 // Navigate to a page so we have a navigation entry in the controller.
2139 GURL start_url("http://www.google.com");
2140 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url);
2141 EXPECT_EQ(1, controller().GetEntryCount());
2143 // Show an interstitial.
2144 TestInterstitialPage::InterstitialState state1 =
2145 TestInterstitialPage::INVALID;
2146 bool deleted1 = false;
2147 GURL url1("http://interstitial1");
2148 TestInterstitialPage* interstitial1 =
2149 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
2150 TestInterstitialPageStateGuard state_guard1(interstitial1);
2151 interstitial1->Show();
2152 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2153 interstitial1->TestDidNavigate(1, interstitial_entry_id, true, url1);
2155 // Take action. The interstitial won't be hidden until the navigation is
2156 // committed.
2157 interstitial1->Proceed();
2158 EXPECT_EQ(TestInterstitialPage::OKED, state1);
2160 // Now show another interstitial (simulating the navigation causing another
2161 // interstitial).
2162 TestInterstitialPage::InterstitialState state2 =
2163 TestInterstitialPage::INVALID;
2164 bool deleted2 = false;
2165 GURL url2("http://interstitial2");
2166 TestInterstitialPage* interstitial2 =
2167 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2168 TestInterstitialPageStateGuard state_guard2(interstitial2);
2169 interstitial2->Show();
2170 interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2171 interstitial2->TestDidNavigate(1, interstitial_entry_id, true, url2);
2173 // Showing interstitial2 should have caused interstitial1 to go away.
2174 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2175 RunAllPendingInMessageLoop();
2176 EXPECT_TRUE(deleted1);
2177 ASSERT_FALSE(deleted2);
2179 // Let's make sure interstitial2 is working as intended.
2180 interstitial2->Proceed();
2181 GURL landing_url("http://www.thepage.com");
2182 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url);
2184 RunAllPendingInMessageLoop();
2185 EXPECT_TRUE(deleted2);
2186 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2187 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2188 NavigationEntry* entry = controller().GetVisibleEntry();
2189 ASSERT_NE(nullptr, entry);
2190 EXPECT_TRUE(entry->GetURL() == landing_url);
2191 EXPECT_EQ(2, controller().GetEntryCount());
2194 // Test that navigating away from an interstitial while it's loading cause it
2195 // not to show.
2196 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
2197 // Show an interstitial.
2198 TestInterstitialPage::InterstitialState state =
2199 TestInterstitialPage::INVALID;
2200 bool deleted = false;
2201 GURL interstitial_url("http://interstitial");
2202 TestInterstitialPage* interstitial =
2203 new TestInterstitialPage(contents(), true, interstitial_url,
2204 &state, &deleted);
2205 TestInterstitialPageStateGuard state_guard(interstitial);
2206 interstitial->Show();
2207 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2209 // Let's simulate a navigation initiated from the browser before the
2210 // interstitial finishes loading.
2211 const GURL url("http://www.google.com");
2212 controller().LoadURL(
2213 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2214 EXPECT_FALSE(interstitial->is_showing());
2215 RunAllPendingInMessageLoop();
2216 ASSERT_FALSE(deleted);
2218 // Now let's make the interstitial navigation commit.
2219 interstitial->TestDidNavigate(1, interstitial_entry_id, true,
2220 interstitial_url);
2222 // After it loaded the interstitial should be gone.
2223 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2225 RunAllPendingInMessageLoop();
2226 EXPECT_TRUE(deleted);
2229 // Test that a new request to show an interstitial while an interstitial is
2230 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2231 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
2232 GURL interstitial_url("http://interstitial");
2234 // Show a first interstitial.
2235 TestInterstitialPage::InterstitialState state1 =
2236 TestInterstitialPage::INVALID;
2237 bool deleted1 = false;
2238 TestInterstitialPage* interstitial1 =
2239 new TestInterstitialPage(contents(), true, interstitial_url,
2240 &state1, &deleted1);
2241 TestInterstitialPageStateGuard state_guard1(interstitial1);
2242 interstitial1->Show();
2244 // Show another interstitial on that same contents before the first one had
2245 // time to load.
2246 TestInterstitialPage::InterstitialState state2 =
2247 TestInterstitialPage::INVALID;
2248 bool deleted2 = false;
2249 TestInterstitialPage* interstitial2 =
2250 new TestInterstitialPage(contents(), true, interstitial_url,
2251 &state2, &deleted2);
2252 TestInterstitialPageStateGuard state_guard2(interstitial2);
2253 interstitial2->Show();
2254 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2256 // The first interstitial should have been closed and deleted.
2257 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2258 // The 2nd one should still be OK.
2259 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2261 RunAllPendingInMessageLoop();
2262 EXPECT_TRUE(deleted1);
2263 ASSERT_FALSE(deleted2);
2265 // Make the interstitial navigation commit it should be showing.
2266 interstitial2->TestDidNavigate(1, interstitial_entry_id, true,
2267 interstitial_url);
2268 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
2271 // Test showing an interstitial and have its renderer crash.
2272 TEST_F(WebContentsImplTest, InterstitialCrasher) {
2273 // Show an interstitial.
2274 TestInterstitialPage::InterstitialState state =
2275 TestInterstitialPage::INVALID;
2276 bool deleted = false;
2277 GURL url("http://interstitial");
2278 TestInterstitialPage* interstitial =
2279 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2280 TestInterstitialPageStateGuard state_guard(interstitial);
2281 interstitial->Show();
2282 // Simulate a renderer crash before the interstitial is shown.
2283 interstitial->TestRenderViewTerminated(
2284 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2285 // The interstitial should have been dismissed.
2286 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2287 RunAllPendingInMessageLoop();
2288 EXPECT_TRUE(deleted);
2290 // Now try again but this time crash the intersitial after it was shown.
2291 interstitial =
2292 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2293 interstitial->Show();
2294 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2295 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
2296 // Simulate a renderer crash.
2297 interstitial->TestRenderViewTerminated(
2298 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2299 // The interstitial should have been dismissed.
2300 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2301 RunAllPendingInMessageLoop();
2302 EXPECT_TRUE(deleted);
2305 // Tests that showing an interstitial as a result of a browser initiated
2306 // navigation while an interstitial is showing does not remove the pending
2307 // entry (see http://crbug.com/9791).
2308 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
2309 const char kUrl[] = "http://www.badguys.com/";
2310 const GURL kGURL(kUrl);
2312 // Start a navigation to a page
2313 contents()->GetController().LoadURL(
2314 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2316 // Simulate that navigation triggering an interstitial.
2317 TestInterstitialPage::InterstitialState state =
2318 TestInterstitialPage::INVALID;
2319 bool deleted = false;
2320 TestInterstitialPage* interstitial =
2321 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2322 TestInterstitialPageStateGuard state_guard(interstitial);
2323 interstitial->Show();
2324 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2325 interstitial->TestDidNavigate(1, interstitial_entry_id, true, kGURL);
2327 // Initiate a new navigation from the browser that also triggers an
2328 // interstitial.
2329 contents()->GetController().LoadURL(
2330 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2331 TestInterstitialPage::InterstitialState state2 =
2332 TestInterstitialPage::INVALID;
2333 bool deleted2 = false;
2334 TestInterstitialPage* interstitial2 =
2335 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
2336 TestInterstitialPageStateGuard state_guard2(interstitial2);
2337 interstitial2->Show();
2338 interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2339 interstitial2->TestDidNavigate(1, interstitial_entry_id, true, kGURL);
2341 // Make sure we still have an entry.
2342 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2343 ASSERT_TRUE(entry);
2344 EXPECT_EQ(kUrl, entry->GetURL().spec());
2346 // And that the first interstitial is gone, but not the second.
2347 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2348 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2349 RunAllPendingInMessageLoop();
2350 EXPECT_TRUE(deleted);
2351 EXPECT_FALSE(deleted2);
2354 // Tests that Javascript messages are not shown while an interstitial is
2355 // showing.
2356 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2357 const char kUrl[] = "http://www.badguys.com/";
2358 const GURL kGURL(kUrl);
2360 // Start a navigation to a page
2361 contents()->GetController().LoadURL(
2362 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2363 int entry_id = controller().GetPendingEntry()->GetUniqueID();
2364 main_test_rfh()->PrepareForCommit();
2365 // DidNavigate from the page
2366 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id, true,
2367 kGURL, ui::PAGE_TRANSITION_TYPED);
2369 // Simulate showing an interstitial while the page is showing.
2370 TestInterstitialPage::InterstitialState state =
2371 TestInterstitialPage::INVALID;
2372 bool deleted = false;
2373 TestInterstitialPage* interstitial =
2374 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2375 TestInterstitialPageStateGuard state_guard(interstitial);
2376 interstitial->Show();
2377 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2378 interstitial->TestDidNavigate(1, interstitial_entry_id, true, kGURL);
2380 // While the interstitial is showing, let's simulate the hidden page
2381 // attempting to show a JS message.
2382 IPC::Message* dummy_message = new IPC::Message;
2383 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2384 base::ASCIIToUTF16("This is an informative message"),
2385 base::ASCIIToUTF16("OK"),
2386 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message);
2387 EXPECT_TRUE(contents()->last_dialog_suppressed_);
2390 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2391 // interstitial it isn't copied over to the destination.
2392 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2393 // Navigate to a page.
2394 GURL url1("http://www.google.com");
2395 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
2396 EXPECT_EQ(1, controller().GetEntryCount());
2398 // Initiate a browser navigation that will trigger the interstitial
2399 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2400 ui::PAGE_TRANSITION_TYPED, std::string());
2402 // Show an interstitial.
2403 TestInterstitialPage::InterstitialState state =
2404 TestInterstitialPage::INVALID;
2405 bool deleted = false;
2406 GURL url2("http://interstitial");
2407 TestInterstitialPage* interstitial =
2408 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2409 TestInterstitialPageStateGuard state_guard(interstitial);
2410 interstitial->Show();
2411 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2412 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
2413 EXPECT_TRUE(interstitial->is_showing());
2414 EXPECT_EQ(2, controller().GetEntryCount());
2416 // Create another NavigationController.
2417 GURL url3("http://foo2");
2418 scoped_ptr<TestWebContents> other_contents(
2419 static_cast<TestWebContents*>(CreateTestWebContents()));
2420 NavigationControllerImpl& other_controller = other_contents->GetController();
2421 other_contents->NavigateAndCommit(url3);
2422 other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
2423 other_controller.CopyStateFromAndPrune(&controller(), false);
2425 // The merged controller should only have two entries: url1 and url2.
2426 ASSERT_EQ(2, other_controller.GetEntryCount());
2427 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2428 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2429 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2431 // And the merged controller shouldn't be showing an interstitial.
2432 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2435 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2436 // showing an interstitial.
2437 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2438 // Navigate to a page.
2439 GURL url1("http://www.google.com");
2440 contents()->NavigateAndCommit(url1);
2442 // Create another NavigationController.
2443 scoped_ptr<TestWebContents> other_contents(
2444 static_cast<TestWebContents*>(CreateTestWebContents()));
2445 NavigationControllerImpl& other_controller = other_contents->GetController();
2447 // Navigate it to url2.
2448 GURL url2("http://foo2");
2449 other_contents->NavigateAndCommit(url2);
2451 // Show an interstitial.
2452 TestInterstitialPage::InterstitialState state =
2453 TestInterstitialPage::INVALID;
2454 bool deleted = false;
2455 GURL url3("http://interstitial");
2456 TestInterstitialPage* interstitial =
2457 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2458 &deleted);
2459 TestInterstitialPageStateGuard state_guard(interstitial);
2460 interstitial->Show();
2461 int interstitial_entry_id =
2462 other_controller.GetTransientEntry()->GetUniqueID();
2463 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url3);
2464 EXPECT_TRUE(interstitial->is_showing());
2465 EXPECT_EQ(2, other_controller.GetEntryCount());
2467 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2468 // interstitial is showing in the target.
2469 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2472 // Regression test for http://crbug.com/168611 - the URLs passed by the
2473 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2474 TEST_F(WebContentsImplTest, FilterURLs) {
2475 TestWebContentsObserver observer(contents());
2477 // A navigation to about:whatever should always look like a navigation to
2478 // about:blank
2479 GURL url_normalized(url::kAboutBlankURL);
2480 GURL url_from_ipc("about:whatever");
2482 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2483 // will use the given URL to create the NavigationEntry as well, and that
2484 // entry should contain the filtered URL.
2485 contents()->NavigateAndCommit(url_normalized);
2487 // Check that an IPC with about:whatever is correctly normalized.
2488 contents()->TestDidFinishLoad(url_from_ipc);
2490 EXPECT_EQ(url_normalized, observer.last_url());
2492 // Create and navigate another WebContents.
2493 scoped_ptr<TestWebContents> other_contents(
2494 static_cast<TestWebContents*>(CreateTestWebContents()));
2495 TestWebContentsObserver other_observer(other_contents.get());
2496 other_contents->NavigateAndCommit(url_normalized);
2498 // Check that an IPC with about:whatever is correctly normalized.
2499 other_contents->TestDidFailLoadWithError(
2500 url_from_ipc, 1, base::string16(), false);
2501 EXPECT_EQ(url_normalized, other_observer.last_url());
2504 // Test that if a pending contents is deleted before it is shown, we don't
2505 // crash.
2506 TEST_F(WebContentsImplTest, PendingContents) {
2507 scoped_ptr<TestWebContents> other_contents(
2508 static_cast<TestWebContents*>(CreateTestWebContents()));
2509 contents()->AddPendingContents(other_contents.get());
2510 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2511 other_contents.reset();
2512 EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id));
2515 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
2516 const gfx::Size original_preferred_size(1024, 768);
2517 contents()->UpdatePreferredSize(original_preferred_size);
2519 // With no capturers, expect the preferred size to be the one propagated into
2520 // WebContentsImpl via the RenderViewHostDelegate interface.
2521 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2522 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2524 // Increment capturer count, but without specifying a capture size. Expect
2525 // a "not set" preferred size.
2526 contents()->IncrementCapturerCount(gfx::Size());
2527 EXPECT_EQ(1, contents()->GetCapturerCount());
2528 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2530 // Increment capturer count again, but with an overriding capture size.
2531 // Expect preferred size to now be overridden to the capture size.
2532 const gfx::Size capture_size(1280, 720);
2533 contents()->IncrementCapturerCount(capture_size);
2534 EXPECT_EQ(2, contents()->GetCapturerCount());
2535 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2537 // Increment capturer count a third time, but the expect that the preferred
2538 // size is still the first capture size.
2539 const gfx::Size another_capture_size(720, 480);
2540 contents()->IncrementCapturerCount(another_capture_size);
2541 EXPECT_EQ(3, contents()->GetCapturerCount());
2542 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2544 // Decrement capturer count twice, but expect the preferred size to still be
2545 // overridden.
2546 contents()->DecrementCapturerCount();
2547 contents()->DecrementCapturerCount();
2548 EXPECT_EQ(1, contents()->GetCapturerCount());
2549 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2551 // Decrement capturer count, and since the count has dropped to zero, the
2552 // original preferred size should be restored.
2553 contents()->DecrementCapturerCount();
2554 EXPECT_EQ(0, contents()->GetCapturerCount());
2555 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2558 TEST_F(WebContentsImplTest, CapturerPreventsHiding) {
2559 const gfx::Size original_preferred_size(1024, 768);
2560 contents()->UpdatePreferredSize(original_preferred_size);
2562 TestRenderWidgetHostView* view = static_cast<TestRenderWidgetHostView*>(
2563 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2565 // With no capturers, setting and un-setting occlusion should change the
2566 // view's occlusion state.
2567 EXPECT_FALSE(view->is_showing());
2568 contents()->WasShown();
2569 EXPECT_TRUE(view->is_showing());
2570 contents()->WasHidden();
2571 EXPECT_FALSE(view->is_showing());
2572 contents()->WasShown();
2573 EXPECT_TRUE(view->is_showing());
2575 // Add a capturer and try to hide the contents. The view will remain visible.
2576 contents()->IncrementCapturerCount(gfx::Size());
2577 contents()->WasHidden();
2578 EXPECT_TRUE(view->is_showing());
2580 // Remove the capturer, and the WasHidden should take effect.
2581 contents()->DecrementCapturerCount();
2582 EXPECT_FALSE(view->is_showing());
2585 TEST_F(WebContentsImplTest, CapturerPreventsOcclusion) {
2586 const gfx::Size original_preferred_size(1024, 768);
2587 contents()->UpdatePreferredSize(original_preferred_size);
2589 TestRenderWidgetHostView* view = static_cast<TestRenderWidgetHostView*>(
2590 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2592 // With no capturers, setting and un-setting occlusion should change the
2593 // view's occlusion state.
2594 EXPECT_FALSE(view->is_occluded());
2595 contents()->WasOccluded();
2596 EXPECT_TRUE(view->is_occluded());
2597 contents()->WasUnOccluded();
2598 EXPECT_FALSE(view->is_occluded());
2599 contents()->WasOccluded();
2600 EXPECT_TRUE(view->is_occluded());
2602 // Add a capturer. This should cause the view to be un-occluded.
2603 contents()->IncrementCapturerCount(gfx::Size());
2604 EXPECT_FALSE(view->is_occluded());
2606 // Try to occlude the view. This will fail to propagate because of the
2607 // active capturer.
2608 contents()->WasOccluded();
2609 EXPECT_FALSE(view->is_occluded());
2611 // Remove the capturer and try again.
2612 contents()->DecrementCapturerCount();
2613 EXPECT_FALSE(view->is_occluded());
2614 contents()->WasOccluded();
2615 EXPECT_TRUE(view->is_occluded());
2618 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2619 // on activity.
2620 TEST_F(WebContentsImplTest, GetLastActiveTime) {
2621 // The WebContents starts with a valid creation time.
2622 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2624 // Reset the last active time to a known-bad value.
2625 contents()->last_active_time_ = base::TimeTicks();
2626 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2628 // Simulate activating the WebContents. The active time should update.
2629 contents()->WasShown();
2630 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2633 class ContentsZoomChangedDelegate : public WebContentsDelegate {
2634 public:
2635 ContentsZoomChangedDelegate() :
2636 contents_zoom_changed_call_count_(0),
2637 last_zoom_in_(false) {
2640 int GetAndResetContentsZoomChangedCallCount() {
2641 int count = contents_zoom_changed_call_count_;
2642 contents_zoom_changed_call_count_ = 0;
2643 return count;
2646 bool last_zoom_in() const {
2647 return last_zoom_in_;
2650 // WebContentsDelegate:
2651 void ContentsZoomChange(bool zoom_in) override {
2652 contents_zoom_changed_call_count_++;
2653 last_zoom_in_ = zoom_in;
2656 private:
2657 int contents_zoom_changed_call_count_;
2658 bool last_zoom_in_;
2660 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
2663 // Tests that some mouseehweel events get turned into browser zoom requests.
2664 TEST_F(WebContentsImplTest, HandleWheelEvent) {
2665 using blink::WebInputEvent;
2667 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2668 new ContentsZoomChangedDelegate());
2669 contents()->SetDelegate(delegate.get());
2671 int modifiers = 0;
2672 // Verify that normal mouse wheel events do nothing to change the zoom level.
2673 blink::WebMouseWheelEvent event =
2674 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2675 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2676 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2678 modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey |
2679 WebInputEvent::ControlKey;
2680 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2681 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2682 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2684 // But whenever the ctrl modifier is applied with canScroll=false, they can
2685 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2686 // with mousewheel.
2687 modifiers = WebInputEvent::ControlKey;
2688 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2689 event.canScroll = false;
2690 bool handled = contents()->HandleWheelEvent(event);
2691 #if defined(OS_MACOSX)
2692 EXPECT_FALSE(handled);
2693 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2694 #else
2695 EXPECT_TRUE(handled);
2696 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2697 EXPECT_TRUE(delegate->last_zoom_in());
2698 #endif
2700 modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
2701 WebInputEvent::AltKey;
2702 event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false);
2703 event.canScroll = false;
2704 handled = contents()->HandleWheelEvent(event);
2705 #if defined(OS_MACOSX)
2706 EXPECT_FALSE(handled);
2707 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2708 #else
2709 EXPECT_TRUE(handled);
2710 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2711 EXPECT_FALSE(delegate->last_zoom_in());
2712 #endif
2714 // Unless there is no vertical movement.
2715 event = SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers, false);
2716 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2717 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2719 // Events containing precise scrolling deltas also shouldn't result in the
2720 // zoom being adjusted, to avoid accidental adjustments caused by
2721 // two-finger-scrolling on a touchpad.
2722 modifiers = WebInputEvent::ControlKey;
2723 event = SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers, true);
2724 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2725 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2727 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2728 contents()->SetDelegate(nullptr);
2731 // Tests that GetRelatedActiveContentsCount is shared between related
2732 // SiteInstances and includes WebContents that have not navigated yet.
2733 TEST_F(WebContentsImplTest, ActiveContentsCountBasic) {
2734 scoped_refptr<SiteInstance> instance1(
2735 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2736 scoped_refptr<SiteInstance> instance2(
2737 instance1->GetRelatedSiteInstance(GURL("http://b.com")));
2739 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2740 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2742 scoped_ptr<TestWebContents> contents1(
2743 TestWebContents::Create(browser_context(), instance1.get()));
2744 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2745 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2747 scoped_ptr<TestWebContents> contents2(
2748 TestWebContents::Create(browser_context(), instance1.get()));
2749 EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount());
2750 EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount());
2752 contents1.reset();
2753 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2754 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2756 contents2.reset();
2757 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2758 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2761 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2762 // same-site and cross-site navigations.
2763 TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
2764 scoped_refptr<SiteInstance> instance(
2765 SiteInstance::Create(browser_context()));
2767 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2769 scoped_ptr<TestWebContents> contents(
2770 TestWebContents::Create(browser_context(), instance.get()));
2771 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2773 // Navigate to a URL.
2774 contents->GetController().LoadURL(GURL("http://a.com/1"),
2775 Referrer(),
2776 ui::PAGE_TRANSITION_TYPED,
2777 std::string());
2778 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2779 contents->CommitPendingNavigation();
2780 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2782 // Navigate to a URL in the same site.
2783 contents->GetController().LoadURL(GURL("http://a.com/2"),
2784 Referrer(),
2785 ui::PAGE_TRANSITION_TYPED,
2786 std::string());
2787 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2788 contents->CommitPendingNavigation();
2789 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2791 // Navigate to a URL in a different site.
2792 const GURL kUrl = GURL("http://b.com");
2793 contents->GetController().LoadURL(kUrl,
2794 Referrer(),
2795 ui::PAGE_TRANSITION_TYPED,
2796 std::string());
2797 int entry_id = contents->GetController().GetPendingEntry()->GetUniqueID();
2798 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2799 switches::kEnableBrowserSideNavigation)) {
2800 contents->GetMainFrame()->PrepareForCommit();
2802 EXPECT_TRUE(contents->CrossProcessNavigationPending());
2803 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2804 contents->GetPendingMainFrame()->SendNavigate(1, entry_id, true, kUrl);
2805 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2807 contents.reset();
2808 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2811 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2812 // from WebUI.
2813 TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
2814 scoped_refptr<SiteInstance> instance(
2815 SiteInstance::Create(browser_context()));
2817 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2819 scoped_ptr<TestWebContents> contents(
2820 TestWebContents::Create(browser_context(), instance.get()));
2821 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2823 // Navigate to a URL.
2824 contents->NavigateAndCommit(GURL("http://a.com"));
2825 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2827 // Navigate to a URL which sort of looks like a chrome:// url.
2828 contents->NavigateAndCommit(GURL("http://gpu"));
2829 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2831 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2832 const GURL kWebUIUrl = GURL("chrome://gpu");
2833 contents->GetController().LoadURL(kWebUIUrl,
2834 Referrer(),
2835 ui::PAGE_TRANSITION_TYPED,
2836 std::string());
2837 int entry_id = contents->GetController().GetPendingEntry()->GetUniqueID();
2838 contents->GetMainFrame()->PrepareForCommit();
2839 EXPECT_TRUE(contents->CrossProcessNavigationPending());
2840 scoped_refptr<SiteInstance> instance_webui(
2841 contents->GetPendingMainFrame()->GetSiteInstance());
2842 EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
2844 // At this point, contents still counts for the old BrowsingInstance.
2845 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2846 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2848 // Commit and contents counts for the new one.
2849 contents->GetPendingMainFrame()->SendNavigate(1, entry_id, true, kWebUIUrl);
2850 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2851 EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount());
2853 contents.reset();
2854 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2855 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2858 class LoadingWebContentsObserver : public WebContentsObserver {
2859 public:
2860 explicit LoadingWebContentsObserver(WebContents* contents)
2861 : WebContentsObserver(contents),
2862 is_loading_(false) {
2864 ~LoadingWebContentsObserver() override {}
2866 void DidStartLoading() override { is_loading_ = true; }
2867 void DidStopLoading() override { is_loading_ = false; }
2869 bool is_loading() const { return is_loading_; }
2871 private:
2872 bool is_loading_;
2874 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver);
2877 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2878 // interleaving cross-process navigations in multiple subframes.
2879 // See https://crbug.com/448601 for details of the underlying issue. The
2880 // sequence of events that reproduce it are as follows:
2881 // * Navigate top-level frame with one subframe.
2882 // * Subframe navigates more than once before the top-level frame has had a
2883 // chance to complete the load.
2884 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2885 // to 0, while the loading_progresses_ map is not reset.
2886 TEST_F(WebContentsImplTest, StartStopEventsBalance) {
2887 // The bug manifests itself in regular mode as well, but browser-initiated
2888 // navigation of subframes is only possible in --site-per-process mode within
2889 // unit tests.
2890 IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess());
2891 const GURL initial_url("about:blank");
2892 const GURL main_url("http://www.chromium.org");
2893 const GURL foo_url("http://foo.chromium.org");
2894 const GURL bar_url("http://bar.chromium.org");
2895 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
2897 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
2898 LoadingWebContentsObserver observer(contents());
2900 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
2901 // The frame should still be loading.
2902 controller().LoadURL(
2903 main_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2904 int entry_id = controller().GetPendingEntry()->GetUniqueID();
2905 orig_rfh->PrepareForCommit();
2906 orig_rfh->OnMessageReceived(
2907 FrameHostMsg_DidStartLoading(orig_rfh->GetRoutingID(), false));
2908 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, main_url,
2909 ui::PAGE_TRANSITION_TYPED);
2910 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2911 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
2912 EXPECT_TRUE(contents()->IsLoading());
2913 EXPECT_TRUE(observer.is_loading());
2915 // Create a child frame to navigate multiple times.
2916 TestRenderFrameHost* subframe = orig_rfh->AppendChild("subframe");
2918 // Navigate the child frame to about:blank, which will send both
2919 // DidStartLoading and DidStopLoading messages.
2921 subframe->SendRendererInitiatedNavigationRequest(initial_url, false);
2922 subframe->OnMessageReceived(
2923 FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
2924 subframe->SendNavigateWithTransition(1, 0, false, initial_url,
2925 ui::PAGE_TRANSITION_AUTO_SUBFRAME);
2926 subframe->OnMessageReceived(
2927 FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
2930 // Navigate the frame to another URL, which will send again
2931 // DidStartLoading and DidStopLoading messages.
2933 subframe->SendRendererInitiatedNavigationRequest(foo_url, false);
2934 subframe->PrepareForCommit();
2935 subframe->OnMessageReceived(
2936 FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
2937 subframe->SendNavigateWithTransition(1, 0, false, foo_url,
2938 ui::PAGE_TRANSITION_AUTO_SUBFRAME);
2939 subframe->OnMessageReceived(
2940 FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
2943 // Since the main frame hasn't sent any DidStopLoading messages, it is
2944 // expected that the WebContents is still in loading state.
2945 EXPECT_TRUE(contents()->IsLoading());
2946 EXPECT_TRUE(observer.is_loading());
2948 // Navigate the frame again, this time using LoadURLWithParams. This causes
2949 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2950 // the spinner.
2952 NavigationController::LoadURLParams load_params(bar_url);
2953 load_params.referrer =
2954 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault);
2955 load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
2956 load_params.extra_headers = "content-type: text/plain";
2957 load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT;
2958 load_params.is_renderer_initiated = false;
2959 load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
2960 load_params.frame_tree_node_id =
2961 subframe->frame_tree_node()->frame_tree_node_id();
2962 controller().LoadURLWithParams(load_params);
2963 entry_id = controller().GetPendingEntry()->GetUniqueID();
2965 subframe->OnMessageReceived(
2966 FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
2968 // Commit the navigation in the child frame and send the DidStopLoading
2969 // message.
2970 subframe->PrepareForCommit();
2971 contents()->TestDidNavigate(subframe, 3, entry_id, true, bar_url,
2972 ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
2973 subframe->OnMessageReceived(
2974 FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
2977 // At this point the status should still be loading, since the main frame
2978 // hasn't sent the DidstopLoading message yet.
2979 EXPECT_TRUE(contents()->IsLoading());
2980 EXPECT_TRUE(observer.is_loading());
2982 // Send the DidStopLoading for the main frame and ensure it isn't loading
2983 // anymore.
2984 orig_rfh->OnMessageReceived(
2985 FrameHostMsg_DidStopLoading(orig_rfh->GetRoutingID()));
2986 EXPECT_FALSE(contents()->IsLoading());
2987 EXPECT_FALSE(observer.is_loading());
2990 // Ensure that WebContentsImpl does not stop loading too early when there still
2991 // is a pending renderer. This can happen if a same-process non user-initiated
2992 // navigation completes while there is an ongoing cross-process navigation.
2993 // TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
2994 // DidStopLoading are properly called.
2995 TEST_F(WebContentsImplTest, NoEarlyStop) {
2996 const GURL kUrl1("http://www.chromium.org");
2997 const GURL kUrl2("http://www.google.com");
2998 const GURL kUrl3("http://www.wikipedia.org");
3000 contents()->NavigateAndCommit(kUrl1);
3002 TestRenderFrameHost* current_rfh = contents()->GetMainFrame();
3004 // Start a browser-initiated cross-process navigation to |kUrl2|. There should
3005 // be a pending RenderFrameHost and the WebContents should be loading.
3006 controller().LoadURL(
3007 kUrl2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
3008 int entry_id = controller().GetPendingEntry()->GetUniqueID();
3009 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
3010 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
3011 ASSERT_TRUE(pending_rfh);
3012 EXPECT_TRUE(contents()->IsLoading());
3014 // The current RenderFrameHost starts a non user-initiated render-initiated
3015 // navigation and sends a DidStartLoading IPC. The WebContents should still be
3016 // loading.
3017 current_rfh->OnMessageReceived(
3018 FrameHostMsg_DidStartLoading(current_rfh->GetRoutingID(), false));
3019 EXPECT_TRUE(contents()->IsLoading());
3021 // Simulate the pending RenderFrameHost DidStartLoading. There should still be
3022 // a pending RenderFrameHost and the WebContents should still be loading.
3023 pending_rfh->PrepareForCommit();
3024 pending_rfh->OnMessageReceived(
3025 FrameHostMsg_DidStartLoading(pending_rfh->GetRoutingID(), false));
3026 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh);
3027 EXPECT_TRUE(contents()->IsLoading());
3029 // Simulate the commit and DidStopLoading from the renderer-initiated
3030 // navigation in the current RenderFrameHost. There should still be a pending
3031 // RenderFrameHost and the WebContents should still be loading.
3032 current_rfh->SendNavigateWithModificationCallback(
3033 1, 0, true, kUrl3, base::Bind(SetAsNonUserGesture));
3034 current_rfh->OnMessageReceived(
3035 FrameHostMsg_DidStopLoading(current_rfh->GetRoutingID()));
3036 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh);
3037 EXPECT_TRUE(contents()->IsLoading());
3038 // It should commit.
3039 ASSERT_EQ(2, controller().GetEntryCount());
3040 EXPECT_EQ(kUrl3, controller().GetLastCommittedEntry()->GetURL());
3042 // Commit the navigation. The formerly pending RenderFrameHost should now be
3043 // the current RenderFrameHost and the WebContents should still be loading.
3044 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, kUrl2,
3045 ui::PAGE_TRANSITION_TYPED);
3046 EXPECT_FALSE(contents()->GetPendingMainFrame());
3047 TestRenderFrameHost* new_current_rfh = contents()->GetMainFrame();
3048 EXPECT_EQ(new_current_rfh, pending_rfh);
3049 EXPECT_TRUE(contents()->IsLoading());
3050 EXPECT_EQ(3, controller().GetEntryCount());
3052 // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
3053 // should now have stopped loading.
3054 new_current_rfh->OnMessageReceived(
3055 FrameHostMsg_DidStopLoading(new_current_rfh->GetRoutingID()));
3056 EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh);
3057 EXPECT_FALSE(contents()->IsLoading());
3060 TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
3061 // PlayerIDs are actually pointers cast to int64, so verify that both negative
3062 // and positive player ids don't blow up.
3063 const int kPlayerAudioVideoId = 15;
3064 const int kPlayerAudioOnlyId = -15;
3065 const int kPlayerVideoOnlyId = 30;
3066 const int kPlayerRemoteId = -30;
3068 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3069 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3071 TestRenderFrameHost* rfh = contents()->GetMainFrame();
3072 AudioStateProvider* audio_state = contents()->audio_state_provider();
3074 // Ensure RenderFrame is initialized before simulating events coming from it.
3075 main_test_rfh()->InitializeRenderFrameIfNeeded();
3077 // The audio power save blocker should not be based on having a media player
3078 // when audio stream monitoring is available.
3079 if (audio_state->IsAudioStateAvailable()) {
3080 // Send a fake audio stream monitor notification. The audio power save
3081 // blocker should be created.
3082 audio_state->set_was_recently_audible_for_testing(true);
3083 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
3084 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
3086 // Send another fake notification, this time when WasRecentlyAudible() will
3087 // be false. The power save blocker should be released.
3088 audio_state->set_was_recently_audible_for_testing(false);
3089 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
3090 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3093 // Start a player with both audio and video. A video power save blocker
3094 // should be created. If audio stream monitoring is available, an audio power
3095 // save blocker should be created too.
3096 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3097 0, kPlayerAudioVideoId, true, true, false));
3098 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3099 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3100 !audio_state->IsAudioStateAvailable());
3102 // Upon hiding the video power save blocker should be released.
3103 contents()->WasHidden();
3104 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3106 // Start another player that only has video. There should be no change in
3107 // the power save blockers. The notification should take into account the
3108 // visibility state of the WebContents.
3109 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3110 0, kPlayerVideoOnlyId, true, false, false));
3111 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3112 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3113 !audio_state->IsAudioStateAvailable());
3115 // Showing the WebContents should result in the creation of the blocker.
3116 contents()->WasShown();
3117 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3119 // Start another player that only has audio. There should be no change in
3120 // the power save blockers.
3121 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3122 0, kPlayerAudioOnlyId, false, true, false));
3123 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3124 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3125 !audio_state->IsAudioStateAvailable());
3127 // Start a remote player. There should be no change in the power save
3128 // blockers.
3129 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3130 0, kPlayerRemoteId, true, true, true));
3131 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3132 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3133 !audio_state->IsAudioStateAvailable());
3135 // Destroy the original audio video player. Both power save blockers should
3136 // remain.
3137 rfh->OnMessageReceived(
3138 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId));
3139 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3140 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3141 !audio_state->IsAudioStateAvailable());
3143 // Destroy the audio only player. The video power save blocker should remain.
3144 rfh->OnMessageReceived(
3145 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId));
3146 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3147 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3149 // Destroy the video only player. No power save blockers should remain.
3150 rfh->OnMessageReceived(
3151 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId));
3152 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3153 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3155 // Destroy the remote player. No power save blockers should remain.
3156 rfh->OnMessageReceived(
3157 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId));
3158 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3159 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3161 // Start a player with both audio and video. A video power save blocker
3162 // should be created. If audio stream monitoring is available, an audio power
3163 // save blocker should be created too.
3164 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3165 0, kPlayerAudioVideoId, true, true, false));
3166 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3167 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3168 !audio_state->IsAudioStateAvailable());
3170 // Crash the renderer.
3171 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
3173 // Verify that all the power save blockers have been released.
3174 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3175 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3178 TEST_F(WebContentsImplTest, ThemeColorChangeDependingOnFirstVisiblePaint) {
3179 TestWebContentsObserver observer(contents());
3180 TestRenderFrameHost* rfh = contents()->GetMainFrame();
3182 SkColor transparent = SK_ColorTRANSPARENT;
3184 EXPECT_EQ(transparent, contents()->GetThemeColor());
3185 EXPECT_EQ(transparent, observer.last_theme_color());
3187 // Theme color changes should not propagate past the WebContentsImpl before
3188 // the first visually non-empty paint has occurred.
3189 RenderViewHostTester::TestOnMessageReceived(
3190 test_rvh(),
3191 FrameHostMsg_DidChangeThemeColor(rfh->GetRoutingID(), SK_ColorRED));
3193 EXPECT_EQ(SK_ColorRED, contents()->GetThemeColor());
3194 EXPECT_EQ(transparent, observer.last_theme_color());
3196 // Simulate that the first visually non-empty paint has occurred. This will
3197 // propagate the current theme color to the delegates.
3198 RenderViewHostTester::TestOnMessageReceived(
3199 test_rvh(),
3200 FrameHostMsg_DidFirstVisuallyNonEmptyPaint(rfh->GetRoutingID()));
3202 EXPECT_EQ(SK_ColorRED, contents()->GetThemeColor());
3203 EXPECT_EQ(SK_ColorRED, observer.last_theme_color());
3205 // Additional changes made by the web contents should propagate as well.
3206 RenderViewHostTester::TestOnMessageReceived(
3207 test_rvh(),
3208 FrameHostMsg_DidChangeThemeColor(rfh->GetRoutingID(), SK_ColorGREEN));
3210 EXPECT_EQ(SK_ColorGREEN, contents()->GetThemeColor());
3211 EXPECT_EQ(SK_ColorGREEN, observer.last_theme_color());
3214 // Test that if a renderer reports that it has loaded a resource from
3215 // memory cache with bad security info (i.e. can't be deserialized), the
3216 // renderer gets killed.
3217 TEST_F(WebContentsImplTest, LoadResourceFromMemoryCacheWithBadSecurityInfo) {
3218 MockRenderProcessHost* rph = contents()->GetMainFrame()->GetProcess();
3219 EXPECT_EQ(0, rph->bad_msg_count());
3221 contents()->OnDidLoadResourceFromMemoryCache(
3222 GURL("http://example.test"), "not valid security info", "GET",
3223 "mime type", RESOURCE_TYPE_MAIN_FRAME);
3224 EXPECT_EQ(1, rph->bad_msg_count());
3227 } // namespace content