chrome/browser/extensions: Remove use of MessageLoopProxy and deprecated MessageLoop...
[chromium-blink-merge.git] / content / browser / web_contents / web_contents_impl_unittest.cc
blob309a91c31820ca14b1e4ab873b6347ddeefaf1a2
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/command_line.h"
6 #include "base/logging.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "content/browser/frame_host/cross_site_transferring_request.h"
9 #include "content/browser/frame_host/interstitial_page_impl.h"
10 #include "content/browser/frame_host/navigation_entry_impl.h"
11 #include "content/browser/frame_host/render_frame_host_impl.h"
12 #include "content/browser/media/audio_state_provider.h"
13 #include "content/browser/renderer_host/render_view_host_impl.h"
14 #include "content/browser/site_instance_impl.h"
15 #include "content/browser/webui/content_web_ui_controller_factory.h"
16 #include "content/browser/webui/web_ui_controller_factory_registry.h"
17 #include "content/common/frame_messages.h"
18 #include "content/common/input/synthetic_web_input_event_builders.h"
19 #include "content/common/view_messages.h"
20 #include "content/public/browser/global_request_id.h"
21 #include "content/public/browser/interstitial_page_delegate.h"
22 #include "content/public/browser/navigation_details.h"
23 #include "content/public/browser/notification_details.h"
24 #include "content/public/browser/notification_source.h"
25 #include "content/public/browser/render_widget_host_view.h"
26 #include "content/public/browser/web_contents_delegate.h"
27 #include "content/public/browser/web_contents_observer.h"
28 #include "content/public/browser/web_ui_controller.h"
29 #include "content/public/common/bindings_policy.h"
30 #include "content/public/common/content_constants.h"
31 #include "content/public/common/content_switches.h"
32 #include "content/public/common/url_constants.h"
33 #include "content/public/common/url_utils.h"
34 #include "content/public/test/mock_render_process_host.h"
35 #include "content/public/test/test_utils.h"
36 #include "content/test/test_content_browser_client.h"
37 #include "content/test/test_content_client.h"
38 #include "content/test/test_render_frame_host.h"
39 #include "content/test/test_render_view_host.h"
40 #include "content/test/test_web_contents.h"
41 #include "testing/gtest/include/gtest/gtest.h"
42 #include "third_party/skia/include/core/SkColor.h"
44 namespace content {
45 namespace {
47 class TestInterstitialPage;
49 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
50 public:
51 explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
52 : interstitial_page_(interstitial_page) {}
53 void CommandReceived(const std::string& command) override;
54 std::string GetHTMLContents() override { return std::string(); }
55 void OnDontProceed() override;
56 void OnProceed() override;
58 private:
59 TestInterstitialPage* interstitial_page_;
62 class TestInterstitialPage : public InterstitialPageImpl {
63 public:
64 enum InterstitialState {
65 INVALID = 0, // Hasn't yet been initialized.
66 UNDECIDED, // Initialized, but no decision taken yet.
67 OKED, // Proceed was called.
68 CANCELED // DontProceed was called.
71 class Delegate {
72 public:
73 virtual void TestInterstitialPageDeleted(
74 TestInterstitialPage* interstitial) = 0;
76 protected:
77 virtual ~Delegate() {}
80 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
81 // |deleted| (like all interstitial related tests do at this point), make sure
82 // to create an instance of the TestInterstitialPageStateGuard class on the
83 // stack in your test. This will ensure that the TestInterstitialPage states
84 // are cleared when the test finishes.
85 // Not doing so will cause stack trashing if your test does not hide the
86 // interstitial, as in such a case it will be destroyed in the test TearDown
87 // method and will dereference the |deleted| local variable which by then is
88 // out of scope.
89 TestInterstitialPage(WebContentsImpl* contents,
90 bool new_navigation,
91 const GURL& url,
92 InterstitialState* state,
93 bool* deleted)
94 : InterstitialPageImpl(
95 contents,
96 static_cast<RenderWidgetHostDelegate*>(contents),
97 new_navigation, url, new TestInterstitialPageDelegate(this)),
98 state_(state),
99 deleted_(deleted),
100 command_received_count_(0),
101 delegate_(nullptr) {
102 *state_ = UNDECIDED;
103 *deleted_ = false;
106 ~TestInterstitialPage() override {
107 if (deleted_)
108 *deleted_ = true;
109 if (delegate_)
110 delegate_->TestInterstitialPageDeleted(this);
113 void OnDontProceed() {
114 if (state_)
115 *state_ = CANCELED;
117 void OnProceed() {
118 if (state_)
119 *state_ = OKED;
122 int command_received_count() const {
123 return command_received_count_;
126 void TestDomOperationResponse(const std::string& json_string) {
127 if (enabled())
128 CommandReceived();
131 void TestDidNavigate(int page_id,
132 int nav_entry_id,
133 bool did_create_new_entry,
134 const GURL& url) {
135 FrameHostMsg_DidCommitProvisionalLoad_Params params;
136 InitNavigateParams(&params, page_id, nav_entry_id, did_create_new_entry,
137 url, ui::PAGE_TRANSITION_TYPED);
138 DidNavigate(GetMainFrame()->GetRenderViewHost(), params);
141 void TestRenderViewTerminated(base::TerminationStatus status,
142 int error_code) {
143 RenderViewTerminated(GetMainFrame()->GetRenderViewHost(), status,
144 error_code);
147 bool is_showing() const {
148 return static_cast<TestRenderWidgetHostView*>(
149 GetMainFrame()->GetRenderViewHost()->GetView())->is_showing();
152 void ClearStates() {
153 state_ = nullptr;
154 deleted_ = nullptr;
155 delegate_ = nullptr;
158 void CommandReceived() {
159 command_received_count_++;
162 void set_delegate(Delegate* delegate) {
163 delegate_ = delegate;
166 protected:
167 WebContentsView* CreateWebContentsView() override { return nullptr; }
169 private:
170 InterstitialState* state_;
171 bool* deleted_;
172 int command_received_count_;
173 Delegate* delegate_;
176 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
177 interstitial_page_->CommandReceived();
180 void TestInterstitialPageDelegate::OnDontProceed() {
181 interstitial_page_->OnDontProceed();
184 void TestInterstitialPageDelegate::OnProceed() {
185 interstitial_page_->OnProceed();
188 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
189 public:
190 explicit TestInterstitialPageStateGuard(
191 TestInterstitialPage* interstitial_page)
192 : interstitial_page_(interstitial_page) {
193 DCHECK(interstitial_page_);
194 interstitial_page_->set_delegate(this);
196 ~TestInterstitialPageStateGuard() override {
197 if (interstitial_page_)
198 interstitial_page_->ClearStates();
201 void TestInterstitialPageDeleted(
202 TestInterstitialPage* interstitial) override {
203 DCHECK(interstitial_page_ == interstitial);
204 interstitial_page_ = nullptr;
207 private:
208 TestInterstitialPage* interstitial_page_;
211 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
212 public:
213 WebContentsImplTestBrowserClient()
214 : assign_site_for_url_(false) {}
216 ~WebContentsImplTestBrowserClient() override {}
218 bool ShouldAssignSiteForURL(const GURL& url) override {
219 return assign_site_for_url_;
222 void set_assign_site_for_url(bool assign) {
223 assign_site_for_url_ = assign;
226 private:
227 bool assign_site_for_url_;
230 class WebContentsImplTest : public RenderViewHostImplTestHarness {
231 public:
232 void SetUp() override {
233 RenderViewHostImplTestHarness::SetUp();
234 WebUIControllerFactory::RegisterFactory(
235 ContentWebUIControllerFactory::GetInstance());
238 void TearDown() override {
239 WebUIControllerFactory::UnregisterFactoryForTesting(
240 ContentWebUIControllerFactory::GetInstance());
241 RenderViewHostImplTestHarness::TearDown();
245 class TestWebContentsObserver : public WebContentsObserver {
246 public:
247 explicit TestWebContentsObserver(WebContents* contents)
248 : WebContentsObserver(contents),
249 last_theme_color_(SK_ColorTRANSPARENT) {
251 ~TestWebContentsObserver() override {}
253 void DidFinishLoad(RenderFrameHost* render_frame_host,
254 const GURL& validated_url) override {
255 last_url_ = validated_url;
257 void DidFailLoad(RenderFrameHost* render_frame_host,
258 const GURL& validated_url,
259 int error_code,
260 const base::string16& error_description) override {
261 last_url_ = validated_url;
264 void DidChangeThemeColor(SkColor theme_color) override {
265 last_theme_color_ = theme_color;
268 const GURL& last_url() const { return last_url_; }
269 SkColor last_theme_color() const { return last_theme_color_; }
271 private:
272 GURL last_url_;
273 SkColor last_theme_color_;
275 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
278 // Pretends to be a normal browser that receives toggles and transitions to/from
279 // a fullscreened state.
280 class FakeFullscreenDelegate : public WebContentsDelegate {
281 public:
282 FakeFullscreenDelegate() : fullscreened_contents_(nullptr) {}
283 ~FakeFullscreenDelegate() override {}
285 void EnterFullscreenModeForTab(WebContents* web_contents,
286 const GURL& origin) override {
287 fullscreened_contents_ = web_contents;
290 void ExitFullscreenModeForTab(WebContents* web_contents) override {
291 fullscreened_contents_ = nullptr;
294 bool IsFullscreenForTabOrPending(
295 const WebContents* web_contents) const override {
296 return fullscreened_contents_ && web_contents == fullscreened_contents_;
299 private:
300 WebContents* fullscreened_contents_;
302 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate);
305 class FakeValidationMessageDelegate : public WebContentsDelegate {
306 public:
307 FakeValidationMessageDelegate()
308 : hide_validation_message_was_called_(false) {}
309 ~FakeValidationMessageDelegate() override {}
311 void HideValidationMessage(WebContents* web_contents) override {
312 hide_validation_message_was_called_ = true;
315 bool hide_validation_message_was_called() const {
316 return hide_validation_message_was_called_;
319 private:
320 bool hide_validation_message_was_called_;
322 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate);
325 } // namespace
327 // Test to make sure that title updates get stripped of whitespace.
328 TEST_F(WebContentsImplTest, UpdateTitle) {
329 NavigationControllerImpl& cont =
330 static_cast<NavigationControllerImpl&>(controller());
331 FrameHostMsg_DidCommitProvisionalLoad_Params params;
332 InitNavigateParams(&params, 0, 0, true, GURL(url::kAboutBlankURL),
333 ui::PAGE_TRANSITION_TYPED);
335 LoadCommittedDetails details;
336 cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
338 contents()->UpdateTitle(contents()->GetMainFrame(), 0,
339 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
340 base::i18n::LEFT_TO_RIGHT);
341 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
344 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
345 const GURL kGURL("chrome://blah");
346 controller().LoadURL(
347 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
348 EXPECT_EQ(base::string16(), contents()->GetTitle());
351 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
352 const GURL kGURL("chrome://blah");
353 const base::string16 title = base::ASCIIToUTF16("My Title");
354 controller().LoadURL(
355 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
357 NavigationEntry* entry = controller().GetVisibleEntry();
358 ASSERT_EQ(kGURL, entry->GetURL());
359 entry->SetTitle(title);
361 EXPECT_EQ(title, contents()->GetTitle());
364 // Test view source mode for a webui page.
365 TEST_F(WebContentsImplTest, NTPViewSource) {
366 NavigationControllerImpl& cont =
367 static_cast<NavigationControllerImpl&>(controller());
368 const char kUrl[] = "view-source:chrome://blah";
369 const GURL kGURL(kUrl);
371 process()->sink().ClearMessages();
373 cont.LoadURL(
374 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
375 int entry_id = cont.GetPendingEntry()->GetUniqueID();
376 rvh()->GetDelegate()->RenderViewCreated(rvh());
377 // Did we get the expected message?
378 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
379 ViewMsg_EnableViewSourceMode::ID));
381 FrameHostMsg_DidCommitProvisionalLoad_Params params;
382 InitNavigateParams(&params, 0, entry_id, true, kGURL,
383 ui::PAGE_TRANSITION_TYPED);
384 LoadCommittedDetails details;
385 cont.RendererDidNavigate(contents()->GetMainFrame(), params, &details);
386 // Also check title and url.
387 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
390 // Test to ensure UpdateMaxPageID is working properly.
391 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
392 SiteInstance* instance1 = contents()->GetSiteInstance();
393 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(nullptr));
395 // Starts at -1.
396 EXPECT_EQ(-1, contents()->GetMaxPageID());
397 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
398 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
400 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
401 contents()->UpdateMaxPageID(3);
402 contents()->UpdateMaxPageID(1);
403 EXPECT_EQ(3, contents()->GetMaxPageID());
404 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
405 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
407 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
408 EXPECT_EQ(3, contents()->GetMaxPageID());
409 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
410 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
413 // Test simple same-SiteInstance navigation.
414 TEST_F(WebContentsImplTest, SimpleNavigation) {
415 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
416 SiteInstance* instance1 = contents()->GetSiteInstance();
417 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
419 // Navigate to URL
420 const GURL url("http://www.google.com");
421 controller().LoadURL(
422 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
423 int entry_id = controller().GetPendingEntry()->GetUniqueID();
424 main_test_rfh()->PrepareForCommit();
425 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
426 EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
427 // Controller's pending entry will have a null site instance until we assign
428 // it in DidNavigate.
429 EXPECT_EQ(
430 nullptr,
431 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
432 site_instance());
434 // DidNavigate from the page
435 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
436 ui::PAGE_TRANSITION_TYPED);
437 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
438 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
439 EXPECT_EQ(instance1, orig_rfh->GetSiteInstance());
440 // Controller's entry should now have the SiteInstance, or else we won't be
441 // able to find it later.
442 EXPECT_EQ(
443 instance1,
444 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
445 site_instance());
448 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
449 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
450 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
451 const GURL url(std::string("http://example.org/").append(
452 GetMaxURLChars() + 1, 'a'));
454 controller().LoadURL(
455 url, Referrer(), ui::PAGE_TRANSITION_GENERATED, std::string());
456 EXPECT_EQ(nullptr, controller().GetVisibleEntry());
459 // Test that navigating across a site boundary creates a new RenderViewHost
460 // with a new SiteInstance. Going back should do the same.
461 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
462 bool is_site_per_process = base::CommandLine::ForCurrentProcess()->HasSwitch(
463 switches::kSitePerProcess);
464 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
465 int orig_rvh_delete_count = 0;
466 orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
467 SiteInstance* instance1 = contents()->GetSiteInstance();
469 // Navigate to URL. First URL should use first RenderViewHost.
470 const GURL url("http://www.google.com");
471 controller().LoadURL(
472 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
473 int entry_id = controller().GetPendingEntry()->GetUniqueID();
474 orig_rfh->PrepareForCommit();
475 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
476 ui::PAGE_TRANSITION_TYPED);
478 // Keep the number of active frames in orig_rfh's SiteInstance non-zero so
479 // that orig_rfh doesn't get deleted when it gets swapped out.
480 orig_rfh->GetSiteInstance()->increment_active_frame_count();
482 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
483 EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
484 EXPECT_EQ(url, contents()->GetLastCommittedURL());
485 EXPECT_EQ(url, contents()->GetVisibleURL());
487 // Navigate to new site
488 const GURL url2("http://www.yahoo.com");
489 controller().LoadURL(
490 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
491 entry_id = controller().GetPendingEntry()->GetUniqueID();
492 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
493 switches::kEnableBrowserSideNavigation)) {
494 orig_rfh->PrepareForCommit();
496 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
497 EXPECT_EQ(url, contents()->GetLastCommittedURL());
498 EXPECT_EQ(url2, contents()->GetVisibleURL());
499 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
500 int pending_rvh_delete_count = 0;
501 pending_rfh->GetRenderViewHost()->set_delete_counter(
502 &pending_rvh_delete_count);
504 // Navigations should be suspended in pending_rfh until BeforeUnloadACK.
505 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
506 switches::kEnableBrowserSideNavigation)) {
507 EXPECT_TRUE(pending_rfh->are_navigations_suspended());
508 orig_rfh->SendBeforeUnloadACK(true);
509 EXPECT_FALSE(pending_rfh->are_navigations_suspended());
512 // DidNavigate from the pending page
513 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
514 ui::PAGE_TRANSITION_TYPED);
515 SiteInstance* instance2 = contents()->GetSiteInstance();
517 // Keep the number of active frames in pending_rfh's SiteInstance
518 // non-zero so that orig_rfh doesn't get deleted when it gets
519 // swapped out.
520 pending_rfh->GetSiteInstance()->increment_active_frame_count();
522 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
523 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
524 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
525 EXPECT_EQ(url2, contents()->GetVisibleURL());
526 EXPECT_NE(instance1, instance2);
527 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
528 // We keep a proxy for the original RFH's SiteInstance.
529 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
530 orig_rfh->GetSiteInstance()));
531 EXPECT_EQ(orig_rvh_delete_count, 0);
533 // Going back should switch SiteInstances again. The first SiteInstance is
534 // stored in the NavigationEntry, so it should be the same as at the start.
535 // We should use the same RFH as before, swapping it back in.
536 controller().GoBack();
537 entry_id = controller().GetPendingEntry()->GetUniqueID();
538 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
539 switches::kEnableBrowserSideNavigation)) {
540 contents()->GetMainFrame()->PrepareForCommit();
542 TestRenderFrameHost* goback_rfh = contents()->GetPendingMainFrame();
543 if (!is_site_per_process)
544 EXPECT_EQ(orig_rfh, goback_rfh);
545 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
547 // Navigations should be suspended in goback_rfh until BeforeUnloadACK.
548 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
549 switches::kEnableBrowserSideNavigation)) {
550 EXPECT_TRUE(goback_rfh->are_navigations_suspended());
551 pending_rfh->SendBeforeUnloadACK(true);
552 EXPECT_FALSE(goback_rfh->are_navigations_suspended());
555 // DidNavigate from the back action
556 contents()->TestDidNavigate(goback_rfh, 1, entry_id, false, url2,
557 ui::PAGE_TRANSITION_TYPED);
558 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
559 EXPECT_EQ(goback_rfh, contents()->GetMainFrame());
560 EXPECT_EQ(instance1, contents()->GetSiteInstance());
561 // There should be a proxy for the pending RFH SiteInstance.
562 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
563 GetRenderFrameProxyHost(pending_rfh->GetSiteInstance()));
564 EXPECT_EQ(pending_rvh_delete_count, 0);
565 pending_rfh->OnSwappedOut();
567 // Close contents and ensure RVHs are deleted.
568 DeleteContents();
569 EXPECT_EQ(orig_rvh_delete_count, 1);
570 EXPECT_EQ(pending_rvh_delete_count, 1);
573 // Test that navigating across a site boundary after a crash creates a new
574 // RFH without requiring a cross-site transition (i.e., PENDING state).
575 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
576 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
578 int orig_rvh_delete_count = 0;
579 orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
580 SiteInstance* instance1 = contents()->GetSiteInstance();
582 // Navigate to URL. First URL should use first RenderViewHost.
583 const GURL url("http://www.google.com");
584 controller().LoadURL(
585 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
586 int entry_id = controller().GetPendingEntry()->GetUniqueID();
587 contents()->GetMainFrame()->PrepareForCommit();
588 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
589 ui::PAGE_TRANSITION_TYPED);
591 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
592 EXPECT_EQ(orig_rfh->GetRenderViewHost(), contents()->GetRenderViewHost());
594 // Simulate a renderer crash.
595 EXPECT_TRUE(orig_rfh->IsRenderFrameLive());
596 orig_rfh->GetProcess()->SimulateCrash();
597 EXPECT_FALSE(orig_rfh->IsRenderFrameLive());
599 // Navigate to new site. We should not go into PENDING.
600 const GURL url2("http://www.yahoo.com");
601 controller().LoadURL(
602 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
603 entry_id = controller().GetPendingEntry()->GetUniqueID();
604 contents()->GetMainFrame()->PrepareForCommit();
605 TestRenderFrameHost* new_rfh = contents()->GetMainFrame();
606 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
607 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
608 EXPECT_NE(orig_rfh, new_rfh);
609 EXPECT_EQ(orig_rvh_delete_count, 1);
611 // DidNavigate from the new page
612 contents()->TestDidNavigate(new_rfh, 1, entry_id, true, url2,
613 ui::PAGE_TRANSITION_TYPED);
614 SiteInstance* instance2 = contents()->GetSiteInstance();
616 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
617 EXPECT_EQ(new_rfh, main_rfh());
618 EXPECT_NE(instance1, instance2);
619 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
621 // Close contents and ensure RVHs are deleted.
622 DeleteContents();
623 EXPECT_EQ(orig_rvh_delete_count, 1);
626 // Test that opening a new contents in the same SiteInstance and then navigating
627 // both contentses to a new site will place both contentses in a single
628 // SiteInstance.
629 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
630 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
631 SiteInstance* instance1 = contents()->GetSiteInstance();
633 // Navigate to URL. First URL should use first RenderViewHost.
634 const GURL url("http://www.google.com");
635 controller().LoadURL(
636 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
637 int entry_id = controller().GetPendingEntry()->GetUniqueID();
638 contents()->GetMainFrame()->PrepareForCommit();
639 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
640 ui::PAGE_TRANSITION_TYPED);
642 // Open a new contents with the same SiteInstance, navigated to the same site.
643 scoped_ptr<TestWebContents> contents2(
644 TestWebContents::Create(browser_context(), instance1));
645 contents2->GetController().LoadURL(url, Referrer(),
646 ui::PAGE_TRANSITION_TYPED,
647 std::string());
648 entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
649 contents2->GetMainFrame()->PrepareForCommit();
650 // Need this page id to be 2 since the site instance is the same (which is the
651 // scope of page IDs) and we want to consider this a new page.
652 contents2->TestDidNavigate(contents2->GetMainFrame(), 2, entry_id, true, url,
653 ui::PAGE_TRANSITION_TYPED);
655 // Navigate first contents to a new site.
656 const GURL url2a("http://www.yahoo.com");
657 controller().LoadURL(
658 url2a, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
659 entry_id = controller().GetPendingEntry()->GetUniqueID();
660 orig_rfh->PrepareForCommit();
661 TestRenderFrameHost* pending_rfh_a = contents()->GetPendingMainFrame();
662 contents()->TestDidNavigate(pending_rfh_a, 1, entry_id, true, url2a,
663 ui::PAGE_TRANSITION_TYPED);
664 SiteInstance* instance2a = contents()->GetSiteInstance();
665 EXPECT_NE(instance1, instance2a);
667 // Navigate second contents to the same site as the first tab.
668 const GURL url2b("http://mail.yahoo.com");
669 contents2->GetController().LoadURL(url2b, Referrer(),
670 ui::PAGE_TRANSITION_TYPED,
671 std::string());
672 entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
673 TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
674 rfh2->PrepareForCommit();
675 TestRenderFrameHost* pending_rfh_b = contents2->GetPendingMainFrame();
676 EXPECT_NE(nullptr, pending_rfh_b);
677 EXPECT_TRUE(contents2->CrossProcessNavigationPending());
679 // NOTE(creis): We used to be in danger of showing a crash page here if the
680 // second contents hadn't navigated somewhere first (bug 1145430). That case
681 // is now covered by the CrossSiteBoundariesAfterCrash test.
682 contents2->TestDidNavigate(pending_rfh_b, 2, entry_id, true, url2b,
683 ui::PAGE_TRANSITION_TYPED);
684 SiteInstance* instance2b = contents2->GetSiteInstance();
685 EXPECT_NE(instance1, instance2b);
687 // Both contentses should now be in the same SiteInstance.
688 EXPECT_EQ(instance2a, instance2b);
691 // The embedder can request sites for certain urls not be be assigned to the
692 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
693 // allowing to reuse the renderer backing certain chrome urls for subsequent
694 // navigation. The test verifies that the override is honored.
695 TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
696 WebContentsImplTestBrowserClient browser_client;
697 SetBrowserClientForTesting(&browser_client);
699 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
700 int orig_rvh_delete_count = 0;
701 orig_rfh->GetRenderViewHost()->set_delete_counter(&orig_rvh_delete_count);
702 SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
704 browser_client.set_assign_site_for_url(false);
705 // Navigate to an URL that will not assign a new SiteInstance.
706 const GURL native_url("non-site-url://stuffandthings");
707 controller().LoadURL(
708 native_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
709 int entry_id = controller().GetPendingEntry()->GetUniqueID();
710 contents()->GetMainFrame()->PrepareForCommit();
711 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, native_url,
712 ui::PAGE_TRANSITION_TYPED);
714 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
715 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
716 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
717 EXPECT_EQ(native_url, contents()->GetVisibleURL());
718 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
719 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
720 EXPECT_FALSE(orig_instance->HasSite());
722 browser_client.set_assign_site_for_url(true);
723 // Navigate to new site (should keep same site instance).
724 const GURL url("http://www.google.com");
725 controller().LoadURL(
726 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
727 entry_id = controller().GetPendingEntry()->GetUniqueID();
728 contents()->GetMainFrame()->PrepareForCommit();
729 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
730 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
731 EXPECT_EQ(url, contents()->GetVisibleURL());
732 EXPECT_FALSE(contents()->GetPendingMainFrame());
733 contents()->TestDidNavigate(orig_rfh, 2, entry_id, true, url,
734 ui::PAGE_TRANSITION_TYPED);
736 // Keep the number of active frames in orig_rfh's SiteInstance
737 // non-zero so that orig_rfh doesn't get deleted when it gets
738 // swapped out.
739 orig_rfh->GetSiteInstance()->increment_active_frame_count();
741 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
742 EXPECT_TRUE(
743 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
744 EXPECT_EQ(url, contents()->GetLastCommittedURL());
746 // Navigate to another new site (should create a new site instance).
747 const GURL url2("http://www.yahoo.com");
748 controller().LoadURL(
749 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
750 entry_id = controller().GetPendingEntry()->GetUniqueID();
751 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
752 switches::kEnableBrowserSideNavigation)) {
753 orig_rfh->PrepareForCommit();
755 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
756 EXPECT_EQ(url, contents()->GetLastCommittedURL());
757 EXPECT_EQ(url2, contents()->GetVisibleURL());
758 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
759 int pending_rvh_delete_count = 0;
760 pending_rfh->GetRenderViewHost()->set_delete_counter(
761 &pending_rvh_delete_count);
763 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
764 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
765 switches::kEnableBrowserSideNavigation)) {
766 EXPECT_TRUE(pending_rfh->are_navigations_suspended());
767 orig_rfh->SendBeforeUnloadACK(true);
768 EXPECT_FALSE(pending_rfh->are_navigations_suspended());
771 // DidNavigate from the pending page.
772 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
773 ui::PAGE_TRANSITION_TYPED);
774 SiteInstance* new_instance = contents()->GetSiteInstance();
776 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
777 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
778 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
779 EXPECT_EQ(url2, contents()->GetVisibleURL());
780 EXPECT_NE(new_instance, orig_instance);
781 EXPECT_FALSE(contents()->GetPendingMainFrame());
782 // We keep a proxy for the original RFH's SiteInstance.
783 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->GetRenderFrameProxyHost(
784 orig_rfh->GetSiteInstance()));
785 EXPECT_EQ(orig_rvh_delete_count, 0);
786 orig_rfh->OnSwappedOut();
788 // Close contents and ensure RVHs are deleted.
789 DeleteContents();
790 EXPECT_EQ(orig_rvh_delete_count, 1);
791 EXPECT_EQ(pending_rvh_delete_count, 1);
794 // Regression test for http://crbug.com/386542 - variation of
795 // NavigateFromSitelessUrl in which the original navigation is a session
796 // restore.
797 TEST_F(WebContentsImplTest, NavigateFromRestoredSitelessUrl) {
798 WebContentsImplTestBrowserClient browser_client;
799 SetBrowserClientForTesting(&browser_client);
800 SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
801 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
803 // Restore a navigation entry for URL that should not assign site to the
804 // SiteInstance.
805 browser_client.set_assign_site_for_url(false);
806 const GURL native_url("non-site-url://stuffandthings");
807 std::vector<NavigationEntry*> entries;
808 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
809 native_url, Referrer(), ui::PAGE_TRANSITION_LINK, false, std::string(),
810 browser_context());
811 entry->SetPageID(0);
812 entries.push_back(entry);
813 controller().Restore(
815 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
816 &entries);
817 ASSERT_EQ(0u, entries.size());
818 ASSERT_EQ(1, controller().GetEntryCount());
819 controller().GoToIndex(0);
820 entry = controller().GetPendingEntry();
821 orig_rfh->PrepareForCommit();
822 contents()->TestDidNavigate(orig_rfh, 0, entry->GetUniqueID(), false,
823 native_url, ui::PAGE_TRANSITION_RELOAD);
824 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
825 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
826 EXPECT_FALSE(orig_instance->HasSite());
828 // Navigate to a regular site and verify that the SiteInstance was kept.
829 browser_client.set_assign_site_for_url(true);
830 const GURL url("http://www.google.com");
831 controller().LoadURL(
832 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
833 entry = controller().GetPendingEntry();
834 orig_rfh->PrepareForCommit();
835 contents()->TestDidNavigate(orig_rfh, 2, entry->GetUniqueID(), true, url,
836 ui::PAGE_TRANSITION_TYPED);
837 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
839 // Cleanup.
840 DeleteContents();
843 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
844 // tab is restored, the SiteInstance will change upon navigation.
845 TEST_F(WebContentsImplTest, NavigateFromRestoredRegularUrl) {
846 WebContentsImplTestBrowserClient browser_client;
847 SetBrowserClientForTesting(&browser_client);
848 SiteInstanceImpl* orig_instance = contents()->GetSiteInstance();
849 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
851 // Restore a navigation entry for a regular URL ensuring that the embedder
852 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
853 browser_client.set_assign_site_for_url(true);
854 const GURL regular_url("http://www.yahoo.com");
855 std::vector<NavigationEntry*> entries;
856 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
857 regular_url, Referrer(), ui::PAGE_TRANSITION_LINK, false, std::string(),
858 browser_context());
859 entry->SetPageID(0);
860 entries.push_back(entry);
861 controller().Restore(
863 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
864 &entries);
865 ASSERT_EQ(0u, entries.size());
866 ASSERT_EQ(1, controller().GetEntryCount());
867 controller().GoToIndex(0);
868 entry = controller().GetPendingEntry();
869 orig_rfh->PrepareForCommit();
870 contents()->TestDidNavigate(orig_rfh, 0, entry->GetUniqueID(), false,
871 regular_url, ui::PAGE_TRANSITION_RELOAD);
872 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
873 EXPECT_TRUE(orig_instance->HasSite());
875 // Navigate to another site and verify that a new SiteInstance was created.
876 const GURL url("http://www.google.com");
877 controller().LoadURL(
878 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
879 entry = controller().GetPendingEntry();
880 orig_rfh->PrepareForCommit();
881 contents()->TestDidNavigate(contents()->GetPendingMainFrame(), 2,
882 entry->GetUniqueID(), true, url,
883 ui::PAGE_TRANSITION_TYPED);
884 EXPECT_NE(orig_instance, contents()->GetSiteInstance());
886 // Cleanup.
887 DeleteContents();
890 // Test that we can find an opener RVH even if it's pending.
891 // http://crbug.com/176252.
892 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
893 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
895 // Navigate to a URL.
896 const GURL url("http://www.google.com");
897 controller().LoadURL(
898 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
899 int entry_id = controller().GetPendingEntry()->GetUniqueID();
900 orig_rfh->PrepareForCommit();
901 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
902 ui::PAGE_TRANSITION_TYPED);
904 // Start to navigate first tab to a new site, so that it has a pending RVH.
905 const GURL url2("http://www.yahoo.com");
906 controller().LoadURL(
907 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
908 orig_rfh->PrepareForCommit();
909 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
911 // While it is still pending, simulate opening a new tab with the first tab
912 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
913 // on the opener to ensure that an RVH exists.
914 int opener_routing_id =
915 contents()->CreateOpenerRenderViews(pending_rfh->GetSiteInstance());
917 // We should find the pending RVH and not create a new one.
918 EXPECT_EQ(pending_rfh->GetRenderViewHost()->GetRoutingID(),
919 opener_routing_id);
922 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
923 // to determine whether a navigation is cross-site.
924 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
925 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
926 SiteInstance* instance1 = contents()->GetSiteInstance();
928 // Navigate to URL.
929 const GURL url("http://www.google.com");
930 controller().LoadURL(
931 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
932 int entry_id = controller().GetPendingEntry()->GetUniqueID();
933 contents()->GetMainFrame()->PrepareForCommit();
934 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
935 ui::PAGE_TRANSITION_TYPED);
937 // Open a related contents to a second site.
938 scoped_ptr<TestWebContents> contents2(
939 TestWebContents::Create(browser_context(), instance1));
940 const GURL url2("http://www.yahoo.com");
941 contents2->GetController().LoadURL(url2, Referrer(),
942 ui::PAGE_TRANSITION_TYPED,
943 std::string());
944 entry_id = contents2->GetController().GetPendingEntry()->GetUniqueID();
945 contents2->GetMainFrame()->PrepareForCommit();
947 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
948 // pending.
949 TestRenderFrameHost* rfh2 = contents2->GetMainFrame();
950 EXPECT_FALSE(contents2->CrossProcessNavigationPending());
951 contents2->TestDidNavigate(rfh2, 2, entry_id, true, url2,
952 ui::PAGE_TRANSITION_TYPED);
953 SiteInstance* instance2 = contents2->GetSiteInstance();
954 EXPECT_NE(instance1, instance2);
955 EXPECT_FALSE(contents2->CrossProcessNavigationPending());
957 // Simulate a link click in first contents to second site. Doesn't switch
958 // SiteInstances, because we don't intercept Blink navigations.
959 orig_rfh->SendRendererInitiatedNavigationRequest(url2, true);
960 orig_rfh->PrepareForCommit();
961 contents()->TestDidNavigate(orig_rfh, 2, 0, true, url2,
962 ui::PAGE_TRANSITION_TYPED);
963 SiteInstance* instance3 = contents()->GetSiteInstance();
964 EXPECT_EQ(instance1, instance3);
965 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
967 // Navigate to the new site. Doesn't switch SiteInstancees, because we
968 // compare against the current URL, not the SiteInstance's site.
969 const GURL url3("http://mail.yahoo.com");
970 controller().LoadURL(
971 url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
972 entry_id = controller().GetPendingEntry()->GetUniqueID();
973 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
974 contents()->GetMainFrame()->PrepareForCommit();
975 contents()->TestDidNavigate(orig_rfh, 3, entry_id, true, url3,
976 ui::PAGE_TRANSITION_TYPED);
977 SiteInstance* instance4 = contents()->GetSiteInstance();
978 EXPECT_EQ(instance1, instance4);
981 // Test that the onbeforeunload and onunload handlers run when navigating
982 // across site boundaries.
983 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
984 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
985 SiteInstance* instance1 = contents()->GetSiteInstance();
987 // Navigate to URL. First URL should use first RenderViewHost.
988 const GURL url("http://www.google.com");
989 controller().LoadURL(
990 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
991 int entry_id = controller().GetPendingEntry()->GetUniqueID();
992 contents()->GetMainFrame()->PrepareForCommit();
993 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
994 ui::PAGE_TRANSITION_TYPED);
995 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
996 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
998 // Navigate to new site, but simulate an onbeforeunload denial.
999 const GURL url2("http://www.yahoo.com");
1000 controller().LoadURL(
1001 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1002 EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
1003 base::TimeTicks now = base::TimeTicks::Now();
1004 orig_rfh->OnMessageReceived(
1005 FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
1006 EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
1007 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1008 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1010 // Navigate again, but simulate an onbeforeunload approval.
1011 controller().LoadURL(
1012 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1013 entry_id = controller().GetPendingEntry()->GetUniqueID();
1014 EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
1015 now = base::TimeTicks::Now();
1016 orig_rfh->PrepareForCommit();
1017 EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
1018 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1019 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
1021 // We won't hear DidNavigate until the onunload handler has finished running.
1023 // DidNavigate from the pending page.
1024 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
1025 ui::PAGE_TRANSITION_TYPED);
1026 SiteInstance* instance2 = contents()->GetSiteInstance();
1027 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1028 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
1029 EXPECT_NE(instance1, instance2);
1030 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1033 // Test that during a slow cross-site navigation, the original renderer can
1034 // navigate to a different URL and have it displayed, canceling the slow
1035 // navigation.
1036 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
1037 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1038 SiteInstance* instance1 = contents()->GetSiteInstance();
1040 // Navigate to URL. First URL should use first RenderFrameHost.
1041 const GURL url("http://www.google.com");
1042 controller().LoadURL(
1043 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1044 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1045 contents()->GetMainFrame()->PrepareForCommit();
1046 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1047 ui::PAGE_TRANSITION_TYPED);
1048 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1049 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1051 // Navigate to new site, simulating an onbeforeunload approval.
1052 const GURL url2("http://www.yahoo.com");
1053 controller().LoadURL(
1054 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1055 EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
1056 orig_rfh->PrepareForCommit();
1057 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1059 // Suppose the original renderer navigates before the new one is ready.
1060 orig_rfh->SendNavigate(2, 0, true, GURL("http://www.google.com/foo"));
1062 // Verify that the pending navigation is cancelled.
1063 EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
1064 SiteInstance* instance2 = contents()->GetSiteInstance();
1065 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1066 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1067 EXPECT_EQ(instance1, instance2);
1068 EXPECT_EQ(nullptr, contents()->GetPendingMainFrame());
1071 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
1072 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1073 const GURL url1("chrome://gpu");
1074 controller().LoadURL(
1075 url1, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1076 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1077 TestRenderFrameHost* ntp_rfh = contents()->GetMainFrame();
1078 ntp_rfh->PrepareForCommit();
1079 contents()->TestDidNavigate(ntp_rfh, 1, entry_id, true, url1,
1080 ui::PAGE_TRANSITION_TYPED);
1081 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
1082 SiteInstance* instance1 = contents()->GetSiteInstance();
1084 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1085 EXPECT_EQ(ntp_rfh, contents()->GetMainFrame());
1086 EXPECT_EQ(url1, entry1->GetURL());
1087 EXPECT_EQ(instance1,
1088 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1089 EXPECT_TRUE(ntp_rfh->GetRenderViewHost()->GetEnabledBindings() &
1090 BINDINGS_POLICY_WEB_UI);
1092 // Navigate to new site.
1093 const GURL url2("http://www.google.com");
1094 controller().LoadURL(
1095 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1096 entry_id = controller().GetPendingEntry()->GetUniqueID();
1097 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1098 TestRenderFrameHost* google_rfh = contents()->GetPendingMainFrame();
1100 // Simulate beforeunload approval.
1101 EXPECT_TRUE(ntp_rfh->IsWaitingForBeforeUnloadACK());
1102 base::TimeTicks now = base::TimeTicks::Now();
1103 ntp_rfh->PrepareForCommit();
1105 // DidNavigate from the pending page.
1106 contents()->TestDidNavigate(google_rfh, 1, entry_id, true, url2,
1107 ui::PAGE_TRANSITION_TYPED);
1108 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
1109 SiteInstance* instance2 = contents()->GetSiteInstance();
1111 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1112 EXPECT_EQ(google_rfh, contents()->GetMainFrame());
1113 EXPECT_NE(instance1, instance2);
1114 EXPECT_FALSE(contents()->GetPendingMainFrame());
1115 EXPECT_EQ(url2, entry2->GetURL());
1116 EXPECT_EQ(instance2,
1117 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1118 EXPECT_FALSE(google_rfh->GetRenderViewHost()->GetEnabledBindings() &
1119 BINDINGS_POLICY_WEB_UI);
1121 // Navigate to third page on same site.
1122 const GURL url3("http://news.google.com");
1123 controller().LoadURL(
1124 url3, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1125 entry_id = controller().GetPendingEntry()->GetUniqueID();
1126 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1127 contents()->GetMainFrame()->PrepareForCommit();
1128 contents()->TestDidNavigate(google_rfh, 2, entry_id, true, url3,
1129 ui::PAGE_TRANSITION_TYPED);
1130 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
1131 SiteInstance* instance3 = contents()->GetSiteInstance();
1133 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1134 EXPECT_EQ(google_rfh, contents()->GetMainFrame());
1135 EXPECT_EQ(instance2, instance3);
1136 EXPECT_FALSE(contents()->GetPendingMainFrame());
1137 EXPECT_EQ(url3, entry3->GetURL());
1138 EXPECT_EQ(instance3,
1139 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1141 // Go back within the site.
1142 controller().GoBack();
1143 NavigationEntry* goback_entry = controller().GetPendingEntry();
1144 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1145 EXPECT_EQ(entry2, controller().GetPendingEntry());
1147 // Before that commits, go back again.
1148 controller().GoBack();
1149 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1150 EXPECT_TRUE(contents()->GetPendingMainFrame());
1151 EXPECT_EQ(entry1, controller().GetPendingEntry());
1153 // Simulate beforeunload approval.
1154 EXPECT_TRUE(google_rfh->IsWaitingForBeforeUnloadACK());
1155 now = base::TimeTicks::Now();
1156 google_rfh->PrepareForCommit();
1157 google_rfh->OnMessageReceived(
1158 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1160 // DidNavigate from the first back. This aborts the second back's pending RFH.
1161 contents()->TestDidNavigate(google_rfh, 1, goback_entry->GetUniqueID(), false,
1162 url2, ui::PAGE_TRANSITION_TYPED);
1164 // We should commit this page and forget about the second back.
1165 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1166 EXPECT_FALSE(controller().GetPendingEntry());
1167 EXPECT_EQ(google_rfh, contents()->GetMainFrame());
1168 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
1170 // We should not have corrupted the NTP entry.
1171 EXPECT_EQ(instance3,
1172 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1173 EXPECT_EQ(instance2,
1174 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1175 EXPECT_EQ(instance1,
1176 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1177 EXPECT_EQ(url1, entry1->GetURL());
1180 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1181 // original renderer will not cancel the slow navigation (bug 42029).
1182 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
1183 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1185 // Navigate to URL. First URL should use the original RenderFrameHost.
1186 const GURL url("http://www.google.com");
1187 controller().LoadURL(
1188 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1189 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1190 contents()->GetMainFrame()->PrepareForCommit();
1191 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1192 ui::PAGE_TRANSITION_TYPED);
1193 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1194 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1196 // Start navigating to new site.
1197 const GURL url2("http://www.yahoo.com");
1198 controller().LoadURL(
1199 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1201 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1202 // waiting for a before unload response.
1203 TestRenderFrameHost* child_rfh = orig_rfh->AppendChild("subframe");
1204 child_rfh->SendNavigateWithTransition(1, 0, false,
1205 GURL("http://google.com/frame"),
1206 ui::PAGE_TRANSITION_AUTO_SUBFRAME);
1207 EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
1209 // Now simulate the onbeforeunload approval and verify the navigation is
1210 // not canceled.
1211 orig_rfh->PrepareForCommit();
1212 EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
1213 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1216 // Test that a cross-site navigation is not preempted if the previous
1217 // renderer sends a FrameNavigate message just before being told to stop.
1218 // We should only preempt the cross-site navigation if the previous renderer
1219 // has started a new navigation. See http://crbug.com/79176.
1220 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1221 // Navigate to WebUI URL.
1222 const GURL url("chrome://gpu");
1223 controller().LoadURL(
1224 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1225 int entry1_id = controller().GetPendingEntry()->GetUniqueID();
1226 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1227 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1229 // Navigate to new site, with the beforeunload request in flight.
1230 const GURL url2("http://www.yahoo.com");
1231 controller().LoadURL(
1232 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1233 int entry2_id = controller().GetPendingEntry()->GetUniqueID();
1234 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
1235 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1236 EXPECT_TRUE(orig_rfh->IsWaitingForBeforeUnloadACK());
1238 // Suppose the first navigation tries to commit now, with a
1239 // FrameMsg_Stop in flight. This should not cancel the pending navigation,
1240 // but it should act as if the beforeunload ack arrived.
1241 orig_rfh->SendNavigate(1, entry1_id, true, GURL("chrome://gpu"));
1242 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
1243 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1244 EXPECT_FALSE(orig_rfh->IsWaitingForBeforeUnloadACK());
1246 // The pending navigation should be able to commit successfully.
1247 contents()->TestDidNavigate(pending_rfh, 1, entry2_id, true, url2,
1248 ui::PAGE_TRANSITION_TYPED);
1249 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1250 EXPECT_EQ(pending_rfh, contents()->GetMainFrame());
1253 // Test that NavigationEntries have the correct page state after going
1254 // forward and back. Prevents regression for bug 1116137.
1255 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1256 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1258 // Navigate to URL. There should be no committed entry yet.
1259 const GURL url("http://www.google.com");
1260 controller().LoadURL(
1261 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1262 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1263 NavigationEntry* entry = controller().GetLastCommittedEntry();
1264 EXPECT_EQ(nullptr, entry);
1266 // Committed entry should have page state after DidNavigate.
1267 orig_rfh->PrepareForCommit();
1268 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1269 ui::PAGE_TRANSITION_TYPED);
1270 entry = controller().GetLastCommittedEntry();
1271 EXPECT_TRUE(entry->GetPageState().IsValid());
1273 // Navigate to same site.
1274 const GURL url2("http://images.google.com");
1275 controller().LoadURL(
1276 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1277 entry_id = controller().GetPendingEntry()->GetUniqueID();
1278 entry = controller().GetLastCommittedEntry();
1279 EXPECT_TRUE(entry->GetPageState().IsValid());
1281 // Committed entry should have page state after DidNavigate.
1282 orig_rfh->PrepareForCommit();
1283 contents()->TestDidNavigate(orig_rfh, 2, entry_id, true, url2,
1284 ui::PAGE_TRANSITION_TYPED);
1285 entry = controller().GetLastCommittedEntry();
1286 EXPECT_TRUE(entry->GetPageState().IsValid());
1288 // Now go back. Committed entry should still have page state.
1289 controller().GoBack();
1290 entry_id = controller().GetPendingEntry()->GetUniqueID();
1291 orig_rfh->PrepareForCommit();
1292 contents()->TestDidNavigate(orig_rfh, 1, entry_id, false, url,
1293 ui::PAGE_TRANSITION_TYPED);
1294 entry = controller().GetLastCommittedEntry();
1295 EXPECT_TRUE(entry->GetPageState().IsValid());
1298 // Test that NavigationEntries have the correct page state and SiteInstance
1299 // state after opening a new window to about:blank. Prevents regression for
1300 // bugs b/1116137 and http://crbug.com/111975.
1301 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1302 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1304 // Navigate to about:blank.
1305 const GURL url(url::kAboutBlankURL);
1306 orig_rfh->SendRendererInitiatedNavigationRequest(url, false);
1307 orig_rfh->PrepareForCommit();
1308 contents()->TestDidNavigate(orig_rfh, 1, 0, true, url,
1309 ui::PAGE_TRANSITION_TYPED);
1311 // Should have a page state here.
1312 NavigationEntry* entry = controller().GetLastCommittedEntry();
1313 EXPECT_TRUE(entry->GetPageState().IsValid());
1315 // The SiteInstance should be available for other navigations to use.
1316 NavigationEntryImpl* entry_impl =
1317 NavigationEntryImpl::FromNavigationEntry(entry);
1318 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1319 int32 site_instance_id = entry_impl->site_instance()->GetId();
1321 // Navigating to a normal page should not cause a process swap.
1322 const GURL new_url("http://www.google.com");
1323 controller().LoadURL(new_url, Referrer(),
1324 ui::PAGE_TRANSITION_TYPED, std::string());
1325 entry = controller().GetPendingEntry();
1326 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1327 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1328 orig_rfh->PrepareForCommit();
1329 contents()->TestDidNavigate(orig_rfh, 2, entry->GetUniqueID(), true, new_url,
1330 ui::PAGE_TRANSITION_TYPED);
1331 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1332 controller().GetLastCommittedEntry());
1333 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1334 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1337 // Tests that fullscreen is exited throughout the object hierarchy when
1338 // navigating to a new page.
1339 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
1340 FakeFullscreenDelegate fake_delegate;
1341 contents()->SetDelegate(&fake_delegate);
1342 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
1343 TestRenderViewHost* orig_rvh = orig_rfh->GetRenderViewHost();
1345 // Navigate to a site.
1346 const GURL url("http://www.google.com");
1347 controller().LoadURL(
1348 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1349 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1350 contents()->GetMainFrame()->PrepareForCommit();
1351 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1352 ui::PAGE_TRANSITION_TYPED);
1353 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1355 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1356 EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
1357 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1358 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1359 orig_rfh->OnMessageReceived(
1360 FrameHostMsg_ToggleFullscreen(orig_rfh->GetRoutingID(), true));
1361 EXPECT_TRUE(orig_rvh->IsFullscreenGranted());
1362 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1363 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1365 // Navigate to a new site.
1366 const GURL url2("http://www.yahoo.com");
1367 controller().LoadURL(
1368 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1369 entry_id = controller().GetPendingEntry()->GetUniqueID();
1370 contents()->GetMainFrame()->PrepareForCommit();
1371 TestRenderFrameHost* const pending_rfh = contents()->GetPendingMainFrame();
1372 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, url2,
1373 ui::PAGE_TRANSITION_TYPED);
1375 // Confirm fullscreen has exited.
1376 EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
1377 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1378 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1380 contents()->SetDelegate(nullptr);
1383 // Tests that fullscreen is exited throughout the object hierarchy when
1384 // instructing NavigationController to GoBack() or GoForward().
1385 TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
1386 FakeFullscreenDelegate fake_delegate;
1387 contents()->SetDelegate(&fake_delegate);
1388 TestRenderFrameHost* const orig_rfh = contents()->GetMainFrame();
1389 TestRenderViewHost* const orig_rvh = orig_rfh->GetRenderViewHost();
1391 // Navigate to a site.
1392 const GURL url("http://www.google.com");
1393 controller().LoadURL(
1394 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1395 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1396 orig_rfh->PrepareForCommit();
1397 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, url,
1398 ui::PAGE_TRANSITION_TYPED);
1399 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1401 // Now, navigate to another page on the same site.
1402 const GURL url2("http://www.google.com/search?q=kittens");
1403 controller().LoadURL(
1404 url2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1405 entry_id = controller().GetPendingEntry()->GetUniqueID();
1406 orig_rfh->PrepareForCommit();
1407 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1408 contents()->TestDidNavigate(orig_rfh, 2, entry_id, true, url2,
1409 ui::PAGE_TRANSITION_TYPED);
1410 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1412 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1413 EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
1414 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1415 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1417 for (int i = 0; i < 2; ++i) {
1418 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1419 orig_rfh->OnMessageReceived(
1420 FrameHostMsg_ToggleFullscreen(orig_rfh->GetRoutingID(), true));
1421 EXPECT_TRUE(orig_rvh->IsFullscreenGranted());
1422 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1423 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1425 // Navigate backward (or forward).
1426 if (i == 0)
1427 controller().GoBack();
1428 else
1429 controller().GoForward();
1430 entry_id = controller().GetPendingEntry()->GetUniqueID();
1431 orig_rfh->PrepareForCommit();
1432 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
1433 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
1434 contents()->TestDidNavigate(orig_rfh, i + 1, entry_id, false, url,
1435 ui::PAGE_TRANSITION_FORWARD_BACK);
1437 // Confirm fullscreen has exited.
1438 EXPECT_FALSE(orig_rvh->IsFullscreenGranted());
1439 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1440 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1443 contents()->SetDelegate(nullptr);
1446 TEST_F(WebContentsImplTest, TerminateHidesValidationMessage) {
1447 FakeValidationMessageDelegate fake_delegate;
1448 contents()->SetDelegate(&fake_delegate);
1449 EXPECT_FALSE(fake_delegate.hide_validation_message_was_called());
1451 // Initialize the RenderFrame and then simulate crashing the renderer
1452 // process.
1453 contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
1454 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1456 // Confirm HideValidationMessage was called.
1457 EXPECT_TRUE(fake_delegate.hide_validation_message_was_called());
1459 contents()->SetDelegate(nullptr);
1462 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1463 // crash.
1464 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
1465 FakeFullscreenDelegate fake_delegate;
1466 contents()->SetDelegate(&fake_delegate);
1468 // Navigate to a site.
1469 const GURL url("http://www.google.com");
1470 controller().LoadURL(
1471 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
1472 int entry_id = controller().GetPendingEntry()->GetUniqueID();
1473 main_test_rfh()->PrepareForCommit();
1474 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id, true,
1475 url, ui::PAGE_TRANSITION_TYPED);
1477 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1478 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1479 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1480 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1481 contents()->GetMainFrame()->OnMessageReceived(FrameHostMsg_ToggleFullscreen(
1482 contents()->GetMainFrame()->GetRoutingID(), true));
1483 EXPECT_TRUE(test_rvh()->IsFullscreenGranted());
1484 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1485 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1487 // Crash the renderer.
1488 main_test_rfh()->GetProcess()->SimulateCrash();
1490 // Confirm fullscreen has exited.
1491 EXPECT_FALSE(test_rvh()->IsFullscreenGranted());
1492 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1493 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1495 contents()->SetDelegate(nullptr);
1498 ////////////////////////////////////////////////////////////////////////////////
1499 // Interstitial Tests
1500 ////////////////////////////////////////////////////////////////////////////////
1502 // Test navigating to a page (with the navigation initiated from the browser,
1503 // as when a URL is typed in the location bar) that shows an interstitial and
1504 // creates a new navigation entry, then hiding it without proceeding.
1505 TEST_F(WebContentsImplTest,
1506 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1507 // Navigate to a page.
1508 GURL url1("http://www.google.com");
1509 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1510 EXPECT_EQ(1, controller().GetEntryCount());
1512 // Initiate a browser navigation that will trigger the interstitial.
1513 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1514 ui::PAGE_TRANSITION_TYPED, std::string());
1515 NavigationEntry* entry = controller().GetPendingEntry();
1517 // Show an interstitial.
1518 TestInterstitialPage::InterstitialState state =
1519 TestInterstitialPage::INVALID;
1520 bool deleted = false;
1521 GURL url2("http://interstitial");
1522 TestInterstitialPage* interstitial =
1523 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1524 TestInterstitialPageStateGuard state_guard(interstitial);
1525 interstitial->Show();
1526 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1527 // The interstitial should not show until its navigation has committed.
1528 EXPECT_FALSE(interstitial->is_showing());
1529 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1530 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1531 // Let's commit the interstitial navigation.
1532 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
1533 EXPECT_TRUE(interstitial->is_showing());
1534 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1535 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1536 entry = controller().GetVisibleEntry();
1537 ASSERT_NE(nullptr, entry);
1538 EXPECT_TRUE(entry->GetURL() == url2);
1540 // Now don't proceed.
1541 interstitial->DontProceed();
1542 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1543 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1544 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1545 entry = controller().GetVisibleEntry();
1546 ASSERT_NE(nullptr, entry);
1547 EXPECT_TRUE(entry->GetURL() == url1);
1548 EXPECT_EQ(1, controller().GetEntryCount());
1550 RunAllPendingInMessageLoop();
1551 EXPECT_TRUE(deleted);
1554 // Test navigating to a page (with the navigation initiated from the renderer,
1555 // as when clicking on a link in the page) that shows an interstitial and
1556 // creates a new navigation entry, then hiding it without proceeding.
1557 TEST_F(WebContentsImplTest,
1558 ShowInterstitialFromRendererWithNewNavigationDontProceed) {
1559 // Navigate to a page.
1560 GURL url1("http://www.google.com");
1561 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1562 EXPECT_EQ(1, controller().GetEntryCount());
1564 // Show an interstitial (no pending entry, the interstitial would have been
1565 // triggered by clicking on a link).
1566 TestInterstitialPage::InterstitialState state =
1567 TestInterstitialPage::INVALID;
1568 bool deleted = false;
1569 GURL url2("http://interstitial");
1570 TestInterstitialPage* interstitial =
1571 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1572 TestInterstitialPageStateGuard state_guard(interstitial);
1573 interstitial->Show();
1574 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1575 // The interstitial should not show until its navigation has committed.
1576 EXPECT_FALSE(interstitial->is_showing());
1577 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1578 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1579 // Let's commit the interstitial navigation.
1580 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
1581 EXPECT_TRUE(interstitial->is_showing());
1582 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1583 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1584 NavigationEntry* entry = controller().GetVisibleEntry();
1585 ASSERT_NE(nullptr, entry);
1586 EXPECT_TRUE(entry->GetURL() == url2);
1588 // Now don't proceed.
1589 interstitial->DontProceed();
1590 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1591 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1592 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1593 entry = controller().GetVisibleEntry();
1594 ASSERT_NE(nullptr, entry);
1595 EXPECT_TRUE(entry->GetURL() == url1);
1596 EXPECT_EQ(1, controller().GetEntryCount());
1598 RunAllPendingInMessageLoop();
1599 EXPECT_TRUE(deleted);
1602 // Test navigating to a page that shows an interstitial without creating a new
1603 // navigation entry (this happens when the interstitial is triggered by a
1604 // sub-resource in the page), then hiding it without proceeding.
1605 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1606 // Navigate to a page.
1607 GURL url1("http://www.google.com");
1608 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1609 EXPECT_EQ(1, controller().GetEntryCount());
1611 // Show an interstitial.
1612 TestInterstitialPage::InterstitialState state =
1613 TestInterstitialPage::INVALID;
1614 bool deleted = false;
1615 GURL url2("http://interstitial");
1616 TestInterstitialPage* interstitial =
1617 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1618 TestInterstitialPageStateGuard state_guard(interstitial);
1619 interstitial->Show();
1620 // The interstitial should not show until its navigation has committed.
1621 EXPECT_FALSE(interstitial->is_showing());
1622 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1623 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1624 // Let's commit the interstitial navigation.
1625 interstitial->TestDidNavigate(1, 0, true, url2);
1626 EXPECT_TRUE(interstitial->is_showing());
1627 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1628 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1629 NavigationEntry* entry = controller().GetVisibleEntry();
1630 ASSERT_NE(nullptr, entry);
1631 // The URL specified to the interstitial should have been ignored.
1632 EXPECT_TRUE(entry->GetURL() == url1);
1634 // Now don't proceed.
1635 interstitial->DontProceed();
1636 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1637 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1638 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1639 entry = controller().GetVisibleEntry();
1640 ASSERT_NE(nullptr, entry);
1641 EXPECT_TRUE(entry->GetURL() == url1);
1642 EXPECT_EQ(1, controller().GetEntryCount());
1644 RunAllPendingInMessageLoop();
1645 EXPECT_TRUE(deleted);
1648 // Test navigating to a page (with the navigation initiated from the browser,
1649 // as when a URL is typed in the location bar) that shows an interstitial and
1650 // creates a new navigation entry, then proceeding.
1651 TEST_F(WebContentsImplTest,
1652 ShowInterstitialFromBrowserNewNavigationProceed) {
1653 // Navigate to a page.
1654 GURL url1("http://www.google.com");
1655 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1656 EXPECT_EQ(1, controller().GetEntryCount());
1658 // Initiate a browser navigation that will trigger the interstitial
1659 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1660 ui::PAGE_TRANSITION_TYPED, std::string());
1662 // Show an interstitial.
1663 TestInterstitialPage::InterstitialState state =
1664 TestInterstitialPage::INVALID;
1665 bool deleted = false;
1666 GURL url2("http://interstitial");
1667 TestInterstitialPage* interstitial =
1668 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1669 TestInterstitialPageStateGuard state_guard(interstitial);
1670 interstitial->Show();
1671 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1672 // The interstitial should not show until its navigation has committed.
1673 EXPECT_FALSE(interstitial->is_showing());
1674 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1675 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1676 // Let's commit the interstitial navigation.
1677 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
1678 EXPECT_TRUE(interstitial->is_showing());
1679 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1680 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1681 NavigationEntry* entry = controller().GetVisibleEntry();
1682 ASSERT_NE(nullptr, entry);
1683 EXPECT_TRUE(entry->GetURL() == url2);
1685 // Then proceed.
1686 interstitial->Proceed();
1687 // The interstitial should show until the new navigation commits.
1688 RunAllPendingInMessageLoop();
1689 ASSERT_FALSE(deleted);
1690 EXPECT_EQ(TestInterstitialPage::OKED, state);
1691 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1692 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1694 // Simulate the navigation to the page, that's when the interstitial gets
1695 // hidden.
1696 GURL url3("http://www.thepage.com");
1697 contents()->GetMainFrame()->PrepareForCommit();
1698 contents()->GetMainFrame()->SendNavigate(2, 0, true, url3);
1700 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1701 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1702 entry = controller().GetVisibleEntry();
1703 ASSERT_NE(nullptr, entry);
1704 EXPECT_TRUE(entry->GetURL() == url3);
1706 EXPECT_EQ(2, controller().GetEntryCount());
1708 RunAllPendingInMessageLoop();
1709 EXPECT_TRUE(deleted);
1712 // Test navigating to a page (with the navigation initiated from the renderer,
1713 // as when clicking on a link in the page) that shows an interstitial and
1714 // creates a new navigation entry, then proceeding.
1715 TEST_F(WebContentsImplTest,
1716 ShowInterstitialFromRendererNewNavigationProceed) {
1717 // Navigate to a page.
1718 GURL url1("http://www.google.com");
1719 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1720 EXPECT_EQ(1, controller().GetEntryCount());
1722 // Show an interstitial.
1723 TestInterstitialPage::InterstitialState state =
1724 TestInterstitialPage::INVALID;
1725 bool deleted = false;
1726 GURL url2("http://interstitial");
1727 TestInterstitialPage* interstitial =
1728 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1729 TestInterstitialPageStateGuard state_guard(interstitial);
1730 interstitial->Show();
1731 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1732 // The interstitial should not show until its navigation has committed.
1733 EXPECT_FALSE(interstitial->is_showing());
1734 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1735 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1736 // Let's commit the interstitial navigation.
1737 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
1738 EXPECT_TRUE(interstitial->is_showing());
1739 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1740 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1741 NavigationEntry* entry = controller().GetVisibleEntry();
1742 ASSERT_NE(nullptr, entry);
1743 EXPECT_TRUE(entry->GetURL() == url2);
1745 // Then proceed.
1746 interstitial->Proceed();
1747 // The interstitial should show until the new navigation commits.
1748 RunAllPendingInMessageLoop();
1749 ASSERT_FALSE(deleted);
1750 EXPECT_EQ(TestInterstitialPage::OKED, state);
1751 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1752 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1754 // Simulate the navigation to the page, that's when the interstitial gets
1755 // hidden.
1756 GURL url3("http://www.thepage.com");
1757 main_test_rfh()->NavigateAndCommitRendererInitiated(2, true, url3);
1759 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1760 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1761 entry = controller().GetVisibleEntry();
1762 ASSERT_NE(nullptr, entry);
1763 EXPECT_TRUE(entry->GetURL() == url3);
1765 EXPECT_EQ(2, controller().GetEntryCount());
1767 RunAllPendingInMessageLoop();
1768 EXPECT_TRUE(deleted);
1771 // Test navigating to a page that shows an interstitial without creating a new
1772 // navigation entry (this happens when the interstitial is triggered by a
1773 // sub-resource in the page), then proceeding.
1774 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1775 // Navigate to a page so we have a navigation entry in the controller.
1776 GURL url1("http://www.google.com");
1777 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1778 EXPECT_EQ(1, controller().GetEntryCount());
1780 // Show an interstitial.
1781 TestInterstitialPage::InterstitialState state =
1782 TestInterstitialPage::INVALID;
1783 bool deleted = false;
1784 GURL url2("http://interstitial");
1785 TestInterstitialPage* interstitial =
1786 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1787 TestInterstitialPageStateGuard state_guard(interstitial);
1788 interstitial->Show();
1789 // The interstitial should not show until its navigation has committed.
1790 EXPECT_FALSE(interstitial->is_showing());
1791 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1792 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1793 // Let's commit the interstitial navigation.
1794 interstitial->TestDidNavigate(1, 0, true, url2);
1795 EXPECT_TRUE(interstitial->is_showing());
1796 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1797 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1798 NavigationEntry* entry = controller().GetVisibleEntry();
1799 ASSERT_NE(nullptr, entry);
1800 // The URL specified to the interstitial should have been ignored.
1801 EXPECT_TRUE(entry->GetURL() == url1);
1803 // Then proceed.
1804 interstitial->Proceed();
1805 // Since this is not a new navigation, the previous page is dismissed right
1806 // away and shows the original page.
1807 EXPECT_EQ(TestInterstitialPage::OKED, state);
1808 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1809 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
1810 entry = controller().GetVisibleEntry();
1811 ASSERT_NE(nullptr, entry);
1812 EXPECT_TRUE(entry->GetURL() == url1);
1814 EXPECT_EQ(1, controller().GetEntryCount());
1816 RunAllPendingInMessageLoop();
1817 EXPECT_TRUE(deleted);
1820 // Test navigating to a page that shows an interstitial, then navigating away.
1821 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1822 // Show interstitial.
1823 TestInterstitialPage::InterstitialState state =
1824 TestInterstitialPage::INVALID;
1825 bool deleted = false;
1826 GURL url("http://interstitial");
1827 TestInterstitialPage* interstitial =
1828 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1829 TestInterstitialPageStateGuard state_guard(interstitial);
1830 interstitial->Show();
1831 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1832 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
1834 // While interstitial showing, navigate to a new URL.
1835 const GURL url2("http://www.yahoo.com");
1836 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url2);
1838 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1840 RunAllPendingInMessageLoop();
1841 EXPECT_TRUE(deleted);
1844 // Test navigating to a page that shows an interstitial, then going back.
1845 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1846 // Navigate to a page so we have a navigation entry in the controller.
1847 GURL url1("http://www.google.com");
1848 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1849 EXPECT_EQ(1, controller().GetEntryCount());
1850 NavigationEntry* entry = controller().GetLastCommittedEntry();
1852 // Show interstitial.
1853 TestInterstitialPage::InterstitialState state =
1854 TestInterstitialPage::INVALID;
1855 bool deleted = false;
1856 GURL interstitial_url("http://interstitial");
1857 TestInterstitialPage* interstitial =
1858 new TestInterstitialPage(contents(), true, interstitial_url,
1859 &state, &deleted);
1860 TestInterstitialPageStateGuard state_guard(interstitial);
1861 interstitial->Show();
1862 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1863 interstitial->TestDidNavigate(2, interstitial_entry_id, true,
1864 interstitial_url);
1866 // While the interstitial is showing, go back.
1867 controller().GoBack();
1868 main_test_rfh()->PrepareForCommit();
1869 contents()->GetMainFrame()->SendNavigate(1, entry->GetUniqueID(), false,
1870 url1);
1872 // Make sure we are back to the original page and that the interstitial is
1873 // gone.
1874 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1875 entry = controller().GetVisibleEntry();
1876 ASSERT_TRUE(entry);
1877 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1879 RunAllPendingInMessageLoop();
1880 EXPECT_TRUE(deleted);
1883 // Test navigating to a page that shows an interstitial, has a renderer crash,
1884 // and then goes back.
1885 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1886 // Navigate to a page so we have a navigation entry in the controller.
1887 GURL url1("http://www.google.com");
1888 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1889 EXPECT_EQ(1, controller().GetEntryCount());
1890 NavigationEntry* entry = controller().GetLastCommittedEntry();
1892 // Show interstitial.
1893 TestInterstitialPage::InterstitialState state =
1894 TestInterstitialPage::INVALID;
1895 bool deleted = false;
1896 GURL interstitial_url("http://interstitial");
1897 TestInterstitialPage* interstitial =
1898 new TestInterstitialPage(contents(), true, interstitial_url,
1899 &state, &deleted);
1900 TestInterstitialPageStateGuard state_guard(interstitial);
1901 interstitial->Show();
1902 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1903 interstitial->TestDidNavigate(2, interstitial_entry_id, true,
1904 interstitial_url);
1906 // Crash the renderer
1907 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1909 // While the interstitial is showing, go back. This will dismiss the
1910 // interstitial and not initiate a navigation, but just show the existing
1911 // RenderFrameHost.
1912 controller().GoBack();
1914 // Make sure we are back to the original page and that the interstitial is
1915 // gone.
1916 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1917 entry = controller().GetVisibleEntry();
1918 ASSERT_TRUE(entry);
1919 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1921 RunAllPendingInMessageLoop();
1922 EXPECT_TRUE(deleted);
1925 // Test navigating to a page that shows an interstitial, has the renderer crash,
1926 // and then navigates to the interstitial.
1927 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1928 // Navigate to a page so we have a navigation entry in the controller.
1929 GURL url1("http://www.google.com");
1930 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
1931 EXPECT_EQ(1, controller().GetEntryCount());
1933 // Show interstitial.
1934 TestInterstitialPage::InterstitialState state =
1935 TestInterstitialPage::INVALID;
1936 bool deleted = false;
1937 GURL interstitial_url("http://interstitial");
1938 TestInterstitialPage* interstitial =
1939 new TestInterstitialPage(contents(), true, interstitial_url,
1940 &state, &deleted);
1941 TestInterstitialPageStateGuard state_guard(interstitial);
1942 interstitial->Show();
1943 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1945 // Crash the renderer
1946 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
1948 interstitial->TestDidNavigate(2, interstitial_entry_id, true,
1949 interstitial_url);
1952 // Test navigating to a page that shows an interstitial, then close the
1953 // contents.
1954 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1955 // Show interstitial.
1956 TestInterstitialPage::InterstitialState state =
1957 TestInterstitialPage::INVALID;
1958 bool deleted = false;
1959 GURL url("http://interstitial");
1960 TestInterstitialPage* interstitial =
1961 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1962 TestInterstitialPageStateGuard state_guard(interstitial);
1963 interstitial->Show();
1964 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1965 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
1967 // Now close the contents.
1968 DeleteContents();
1969 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1971 RunAllPendingInMessageLoop();
1972 EXPECT_TRUE(deleted);
1975 // Test navigating to a page that shows an interstitial, then close the
1976 // contents.
1977 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1978 // Show interstitial.
1979 TestInterstitialPage::InterstitialState state =
1980 TestInterstitialPage::INVALID;
1981 bool deleted = false;
1982 GURL url("http://interstitial");
1983 TestInterstitialPage* interstitial =
1984 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1985 TestInterstitialPageStateGuard state_guard(interstitial);
1986 interstitial->Show();
1987 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
1988 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
1989 TestRenderFrameHost* rfh =
1990 static_cast<TestRenderFrameHost*>(interstitial->GetMainFrame());
1992 // Now close the contents.
1993 DeleteContents();
1994 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1996 // Before the interstitial has a chance to process its shutdown task,
1997 // simulate quitting the browser. This goes through all processes and
1998 // tells them to destruct.
1999 rfh->GetProcess()->SimulateCrash();
2001 RunAllPendingInMessageLoop();
2002 EXPECT_TRUE(deleted);
2005 // Test that after Proceed is called and an interstitial is still shown, no more
2006 // commands get executed.
2007 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
2008 // Navigate to a page so we have a navigation entry in the controller.
2009 GURL url1("http://www.google.com");
2010 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
2011 EXPECT_EQ(1, controller().GetEntryCount());
2013 // Show an interstitial.
2014 TestInterstitialPage::InterstitialState state =
2015 TestInterstitialPage::INVALID;
2016 bool deleted = false;
2017 GURL url2("http://interstitial");
2018 TestInterstitialPage* interstitial =
2019 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2020 TestInterstitialPageStateGuard state_guard(interstitial);
2021 interstitial->Show();
2022 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2023 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
2025 // Run a command.
2026 EXPECT_EQ(0, interstitial->command_received_count());
2027 interstitial->TestDomOperationResponse("toto");
2028 EXPECT_EQ(1, interstitial->command_received_count());
2030 // Then proceed.
2031 interstitial->Proceed();
2032 RunAllPendingInMessageLoop();
2033 ASSERT_FALSE(deleted);
2035 // While the navigation to the new page is pending, send other commands, they
2036 // should be ignored.
2037 interstitial->TestDomOperationResponse("hello");
2038 interstitial->TestDomOperationResponse("hi");
2039 EXPECT_EQ(1, interstitial->command_received_count());
2042 // Test showing an interstitial while another interstitial is already showing.
2043 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
2044 // Navigate to a page so we have a navigation entry in the controller.
2045 GURL start_url("http://www.google.com");
2046 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url);
2047 EXPECT_EQ(1, controller().GetEntryCount());
2049 // Show an interstitial.
2050 TestInterstitialPage::InterstitialState state1 =
2051 TestInterstitialPage::INVALID;
2052 bool deleted1 = false;
2053 GURL url1("http://interstitial1");
2054 TestInterstitialPage* interstitial1 =
2055 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
2056 TestInterstitialPageStateGuard state_guard1(interstitial1);
2057 interstitial1->Show();
2058 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2059 interstitial1->TestDidNavigate(1, interstitial_entry_id, true, url1);
2061 // Now show another interstitial.
2062 TestInterstitialPage::InterstitialState state2 =
2063 TestInterstitialPage::INVALID;
2064 bool deleted2 = false;
2065 GURL url2("http://interstitial2");
2066 TestInterstitialPage* interstitial2 =
2067 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2068 TestInterstitialPageStateGuard state_guard2(interstitial2);
2069 interstitial2->Show();
2070 interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2071 interstitial2->TestDidNavigate(1, interstitial_entry_id, true, url2);
2073 // Showing interstitial2 should have caused interstitial1 to go away.
2074 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2075 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2077 RunAllPendingInMessageLoop();
2078 EXPECT_TRUE(deleted1);
2079 ASSERT_FALSE(deleted2);
2081 // Let's make sure interstitial2 is working as intended.
2082 interstitial2->Proceed();
2083 GURL landing_url("http://www.thepage.com");
2084 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url);
2086 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2087 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2088 NavigationEntry* entry = controller().GetVisibleEntry();
2089 ASSERT_NE(nullptr, entry);
2090 EXPECT_TRUE(entry->GetURL() == landing_url);
2091 EXPECT_EQ(2, controller().GetEntryCount());
2092 RunAllPendingInMessageLoop();
2093 EXPECT_TRUE(deleted2);
2096 // Test showing an interstitial, proceeding and then navigating to another
2097 // interstitial.
2098 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
2099 // Navigate to a page so we have a navigation entry in the controller.
2100 GURL start_url("http://www.google.com");
2101 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, start_url);
2102 EXPECT_EQ(1, controller().GetEntryCount());
2104 // Show an interstitial.
2105 TestInterstitialPage::InterstitialState state1 =
2106 TestInterstitialPage::INVALID;
2107 bool deleted1 = false;
2108 GURL url1("http://interstitial1");
2109 TestInterstitialPage* interstitial1 =
2110 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
2111 TestInterstitialPageStateGuard state_guard1(interstitial1);
2112 interstitial1->Show();
2113 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2114 interstitial1->TestDidNavigate(1, interstitial_entry_id, true, url1);
2116 // Take action. The interstitial won't be hidden until the navigation is
2117 // committed.
2118 interstitial1->Proceed();
2119 EXPECT_EQ(TestInterstitialPage::OKED, state1);
2121 // Now show another interstitial (simulating the navigation causing another
2122 // interstitial).
2123 TestInterstitialPage::InterstitialState state2 =
2124 TestInterstitialPage::INVALID;
2125 bool deleted2 = false;
2126 GURL url2("http://interstitial2");
2127 TestInterstitialPage* interstitial2 =
2128 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2129 TestInterstitialPageStateGuard state_guard2(interstitial2);
2130 interstitial2->Show();
2131 interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2132 interstitial2->TestDidNavigate(1, interstitial_entry_id, true, url2);
2134 // Showing interstitial2 should have caused interstitial1 to go away.
2135 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2136 RunAllPendingInMessageLoop();
2137 EXPECT_TRUE(deleted1);
2138 ASSERT_FALSE(deleted2);
2140 // Let's make sure interstitial2 is working as intended.
2141 interstitial2->Proceed();
2142 GURL landing_url("http://www.thepage.com");
2143 contents()->GetMainFrame()->SendNavigate(2, 0, true, landing_url);
2145 RunAllPendingInMessageLoop();
2146 EXPECT_TRUE(deleted2);
2147 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2148 EXPECT_EQ(nullptr, contents()->GetInterstitialPage());
2149 NavigationEntry* entry = controller().GetVisibleEntry();
2150 ASSERT_NE(nullptr, entry);
2151 EXPECT_TRUE(entry->GetURL() == landing_url);
2152 EXPECT_EQ(2, controller().GetEntryCount());
2155 // Test that navigating away from an interstitial while it's loading cause it
2156 // not to show.
2157 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
2158 // Show an interstitial.
2159 TestInterstitialPage::InterstitialState state =
2160 TestInterstitialPage::INVALID;
2161 bool deleted = false;
2162 GURL interstitial_url("http://interstitial");
2163 TestInterstitialPage* interstitial =
2164 new TestInterstitialPage(contents(), true, interstitial_url,
2165 &state, &deleted);
2166 TestInterstitialPageStateGuard state_guard(interstitial);
2167 interstitial->Show();
2168 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2170 // Let's simulate a navigation initiated from the browser before the
2171 // interstitial finishes loading.
2172 const GURL url("http://www.google.com");
2173 controller().LoadURL(
2174 url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2175 EXPECT_FALSE(interstitial->is_showing());
2176 RunAllPendingInMessageLoop();
2177 ASSERT_FALSE(deleted);
2179 // Now let's make the interstitial navigation commit.
2180 interstitial->TestDidNavigate(1, interstitial_entry_id, true,
2181 interstitial_url);
2183 // After it loaded the interstitial should be gone.
2184 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2186 RunAllPendingInMessageLoop();
2187 EXPECT_TRUE(deleted);
2190 // Test that a new request to show an interstitial while an interstitial is
2191 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2192 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
2193 GURL interstitial_url("http://interstitial");
2195 // Show a first interstitial.
2196 TestInterstitialPage::InterstitialState state1 =
2197 TestInterstitialPage::INVALID;
2198 bool deleted1 = false;
2199 TestInterstitialPage* interstitial1 =
2200 new TestInterstitialPage(contents(), true, interstitial_url,
2201 &state1, &deleted1);
2202 TestInterstitialPageStateGuard state_guard1(interstitial1);
2203 interstitial1->Show();
2205 // Show another interstitial on that same contents before the first one had
2206 // time to load.
2207 TestInterstitialPage::InterstitialState state2 =
2208 TestInterstitialPage::INVALID;
2209 bool deleted2 = false;
2210 TestInterstitialPage* interstitial2 =
2211 new TestInterstitialPage(contents(), true, interstitial_url,
2212 &state2, &deleted2);
2213 TestInterstitialPageStateGuard state_guard2(interstitial2);
2214 interstitial2->Show();
2215 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2217 // The first interstitial should have been closed and deleted.
2218 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2219 // The 2nd one should still be OK.
2220 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2222 RunAllPendingInMessageLoop();
2223 EXPECT_TRUE(deleted1);
2224 ASSERT_FALSE(deleted2);
2226 // Make the interstitial navigation commit it should be showing.
2227 interstitial2->TestDidNavigate(1, interstitial_entry_id, true,
2228 interstitial_url);
2229 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
2232 // Test showing an interstitial and have its renderer crash.
2233 TEST_F(WebContentsImplTest, InterstitialCrasher) {
2234 // Show an interstitial.
2235 TestInterstitialPage::InterstitialState state =
2236 TestInterstitialPage::INVALID;
2237 bool deleted = false;
2238 GURL url("http://interstitial");
2239 TestInterstitialPage* interstitial =
2240 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2241 TestInterstitialPageStateGuard state_guard(interstitial);
2242 interstitial->Show();
2243 // Simulate a renderer crash before the interstitial is shown.
2244 interstitial->TestRenderViewTerminated(
2245 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2246 // The interstitial should have been dismissed.
2247 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2248 RunAllPendingInMessageLoop();
2249 EXPECT_TRUE(deleted);
2251 // Now try again but this time crash the intersitial after it was shown.
2252 interstitial =
2253 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2254 interstitial->Show();
2255 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2256 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url);
2257 // Simulate a renderer crash.
2258 interstitial->TestRenderViewTerminated(
2259 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2260 // The interstitial should have been dismissed.
2261 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2262 RunAllPendingInMessageLoop();
2263 EXPECT_TRUE(deleted);
2266 // Tests that showing an interstitial as a result of a browser initiated
2267 // navigation while an interstitial is showing does not remove the pending
2268 // entry (see http://crbug.com/9791).
2269 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
2270 const char kUrl[] = "http://www.badguys.com/";
2271 const GURL kGURL(kUrl);
2273 // Start a navigation to a page
2274 contents()->GetController().LoadURL(
2275 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2277 // Simulate that navigation triggering an interstitial.
2278 TestInterstitialPage::InterstitialState state =
2279 TestInterstitialPage::INVALID;
2280 bool deleted = false;
2281 TestInterstitialPage* interstitial =
2282 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2283 TestInterstitialPageStateGuard state_guard(interstitial);
2284 interstitial->Show();
2285 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2286 interstitial->TestDidNavigate(1, interstitial_entry_id, true, kGURL);
2288 // Initiate a new navigation from the browser that also triggers an
2289 // interstitial.
2290 contents()->GetController().LoadURL(
2291 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2292 TestInterstitialPage::InterstitialState state2 =
2293 TestInterstitialPage::INVALID;
2294 bool deleted2 = false;
2295 TestInterstitialPage* interstitial2 =
2296 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
2297 TestInterstitialPageStateGuard state_guard2(interstitial2);
2298 interstitial2->Show();
2299 interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2300 interstitial2->TestDidNavigate(1, interstitial_entry_id, true, kGURL);
2302 // Make sure we still have an entry.
2303 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2304 ASSERT_TRUE(entry);
2305 EXPECT_EQ(kUrl, entry->GetURL().spec());
2307 // And that the first interstitial is gone, but not the second.
2308 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2309 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2310 RunAllPendingInMessageLoop();
2311 EXPECT_TRUE(deleted);
2312 EXPECT_FALSE(deleted2);
2315 // Tests that Javascript messages are not shown while an interstitial is
2316 // showing.
2317 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2318 const char kUrl[] = "http://www.badguys.com/";
2319 const GURL kGURL(kUrl);
2321 // Start a navigation to a page
2322 contents()->GetController().LoadURL(
2323 kGURL, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2324 int entry_id = controller().GetPendingEntry()->GetUniqueID();
2325 main_test_rfh()->PrepareForCommit();
2326 // DidNavigate from the page
2327 contents()->TestDidNavigate(contents()->GetMainFrame(), 1, entry_id, true,
2328 kGURL, ui::PAGE_TRANSITION_TYPED);
2330 // Simulate showing an interstitial while the page is showing.
2331 TestInterstitialPage::InterstitialState state =
2332 TestInterstitialPage::INVALID;
2333 bool deleted = false;
2334 TestInterstitialPage* interstitial =
2335 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2336 TestInterstitialPageStateGuard state_guard(interstitial);
2337 interstitial->Show();
2338 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2339 interstitial->TestDidNavigate(1, interstitial_entry_id, true, kGURL);
2341 // While the interstitial is showing, let's simulate the hidden page
2342 // attempting to show a JS message.
2343 IPC::Message* dummy_message = new IPC::Message;
2344 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2345 base::ASCIIToUTF16("This is an informative message"),
2346 base::ASCIIToUTF16("OK"),
2347 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message);
2348 EXPECT_TRUE(contents()->last_dialog_suppressed_);
2351 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2352 // interstitial it isn't copied over to the destination.
2353 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2354 // Navigate to a page.
2355 GURL url1("http://www.google.com");
2356 main_test_rfh()->NavigateAndCommitRendererInitiated(1, true, url1);
2357 EXPECT_EQ(1, controller().GetEntryCount());
2359 // Initiate a browser navigation that will trigger the interstitial
2360 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2361 ui::PAGE_TRANSITION_TYPED, std::string());
2363 // Show an interstitial.
2364 TestInterstitialPage::InterstitialState state =
2365 TestInterstitialPage::INVALID;
2366 bool deleted = false;
2367 GURL url2("http://interstitial");
2368 TestInterstitialPage* interstitial =
2369 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2370 TestInterstitialPageStateGuard state_guard(interstitial);
2371 interstitial->Show();
2372 int interstitial_entry_id = controller().GetTransientEntry()->GetUniqueID();
2373 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url2);
2374 EXPECT_TRUE(interstitial->is_showing());
2375 EXPECT_EQ(2, controller().GetEntryCount());
2377 // Create another NavigationController.
2378 GURL url3("http://foo2");
2379 scoped_ptr<TestWebContents> other_contents(
2380 static_cast<TestWebContents*>(CreateTestWebContents()));
2381 NavigationControllerImpl& other_controller = other_contents->GetController();
2382 other_contents->NavigateAndCommit(url3);
2383 other_contents->ExpectSetHistoryOffsetAndLength(1, 2);
2384 other_controller.CopyStateFromAndPrune(&controller(), false);
2386 // The merged controller should only have two entries: url1 and url2.
2387 ASSERT_EQ(2, other_controller.GetEntryCount());
2388 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2389 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2390 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2392 // And the merged controller shouldn't be showing an interstitial.
2393 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2396 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2397 // showing an interstitial.
2398 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2399 // Navigate to a page.
2400 GURL url1("http://www.google.com");
2401 contents()->NavigateAndCommit(url1);
2403 // Create another NavigationController.
2404 scoped_ptr<TestWebContents> other_contents(
2405 static_cast<TestWebContents*>(CreateTestWebContents()));
2406 NavigationControllerImpl& other_controller = other_contents->GetController();
2408 // Navigate it to url2.
2409 GURL url2("http://foo2");
2410 other_contents->NavigateAndCommit(url2);
2412 // Show an interstitial.
2413 TestInterstitialPage::InterstitialState state =
2414 TestInterstitialPage::INVALID;
2415 bool deleted = false;
2416 GURL url3("http://interstitial");
2417 TestInterstitialPage* interstitial =
2418 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2419 &deleted);
2420 TestInterstitialPageStateGuard state_guard(interstitial);
2421 interstitial->Show();
2422 int interstitial_entry_id =
2423 other_controller.GetTransientEntry()->GetUniqueID();
2424 interstitial->TestDidNavigate(1, interstitial_entry_id, true, url3);
2425 EXPECT_TRUE(interstitial->is_showing());
2426 EXPECT_EQ(2, other_controller.GetEntryCount());
2428 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2429 // interstitial is showing in the target.
2430 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2433 // Regression test for http://crbug.com/168611 - the URLs passed by the
2434 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2435 TEST_F(WebContentsImplTest, FilterURLs) {
2436 TestWebContentsObserver observer(contents());
2438 // A navigation to about:whatever should always look like a navigation to
2439 // about:blank
2440 GURL url_normalized(url::kAboutBlankURL);
2441 GURL url_from_ipc("about:whatever");
2443 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2444 // will use the given URL to create the NavigationEntry as well, and that
2445 // entry should contain the filtered URL.
2446 contents()->NavigateAndCommit(url_normalized);
2448 // Check that an IPC with about:whatever is correctly normalized.
2449 contents()->TestDidFinishLoad(url_from_ipc);
2451 EXPECT_EQ(url_normalized, observer.last_url());
2453 // Create and navigate another WebContents.
2454 scoped_ptr<TestWebContents> other_contents(
2455 static_cast<TestWebContents*>(CreateTestWebContents()));
2456 TestWebContentsObserver other_observer(other_contents.get());
2457 other_contents->NavigateAndCommit(url_normalized);
2459 // Check that an IPC with about:whatever is correctly normalized.
2460 other_contents->TestDidFailLoadWithError(
2461 url_from_ipc, 1, base::string16());
2462 EXPECT_EQ(url_normalized, other_observer.last_url());
2465 // Test that if a pending contents is deleted before it is shown, we don't
2466 // crash.
2467 TEST_F(WebContentsImplTest, PendingContents) {
2468 scoped_ptr<TestWebContents> other_contents(
2469 static_cast<TestWebContents*>(CreateTestWebContents()));
2470 contents()->AddPendingContents(other_contents.get());
2471 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2472 other_contents.reset();
2473 EXPECT_EQ(nullptr, contents()->GetCreatedWindow(route_id));
2476 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
2477 const gfx::Size original_preferred_size(1024, 768);
2478 contents()->UpdatePreferredSize(original_preferred_size);
2480 // With no capturers, expect the preferred size to be the one propagated into
2481 // WebContentsImpl via the RenderViewHostDelegate interface.
2482 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2483 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2485 // Increment capturer count, but without specifying a capture size. Expect
2486 // a "not set" preferred size.
2487 contents()->IncrementCapturerCount(gfx::Size());
2488 EXPECT_EQ(1, contents()->GetCapturerCount());
2489 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2491 // Increment capturer count again, but with an overriding capture size.
2492 // Expect preferred size to now be overridden to the capture size.
2493 const gfx::Size capture_size(1280, 720);
2494 contents()->IncrementCapturerCount(capture_size);
2495 EXPECT_EQ(2, contents()->GetCapturerCount());
2496 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2498 // Increment capturer count a third time, but the expect that the preferred
2499 // size is still the first capture size.
2500 const gfx::Size another_capture_size(720, 480);
2501 contents()->IncrementCapturerCount(another_capture_size);
2502 EXPECT_EQ(3, contents()->GetCapturerCount());
2503 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2505 // Decrement capturer count twice, but expect the preferred size to still be
2506 // overridden.
2507 contents()->DecrementCapturerCount();
2508 contents()->DecrementCapturerCount();
2509 EXPECT_EQ(1, contents()->GetCapturerCount());
2510 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2512 // Decrement capturer count, and since the count has dropped to zero, the
2513 // original preferred size should be restored.
2514 contents()->DecrementCapturerCount();
2515 EXPECT_EQ(0, contents()->GetCapturerCount());
2516 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2519 TEST_F(WebContentsImplTest, CapturerPreventsHiding) {
2520 const gfx::Size original_preferred_size(1024, 768);
2521 contents()->UpdatePreferredSize(original_preferred_size);
2523 TestRenderWidgetHostView* view = static_cast<TestRenderWidgetHostView*>(
2524 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2526 // With no capturers, setting and un-setting occlusion should change the
2527 // view's occlusion state.
2528 EXPECT_FALSE(view->is_showing());
2529 contents()->WasShown();
2530 EXPECT_TRUE(view->is_showing());
2531 contents()->WasHidden();
2532 EXPECT_FALSE(view->is_showing());
2533 contents()->WasShown();
2534 EXPECT_TRUE(view->is_showing());
2536 // Add a capturer and try to hide the contents. The view will remain visible.
2537 contents()->IncrementCapturerCount(gfx::Size());
2538 contents()->WasHidden();
2539 EXPECT_TRUE(view->is_showing());
2541 // Remove the capturer, and the WasHidden should take effect.
2542 contents()->DecrementCapturerCount();
2543 EXPECT_FALSE(view->is_showing());
2546 TEST_F(WebContentsImplTest, CapturerPreventsOcclusion) {
2547 const gfx::Size original_preferred_size(1024, 768);
2548 contents()->UpdatePreferredSize(original_preferred_size);
2550 TestRenderWidgetHostView* view = static_cast<TestRenderWidgetHostView*>(
2551 contents()->GetMainFrame()->GetRenderViewHost()->GetView());
2553 // With no capturers, setting and un-setting occlusion should change the
2554 // view's occlusion state.
2555 EXPECT_FALSE(view->is_occluded());
2556 contents()->WasOccluded();
2557 EXPECT_TRUE(view->is_occluded());
2558 contents()->WasUnOccluded();
2559 EXPECT_FALSE(view->is_occluded());
2560 contents()->WasOccluded();
2561 EXPECT_TRUE(view->is_occluded());
2563 // Add a capturer. This should cause the view to be un-occluded.
2564 contents()->IncrementCapturerCount(gfx::Size());
2565 EXPECT_FALSE(view->is_occluded());
2567 // Try to occlude the view. This will fail to propagate because of the
2568 // active capturer.
2569 contents()->WasOccluded();
2570 EXPECT_FALSE(view->is_occluded());
2572 // Remove the capturer and try again.
2573 contents()->DecrementCapturerCount();
2574 EXPECT_FALSE(view->is_occluded());
2575 contents()->WasOccluded();
2576 EXPECT_TRUE(view->is_occluded());
2579 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2580 // on activity.
2581 TEST_F(WebContentsImplTest, GetLastActiveTime) {
2582 // The WebContents starts with a valid creation time.
2583 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2585 // Reset the last active time to a known-bad value.
2586 contents()->last_active_time_ = base::TimeTicks();
2587 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2589 // Simulate activating the WebContents. The active time should update.
2590 contents()->WasShown();
2591 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2594 class ContentsZoomChangedDelegate : public WebContentsDelegate {
2595 public:
2596 ContentsZoomChangedDelegate() :
2597 contents_zoom_changed_call_count_(0),
2598 last_zoom_in_(false) {
2601 int GetAndResetContentsZoomChangedCallCount() {
2602 int count = contents_zoom_changed_call_count_;
2603 contents_zoom_changed_call_count_ = 0;
2604 return count;
2607 bool last_zoom_in() const {
2608 return last_zoom_in_;
2611 // WebContentsDelegate:
2612 void ContentsZoomChange(bool zoom_in) override {
2613 contents_zoom_changed_call_count_++;
2614 last_zoom_in_ = zoom_in;
2617 private:
2618 int contents_zoom_changed_call_count_;
2619 bool last_zoom_in_;
2621 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
2624 // Tests that some mouseehweel events get turned into browser zoom requests.
2625 TEST_F(WebContentsImplTest, HandleWheelEvent) {
2626 using blink::WebInputEvent;
2628 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2629 new ContentsZoomChangedDelegate());
2630 contents()->SetDelegate(delegate.get());
2632 int modifiers = 0;
2633 // Verify that normal mouse wheel events do nothing to change the zoom level.
2634 blink::WebMouseWheelEvent event =
2635 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2636 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2637 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2639 modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey |
2640 WebInputEvent::ControlKey;
2641 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2642 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2643 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2645 // But whenever the ctrl modifier is applied with canScroll=false, they can
2646 // increase/decrease zoom. Except on MacOS where we never want to adjust zoom
2647 // with mousewheel.
2648 modifiers = WebInputEvent::ControlKey;
2649 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2650 event.canScroll = false;
2651 bool handled = contents()->HandleWheelEvent(event);
2652 #if defined(OS_MACOSX)
2653 EXPECT_FALSE(handled);
2654 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2655 #else
2656 EXPECT_TRUE(handled);
2657 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2658 EXPECT_TRUE(delegate->last_zoom_in());
2659 #endif
2661 modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
2662 WebInputEvent::AltKey;
2663 event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false);
2664 event.canScroll = false;
2665 handled = contents()->HandleWheelEvent(event);
2666 #if defined(OS_MACOSX)
2667 EXPECT_FALSE(handled);
2668 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2669 #else
2670 EXPECT_TRUE(handled);
2671 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2672 EXPECT_FALSE(delegate->last_zoom_in());
2673 #endif
2675 // Unless there is no vertical movement.
2676 event = SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers, false);
2677 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2678 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2680 // Events containing precise scrolling deltas also shouldn't result in the
2681 // zoom being adjusted, to avoid accidental adjustments caused by
2682 // two-finger-scrolling on a touchpad.
2683 modifiers = WebInputEvent::ControlKey;
2684 event = SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers, true);
2685 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2686 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2688 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2689 contents()->SetDelegate(nullptr);
2692 // Tests that GetRelatedActiveContentsCount is shared between related
2693 // SiteInstances and includes WebContents that have not navigated yet.
2694 TEST_F(WebContentsImplTest, ActiveContentsCountBasic) {
2695 scoped_refptr<SiteInstance> instance1(
2696 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2697 scoped_refptr<SiteInstance> instance2(
2698 instance1->GetRelatedSiteInstance(GURL("http://b.com")));
2700 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2701 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2703 scoped_ptr<TestWebContents> contents1(
2704 TestWebContents::Create(browser_context(), instance1.get()));
2705 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2706 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2708 scoped_ptr<TestWebContents> contents2(
2709 TestWebContents::Create(browser_context(), instance1.get()));
2710 EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount());
2711 EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount());
2713 contents1.reset();
2714 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2715 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2717 contents2.reset();
2718 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2719 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2722 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2723 // same-site and cross-site navigations.
2724 TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
2725 scoped_refptr<SiteInstance> instance(
2726 SiteInstance::Create(browser_context()));
2728 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2730 scoped_ptr<TestWebContents> contents(
2731 TestWebContents::Create(browser_context(), instance.get()));
2732 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2734 // Navigate to a URL.
2735 contents->GetController().LoadURL(GURL("http://a.com/1"),
2736 Referrer(),
2737 ui::PAGE_TRANSITION_TYPED,
2738 std::string());
2739 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2740 contents->CommitPendingNavigation();
2741 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2743 // Navigate to a URL in the same site.
2744 contents->GetController().LoadURL(GURL("http://a.com/2"),
2745 Referrer(),
2746 ui::PAGE_TRANSITION_TYPED,
2747 std::string());
2748 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2749 contents->CommitPendingNavigation();
2750 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2752 // Navigate to a URL in a different site.
2753 const GURL kUrl = GURL("http://b.com");
2754 contents->GetController().LoadURL(kUrl,
2755 Referrer(),
2756 ui::PAGE_TRANSITION_TYPED,
2757 std::string());
2758 int entry_id = contents->GetController().GetPendingEntry()->GetUniqueID();
2759 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
2760 switches::kEnableBrowserSideNavigation)) {
2761 contents->GetMainFrame()->PrepareForCommit();
2763 EXPECT_TRUE(contents->CrossProcessNavigationPending());
2764 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2765 contents->GetPendingMainFrame()->SendNavigate(1, entry_id, true, kUrl);
2766 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2768 contents.reset();
2769 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2772 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2773 // from WebUI.
2774 TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
2775 scoped_refptr<SiteInstance> instance(
2776 SiteInstance::Create(browser_context()));
2778 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2780 scoped_ptr<TestWebContents> contents(
2781 TestWebContents::Create(browser_context(), instance.get()));
2782 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2784 // Navigate to a URL.
2785 contents->NavigateAndCommit(GURL("http://a.com"));
2786 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2788 // Navigate to a URL which sort of looks like a chrome:// url.
2789 contents->NavigateAndCommit(GURL("http://gpu"));
2790 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2792 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2793 const GURL kWebUIUrl = GURL("chrome://gpu");
2794 contents->GetController().LoadURL(kWebUIUrl,
2795 Referrer(),
2796 ui::PAGE_TRANSITION_TYPED,
2797 std::string());
2798 int entry_id = contents->GetController().GetPendingEntry()->GetUniqueID();
2799 contents->GetMainFrame()->PrepareForCommit();
2800 EXPECT_TRUE(contents->CrossProcessNavigationPending());
2801 scoped_refptr<SiteInstance> instance_webui(
2802 contents->GetPendingMainFrame()->GetSiteInstance());
2803 EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
2805 // At this point, contents still counts for the old BrowsingInstance.
2806 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2807 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2809 // Commit and contents counts for the new one.
2810 contents->GetPendingMainFrame()->SendNavigate(1, entry_id, true, kWebUIUrl);
2811 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2812 EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount());
2814 contents.reset();
2815 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2816 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2819 class LoadingWebContentsObserver : public WebContentsObserver {
2820 public:
2821 explicit LoadingWebContentsObserver(WebContents* contents)
2822 : WebContentsObserver(contents),
2823 is_loading_(false) {
2825 ~LoadingWebContentsObserver() override {}
2827 void DidStartLoading() override { is_loading_ = true; }
2828 void DidStopLoading() override { is_loading_ = false; }
2830 bool is_loading() const { return is_loading_; }
2832 private:
2833 bool is_loading_;
2835 DISALLOW_COPY_AND_ASSIGN(LoadingWebContentsObserver);
2838 // Ensure that DidStartLoading/DidStopLoading events balance out properly with
2839 // interleaving cross-process navigations in multiple subframes.
2840 // See https://crbug.com/448601 for details of the underlying issue. The
2841 // sequence of events that reproduce it are as follows:
2842 // * Navigate top-level frame with one subframe.
2843 // * Subframe navigates more than once before the top-level frame has had a
2844 // chance to complete the load.
2845 // The subframe navigations cause the loading_frames_in_progress_ to drop down
2846 // to 0, while the loading_progresses_ map is not reset.
2847 TEST_F(WebContentsImplTest, StartStopEventsBalance) {
2848 // The bug manifests itself in regular mode as well, but browser-initiated
2849 // navigation of subframes is only possible in --site-per-process mode within
2850 // unit tests.
2851 base::CommandLine::ForCurrentProcess()->AppendSwitch(
2852 switches::kSitePerProcess);
2853 const GURL initial_url("about:blank");
2854 const GURL main_url("http://www.chromium.org");
2855 const GURL foo_url("http://foo.chromium.org");
2856 const GURL bar_url("http://bar.chromium.org");
2857 TestRenderFrameHost* orig_rfh = contents()->GetMainFrame();
2859 // Use a WebContentsObserver to approximate the behavior of the tab's spinner.
2860 LoadingWebContentsObserver observer(contents());
2862 // Navigate the main RenderFrame, simulate the DidStartLoading, and commit.
2863 // The frame should still be loading.
2864 controller().LoadURL(
2865 main_url, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2866 int entry_id = controller().GetPendingEntry()->GetUniqueID();
2867 orig_rfh->PrepareForCommit();
2868 orig_rfh->OnMessageReceived(
2869 FrameHostMsg_DidStartLoading(orig_rfh->GetRoutingID(), false));
2870 contents()->TestDidNavigate(orig_rfh, 1, entry_id, true, main_url,
2871 ui::PAGE_TRANSITION_TYPED);
2872 EXPECT_FALSE(contents()->CrossProcessNavigationPending());
2873 EXPECT_EQ(orig_rfh, contents()->GetMainFrame());
2874 EXPECT_TRUE(contents()->IsLoading());
2875 EXPECT_TRUE(observer.is_loading());
2877 // Create a child frame to navigate multiple times.
2878 TestRenderFrameHost* subframe = orig_rfh->AppendChild("subframe");
2880 // Navigate the child frame to about:blank, which will send both
2881 // DidStartLoading and DidStopLoading messages.
2883 subframe->SendRendererInitiatedNavigationRequest(initial_url, false);
2884 subframe->PrepareForCommit();
2885 subframe->OnMessageReceived(
2886 FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
2887 subframe->SendNavigateWithTransition(1, 0, false, initial_url,
2888 ui::PAGE_TRANSITION_AUTO_SUBFRAME);
2889 subframe->OnMessageReceived(
2890 FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
2893 // Navigate the frame to another URL, which will send again
2894 // DidStartLoading and DidStopLoading messages.
2896 subframe->SendRendererInitiatedNavigationRequest(foo_url, false);
2897 subframe->PrepareForCommit();
2898 subframe->OnMessageReceived(
2899 FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
2900 subframe->SendNavigateWithTransition(1, 0, false, foo_url,
2901 ui::PAGE_TRANSITION_AUTO_SUBFRAME);
2902 subframe->OnMessageReceived(
2903 FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
2906 // Since the main frame hasn't sent any DidStopLoading messages, it is
2907 // expected that the WebContents is still in loading state.
2908 EXPECT_TRUE(contents()->IsLoading());
2909 EXPECT_TRUE(observer.is_loading());
2911 // Navigate the frame again, this time using LoadURLWithParams. This causes
2912 // RenderFrameHost to call into WebContents::DidStartLoading, which starts
2913 // the spinner.
2915 NavigationController::LoadURLParams load_params(bar_url);
2916 load_params.referrer =
2917 Referrer(GURL("http://referrer"), blink::WebReferrerPolicyDefault);
2918 load_params.transition_type = ui::PAGE_TRANSITION_GENERATED;
2919 load_params.extra_headers = "content-type: text/plain";
2920 load_params.load_type = NavigationController::LOAD_TYPE_DEFAULT;
2921 load_params.is_renderer_initiated = false;
2922 load_params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE;
2923 load_params.frame_tree_node_id =
2924 subframe->frame_tree_node()->frame_tree_node_id();
2925 controller().LoadURLWithParams(load_params);
2926 entry_id = controller().GetPendingEntry()->GetUniqueID();
2928 subframe->OnMessageReceived(
2929 FrameHostMsg_DidStartLoading(subframe->GetRoutingID(), true));
2931 // Commit the navigation in the child frame and send the DidStopLoading
2932 // message.
2933 subframe->PrepareForCommit();
2934 contents()->TestDidNavigate(subframe, 3, entry_id, true, bar_url,
2935 ui::PAGE_TRANSITION_MANUAL_SUBFRAME);
2936 subframe->OnMessageReceived(
2937 FrameHostMsg_DidStopLoading(subframe->GetRoutingID()));
2940 // At this point the status should still be loading, since the main frame
2941 // hasn't sent the DidstopLoading message yet.
2942 EXPECT_TRUE(contents()->IsLoading());
2943 EXPECT_TRUE(observer.is_loading());
2945 // Send the DidStopLoading for the main frame and ensure it isn't loading
2946 // anymore.
2947 orig_rfh->OnMessageReceived(
2948 FrameHostMsg_DidStopLoading(orig_rfh->GetRoutingID()));
2949 EXPECT_FALSE(contents()->IsLoading());
2950 EXPECT_FALSE(observer.is_loading());
2953 // Ensure that WebContentsImpl does not stop loading too early when there still
2954 // is a pending renderer. This can happen if a same-process non user-initiated
2955 // navigation completes while there is an ongoing cross-process navigation.
2956 // TODO(fdegans): Rewrite the test for PlzNavigate when DidStartLoading and
2957 // DidStopLoading are properly called.
2958 TEST_F(WebContentsImplTest, NoEarlyStop) {
2959 const GURL kUrl1("http://www.chromium.org");
2960 const GURL kUrl2("http://www.google.com");
2961 const GURL kUrl3("http://www.wikipedia.org");
2963 contents()->NavigateAndCommit(kUrl1);
2965 TestRenderFrameHost* current_rfh = contents()->GetMainFrame();
2967 // Start a browser-initiated cross-process navigation to |kUrl2|. There should
2968 // be a pending RenderFrameHost and the WebContents should be loading.
2969 controller().LoadURL(
2970 kUrl2, Referrer(), ui::PAGE_TRANSITION_TYPED, std::string());
2971 int entry_id = controller().GetPendingEntry()->GetUniqueID();
2972 EXPECT_TRUE(contents()->CrossProcessNavigationPending());
2973 TestRenderFrameHost* pending_rfh = contents()->GetPendingMainFrame();
2974 ASSERT_TRUE(pending_rfh);
2975 EXPECT_TRUE(contents()->IsLoading());
2977 // The current RenderFrameHost starts a non user-initiated render-initiated
2978 // navigation and sends a DidStartLoading IPC. The WebContents should still be
2979 // loading.
2980 current_rfh->OnMessageReceived(
2981 FrameHostMsg_DidStartLoading(current_rfh->GetRoutingID(), false));
2982 EXPECT_TRUE(contents()->IsLoading());
2984 // Simulate the pending RenderFrameHost DidStartLoading. There should still be
2985 // a pending RenderFrameHost and the WebContents should still be loading.
2986 pending_rfh->PrepareForCommit();
2987 pending_rfh->OnMessageReceived(
2988 FrameHostMsg_DidStartLoading(pending_rfh->GetRoutingID(), false));
2989 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh);
2990 EXPECT_TRUE(contents()->IsLoading());
2992 // Simulate the commit and DidStopLoading from the renderer-initiated
2993 // navigation in the current RenderFrameHost. There should still be a pending
2994 // RenderFrameHost and the WebContents should still be loading.
2995 current_rfh->SendNavigate(1, 0, true, kUrl3);
2996 current_rfh->OnMessageReceived(
2997 FrameHostMsg_DidStopLoading(current_rfh->GetRoutingID()));
2998 EXPECT_EQ(contents()->GetPendingMainFrame(), pending_rfh);
2999 EXPECT_TRUE(contents()->IsLoading());
3001 // Commit the navigation. The formerly pending RenderFrameHost should now be
3002 // the current RenderFrameHost and the WebContents should still be loading.
3003 contents()->TestDidNavigate(pending_rfh, 1, entry_id, true, kUrl2,
3004 ui::PAGE_TRANSITION_TYPED);
3005 EXPECT_FALSE(contents()->GetPendingMainFrame());
3006 TestRenderFrameHost* new_current_rfh = contents()->GetMainFrame();
3007 EXPECT_EQ(new_current_rfh, pending_rfh);
3008 EXPECT_TRUE(contents()->IsLoading());
3010 // Simulate the new current RenderFrameHost DidStopLoading. The WebContents
3011 // should now have stopped loading.
3012 new_current_rfh->OnMessageReceived(
3013 FrameHostMsg_DidStopLoading(new_current_rfh->GetRoutingID()));
3014 EXPECT_EQ(contents()->GetMainFrame(), new_current_rfh);
3015 EXPECT_FALSE(contents()->IsLoading());
3018 TEST_F(WebContentsImplTest, MediaPowerSaveBlocking) {
3019 // PlayerIDs are actually pointers cast to int64, so verify that both negative
3020 // and positive player ids don't blow up.
3021 const int kPlayerAudioVideoId = 15;
3022 const int kPlayerAudioOnlyId = -15;
3023 const int kPlayerVideoOnlyId = 30;
3024 const int kPlayerRemoteId = -30;
3026 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3027 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3029 TestRenderFrameHost* rfh = contents()->GetMainFrame();
3030 AudioStateProvider* audio_state = contents()->audio_state_provider();
3032 // Ensure RenderFrame is initialized before simulating events coming from it.
3033 main_test_rfh()->InitializeRenderFrameIfNeeded();
3035 // The audio power save blocker should not be based on having a media player
3036 // when audio stream monitoring is available.
3037 if (audio_state->IsAudioStateAvailable()) {
3038 // Send a fake audio stream monitor notification. The audio power save
3039 // blocker should be created.
3040 audio_state->set_was_recently_audible_for_testing(true);
3041 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
3042 EXPECT_TRUE(contents()->has_audio_power_save_blocker_for_testing());
3044 // Send another fake notification, this time when WasRecentlyAudible() will
3045 // be false. The power save blocker should be released.
3046 audio_state->set_was_recently_audible_for_testing(false);
3047 contents()->NotifyNavigationStateChanged(INVALIDATE_TYPE_TAB);
3048 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3051 // Start a player with both audio and video. A video power save blocker
3052 // should be created. If audio stream monitoring is available, an audio power
3053 // save blocker should be created too.
3054 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3055 0, kPlayerAudioVideoId, true, true, false));
3056 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3057 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3058 !audio_state->IsAudioStateAvailable());
3060 // Upon hiding the video power save blocker should be released.
3061 contents()->WasHidden();
3062 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3064 // Start another player that only has video. There should be no change in
3065 // the power save blockers. The notification should take into account the
3066 // visibility state of the WebContents.
3067 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3068 0, kPlayerVideoOnlyId, true, false, false));
3069 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3070 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3071 !audio_state->IsAudioStateAvailable());
3073 // Showing the WebContents should result in the creation of the blocker.
3074 contents()->WasShown();
3075 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3077 // Start another player that only has audio. There should be no change in
3078 // the power save blockers.
3079 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3080 0, kPlayerAudioOnlyId, false, true, false));
3081 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3082 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3083 !audio_state->IsAudioStateAvailable());
3085 // Start a remote player. There should be no change in the power save
3086 // blockers.
3087 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3088 0, kPlayerRemoteId, true, true, true));
3089 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3090 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3091 !audio_state->IsAudioStateAvailable());
3093 // Destroy the original audio video player. Both power save blockers should
3094 // remain.
3095 rfh->OnMessageReceived(
3096 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioVideoId));
3097 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3098 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3099 !audio_state->IsAudioStateAvailable());
3101 // Destroy the audio only player. The video power save blocker should remain.
3102 rfh->OnMessageReceived(
3103 FrameHostMsg_MediaPausedNotification(0, kPlayerAudioOnlyId));
3104 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3105 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3107 // Destroy the video only player. No power save blockers should remain.
3108 rfh->OnMessageReceived(
3109 FrameHostMsg_MediaPausedNotification(0, kPlayerVideoOnlyId));
3110 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3111 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3113 // Destroy the remote player. No power save blockers should remain.
3114 rfh->OnMessageReceived(
3115 FrameHostMsg_MediaPausedNotification(0, kPlayerRemoteId));
3116 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3117 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3119 // Start a player with both audio and video. A video power save blocker
3120 // should be created. If audio stream monitoring is available, an audio power
3121 // save blocker should be created too.
3122 rfh->OnMessageReceived(FrameHostMsg_MediaPlayingNotification(
3123 0, kPlayerAudioVideoId, true, true, false));
3124 EXPECT_TRUE(contents()->has_video_power_save_blocker_for_testing());
3125 EXPECT_EQ(contents()->has_audio_power_save_blocker_for_testing(),
3126 !audio_state->IsAudioStateAvailable());
3128 // Crash the renderer.
3129 contents()->GetMainFrame()->GetProcess()->SimulateCrash();
3131 // Verify that all the power save blockers have been released.
3132 EXPECT_FALSE(contents()->has_video_power_save_blocker_for_testing());
3133 EXPECT_FALSE(contents()->has_audio_power_save_blocker_for_testing());
3136 TEST_F(WebContentsImplTest, ThemeColorChangeDependingOnFirstVisiblePaint) {
3137 TestWebContentsObserver observer(contents());
3138 TestRenderFrameHost* rfh = contents()->GetMainFrame();
3140 SkColor transparent = SK_ColorTRANSPARENT;
3142 EXPECT_EQ(transparent, contents()->GetThemeColor());
3143 EXPECT_EQ(transparent, observer.last_theme_color());
3145 // Theme color changes should not propagate past the WebContentsImpl before
3146 // the first visually non-empty paint has occurred.
3147 RenderViewHostTester::TestOnMessageReceived(
3148 test_rvh(),
3149 FrameHostMsg_DidChangeThemeColor(rfh->GetRoutingID(), SK_ColorRED));
3151 EXPECT_EQ(SK_ColorRED, contents()->GetThemeColor());
3152 EXPECT_EQ(transparent, observer.last_theme_color());
3154 // Simulate that the first visually non-empty paint has occurred. This will
3155 // propagate the current theme color to the delegates.
3156 RenderViewHostTester::TestOnMessageReceived(
3157 test_rvh(),
3158 FrameHostMsg_DidFirstVisuallyNonEmptyPaint(rfh->GetRoutingID()));
3160 EXPECT_EQ(SK_ColorRED, contents()->GetThemeColor());
3161 EXPECT_EQ(SK_ColorRED, observer.last_theme_color());
3163 // Additional changes made by the web contents should propagate as well.
3164 RenderViewHostTester::TestOnMessageReceived(
3165 test_rvh(),
3166 FrameHostMsg_DidChangeThemeColor(rfh->GetRoutingID(), SK_ColorGREEN));
3168 EXPECT_EQ(SK_ColorGREEN, contents()->GetThemeColor());
3169 EXPECT_EQ(SK_ColorGREEN, observer.last_theme_color());
3172 } // namespace content