Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / content / browser / web_contents / web_contents_impl_unittest.cc
blobd49fcec850756b382832b779ae4ec9f542c6f352
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/logging.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "content/browser/frame_host/cross_site_transferring_request.h"
8 #include "content/browser/frame_host/interstitial_page_impl.h"
9 #include "content/browser/frame_host/navigation_entry_impl.h"
10 #include "content/browser/renderer_host/render_view_host_impl.h"
11 #include "content/browser/site_instance_impl.h"
12 #include "content/browser/webui/web_ui_controller_factory_registry.h"
13 #include "content/common/frame_messages.h"
14 #include "content/common/input/synthetic_web_input_event_builders.h"
15 #include "content/common/view_messages.h"
16 #include "content/public/browser/global_request_id.h"
17 #include "content/public/browser/interstitial_page_delegate.h"
18 #include "content/public/browser/navigation_details.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_source.h"
21 #include "content/public/browser/render_widget_host_view.h"
22 #include "content/public/browser/web_contents_delegate.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/browser/web_ui_controller.h"
25 #include "content/public/common/bindings_policy.h"
26 #include "content/public/common/content_constants.h"
27 #include "content/public/common/url_constants.h"
28 #include "content/public/common/url_utils.h"
29 #include "content/public/test/mock_render_process_host.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/test/test_content_browser_client.h"
32 #include "content/test/test_content_client.h"
33 #include "content/test/test_render_view_host.h"
34 #include "content/test/test_web_contents.h"
35 #include "testing/gtest/include/gtest/gtest.h"
37 namespace content {
38 namespace {
40 const char kTestWebUIUrl[] = "chrome://blah";
42 class WebContentsImplTestWebUIControllerFactory
43 : public WebUIControllerFactory {
44 public:
45 virtual WebUIController* CreateWebUIControllerForURL(
46 WebUI* web_ui, const GURL& url) const OVERRIDE {
47 if (!UseWebUI(url))
48 return NULL;
49 return new WebUIController(web_ui);
52 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
53 const GURL& url) const OVERRIDE {
54 return WebUI::kNoWebUI;
57 virtual bool UseWebUIForURL(BrowserContext* browser_context,
58 const GURL& url) const OVERRIDE {
59 return UseWebUI(url);
62 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
63 const GURL& url) const OVERRIDE {
64 return UseWebUI(url);
67 private:
68 bool UseWebUI(const GURL& url) const {
69 return url == GURL(kTestWebUIUrl);
73 class TestInterstitialPage;
75 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
76 public:
77 explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
78 : interstitial_page_(interstitial_page) {}
79 virtual void CommandReceived(const std::string& command) OVERRIDE;
80 virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
81 virtual void OnDontProceed() OVERRIDE;
82 virtual void OnProceed() OVERRIDE;
83 private:
84 TestInterstitialPage* interstitial_page_;
87 class TestInterstitialPage : public InterstitialPageImpl {
88 public:
89 enum InterstitialState {
90 INVALID = 0, // Hasn't yet been initialized.
91 UNDECIDED, // Initialized, but no decision taken yet.
92 OKED, // Proceed was called.
93 CANCELED // DontProceed was called.
96 class Delegate {
97 public:
98 virtual void TestInterstitialPageDeleted(
99 TestInterstitialPage* interstitial) = 0;
101 protected:
102 virtual ~Delegate() {}
105 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
106 // |deleted| (like all interstitial related tests do at this point), make sure
107 // to create an instance of the TestInterstitialPageStateGuard class on the
108 // stack in your test. This will ensure that the TestInterstitialPage states
109 // are cleared when the test finishes.
110 // Not doing so will cause stack trashing if your test does not hide the
111 // interstitial, as in such a case it will be destroyed in the test TearDown
112 // method and will dereference the |deleted| local variable which by then is
113 // out of scope.
114 TestInterstitialPage(WebContentsImpl* contents,
115 bool new_navigation,
116 const GURL& url,
117 InterstitialState* state,
118 bool* deleted)
119 : InterstitialPageImpl(
120 contents,
121 static_cast<RenderWidgetHostDelegate*>(contents),
122 new_navigation, url, new TestInterstitialPageDelegate(this)),
123 state_(state),
124 deleted_(deleted),
125 command_received_count_(0),
126 delegate_(NULL) {
127 *state_ = UNDECIDED;
128 *deleted_ = false;
131 virtual ~TestInterstitialPage() {
132 if (deleted_)
133 *deleted_ = true;
134 if (delegate_)
135 delegate_->TestInterstitialPageDeleted(this);
138 void OnDontProceed() {
139 if (state_)
140 *state_ = CANCELED;
142 void OnProceed() {
143 if (state_)
144 *state_ = OKED;
147 int command_received_count() const {
148 return command_received_count_;
151 void TestDomOperationResponse(const std::string& json_string) {
152 if (enabled())
153 CommandReceived();
156 void TestDidNavigate(int page_id, const GURL& url) {
157 FrameHostMsg_DidCommitProvisionalLoad_Params params;
158 InitNavigateParams(&params, page_id, url, PAGE_TRANSITION_TYPED);
159 DidNavigate(GetRenderViewHostForTesting(), params);
162 void TestRenderViewTerminated(base::TerminationStatus status,
163 int error_code) {
164 RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
167 bool is_showing() const {
168 return static_cast<TestRenderWidgetHostView*>(
169 GetRenderViewHostForTesting()->GetView())->is_showing();
172 void ClearStates() {
173 state_ = NULL;
174 deleted_ = NULL;
175 delegate_ = NULL;
178 void CommandReceived() {
179 command_received_count_++;
182 void set_delegate(Delegate* delegate) {
183 delegate_ = delegate;
186 protected:
187 virtual WebContentsView* CreateWebContentsView() OVERRIDE {
188 return NULL;
191 private:
192 InterstitialState* state_;
193 bool* deleted_;
194 int command_received_count_;
195 Delegate* delegate_;
198 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
199 interstitial_page_->CommandReceived();
202 void TestInterstitialPageDelegate::OnDontProceed() {
203 interstitial_page_->OnDontProceed();
206 void TestInterstitialPageDelegate::OnProceed() {
207 interstitial_page_->OnProceed();
210 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
211 public:
212 explicit TestInterstitialPageStateGuard(
213 TestInterstitialPage* interstitial_page)
214 : interstitial_page_(interstitial_page) {
215 DCHECK(interstitial_page_);
216 interstitial_page_->set_delegate(this);
218 virtual ~TestInterstitialPageStateGuard() {
219 if (interstitial_page_)
220 interstitial_page_->ClearStates();
223 virtual void TestInterstitialPageDeleted(
224 TestInterstitialPage* interstitial) OVERRIDE {
225 DCHECK(interstitial_page_ == interstitial);
226 interstitial_page_ = NULL;
229 private:
230 TestInterstitialPage* interstitial_page_;
233 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
234 public:
235 WebContentsImplTestBrowserClient()
236 : assign_site_for_url_(false) {}
238 virtual ~WebContentsImplTestBrowserClient() {}
240 virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
241 return assign_site_for_url_;
244 void set_assign_site_for_url(bool assign) {
245 assign_site_for_url_ = assign;
248 private:
249 bool assign_site_for_url_;
252 class WebContentsImplTest : public RenderViewHostImplTestHarness {
253 public:
254 virtual void SetUp() {
255 RenderViewHostImplTestHarness::SetUp();
256 WebUIControllerFactory::RegisterFactory(&factory_);
259 virtual void TearDown() {
260 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
261 RenderViewHostImplTestHarness::TearDown();
264 private:
265 WebContentsImplTestWebUIControllerFactory factory_;
268 class TestWebContentsObserver : public WebContentsObserver {
269 public:
270 explicit TestWebContentsObserver(WebContents* contents)
271 : WebContentsObserver(contents) {
273 virtual ~TestWebContentsObserver() {}
275 virtual void DidFinishLoad(int64 frame_id,
276 const GURL& validated_url,
277 bool is_main_frame,
278 RenderViewHost* render_view_host) OVERRIDE {
279 last_url_ = validated_url;
281 virtual void DidFailLoad(int64 frame_id,
282 const GURL& validated_url,
283 bool is_main_frame,
284 int error_code,
285 const base::string16& error_description,
286 RenderViewHost* render_view_host) OVERRIDE {
287 last_url_ = validated_url;
290 const GURL& last_url() const { return last_url_; }
292 private:
293 GURL last_url_;
295 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
298 // Pretends to be a normal browser that receives toggles and transitions to/from
299 // a fullscreened state.
300 class FakeFullscreenDelegate : public WebContentsDelegate {
301 public:
302 FakeFullscreenDelegate() : fullscreened_contents_(NULL) {}
303 virtual ~FakeFullscreenDelegate() {}
305 virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
306 bool enter_fullscreen) OVERRIDE {
307 fullscreened_contents_ = enter_fullscreen ? web_contents : NULL;
310 virtual bool IsFullscreenForTabOrPending(const WebContents* web_contents)
311 const OVERRIDE {
312 return fullscreened_contents_ && web_contents == fullscreened_contents_;
315 private:
316 WebContents* fullscreened_contents_;
318 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate);
321 } // namespace
323 // Test to make sure that title updates get stripped of whitespace.
324 TEST_F(WebContentsImplTest, UpdateTitle) {
325 NavigationControllerImpl& cont =
326 static_cast<NavigationControllerImpl&>(controller());
327 FrameHostMsg_DidCommitProvisionalLoad_Params params;
328 InitNavigateParams(&params, 0, GURL(kAboutBlankURL), PAGE_TRANSITION_TYPED);
330 LoadCommittedDetails details;
331 cont.RendererDidNavigate(main_test_rfh(), params, &details);
333 contents()->UpdateTitle(rvh(), 0,
334 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
335 base::i18n::LEFT_TO_RIGHT);
336 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
339 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
340 const GURL kGURL("chrome://blah");
341 controller().LoadURL(
342 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
343 EXPECT_EQ(base::string16(), contents()->GetTitle());
346 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
347 const GURL kGURL("chrome://blah");
348 const base::string16 title = base::ASCIIToUTF16("My Title");
349 controller().LoadURL(
350 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
352 NavigationEntry* entry = controller().GetVisibleEntry();
353 ASSERT_EQ(kGURL, entry->GetURL());
354 entry->SetTitle(title);
356 EXPECT_EQ(title, contents()->GetTitle());
359 // Test view source mode for a webui page.
360 TEST_F(WebContentsImplTest, NTPViewSource) {
361 NavigationControllerImpl& cont =
362 static_cast<NavigationControllerImpl&>(controller());
363 const char kUrl[] = "view-source:chrome://blah";
364 const GURL kGURL(kUrl);
366 process()->sink().ClearMessages();
368 cont.LoadURL(
369 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
370 rvh()->GetDelegate()->RenderViewCreated(rvh());
371 // Did we get the expected message?
372 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
373 ViewMsg_EnableViewSourceMode::ID));
375 FrameHostMsg_DidCommitProvisionalLoad_Params params;
376 InitNavigateParams(&params, 0, kGURL, PAGE_TRANSITION_TYPED);
377 LoadCommittedDetails details;
378 cont.RendererDidNavigate(main_test_rfh(), params, &details);
379 // Also check title and url.
380 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
383 // Test to ensure UpdateMaxPageID is working properly.
384 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
385 SiteInstance* instance1 = contents()->GetSiteInstance();
386 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
388 // Starts at -1.
389 EXPECT_EQ(-1, contents()->GetMaxPageID());
390 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
391 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
393 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
394 contents()->UpdateMaxPageID(3);
395 contents()->UpdateMaxPageID(1);
396 EXPECT_EQ(3, contents()->GetMaxPageID());
397 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
398 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
400 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
401 EXPECT_EQ(3, contents()->GetMaxPageID());
402 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
403 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
406 // Test simple same-SiteInstance navigation.
407 TEST_F(WebContentsImplTest, SimpleNavigation) {
408 TestRenderViewHost* orig_rvh = test_rvh();
409 SiteInstance* instance1 = contents()->GetSiteInstance();
410 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
412 // Navigate to URL
413 const GURL url("http://www.google.com");
414 controller().LoadURL(
415 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
416 EXPECT_FALSE(contents()->cross_navigation_pending());
417 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
418 // Controller's pending entry will have a NULL site instance until we assign
419 // it in DidNavigate.
420 EXPECT_TRUE(
421 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
422 site_instance() == NULL);
424 // DidNavigate from the page
425 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
426 EXPECT_FALSE(contents()->cross_navigation_pending());
427 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
428 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
429 // Controller's entry should now have the SiteInstance, or else we won't be
430 // able to find it later.
431 EXPECT_EQ(
432 instance1,
433 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
434 site_instance());
437 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
438 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
439 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
440 const GURL url(std::string("http://example.org/").append(
441 GetMaxURLChars() + 1, 'a'));
443 controller().LoadURL(
444 url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
445 EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
448 // Test that navigating across a site boundary creates a new RenderViewHost
449 // with a new SiteInstance. Going back should do the same.
450 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
451 contents()->transition_cross_site = true;
452 TestRenderViewHost* orig_rvh = test_rvh();
453 RenderFrameHostImpl* orig_rfh =
454 contents()->GetFrameTree()->root()->current_frame_host();
455 int orig_rvh_delete_count = 0;
456 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
457 SiteInstance* instance1 = contents()->GetSiteInstance();
459 // Navigate to URL. First URL should use first RenderViewHost.
460 const GURL url("http://www.google.com");
461 controller().LoadURL(
462 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
463 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
465 // Keep the number of active views in orig_rvh's SiteInstance
466 // non-zero so that orig_rvh doesn't get deleted when it gets
467 // swapped out.
468 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
469 increment_active_view_count();
471 EXPECT_FALSE(contents()->cross_navigation_pending());
472 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
473 EXPECT_EQ(url, contents()->GetLastCommittedURL());
474 EXPECT_EQ(url, contents()->GetVisibleURL());
476 // Navigate to new site
477 const GURL url2("http://www.yahoo.com");
478 controller().LoadURL(
479 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
480 EXPECT_TRUE(contents()->cross_navigation_pending());
481 EXPECT_EQ(url, contents()->GetLastCommittedURL());
482 EXPECT_EQ(url2, contents()->GetVisibleURL());
483 TestRenderViewHost* pending_rvh =
484 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
485 int pending_rvh_delete_count = 0;
486 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
487 RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()->
488 render_manager()->pending_frame_host();
490 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
491 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
492 orig_rvh->SendBeforeUnloadACK(true);
493 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
495 // DidNavigate from the pending page
496 contents()->TestDidNavigate(
497 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
498 SiteInstance* instance2 = contents()->GetSiteInstance();
500 // Keep the number of active views in pending_rvh's SiteInstance
501 // non-zero so that orig_rvh doesn't get deleted when it gets
502 // swapped out.
503 static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
504 increment_active_view_count();
506 EXPECT_FALSE(contents()->cross_navigation_pending());
507 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
508 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
509 EXPECT_EQ(url2, contents()->GetVisibleURL());
510 EXPECT_NE(instance1, instance2);
511 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
512 // We keep the original RFH around, swapped out.
513 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
514 orig_rfh));
515 EXPECT_EQ(orig_rvh_delete_count, 0);
517 // Going back should switch SiteInstances again. The first SiteInstance is
518 // stored in the NavigationEntry, so it should be the same as at the start.
519 // We should use the same RVH as before, swapping it back in.
520 controller().GoBack();
521 TestRenderViewHost* goback_rvh =
522 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
523 EXPECT_EQ(orig_rvh, goback_rvh);
524 EXPECT_TRUE(contents()->cross_navigation_pending());
526 // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
527 EXPECT_TRUE(goback_rvh->are_navigations_suspended());
528 pending_rvh->SendBeforeUnloadACK(true);
529 EXPECT_FALSE(goback_rvh->are_navigations_suspended());
531 // DidNavigate from the back action
532 contents()->TestDidNavigate(
533 goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
534 EXPECT_FALSE(contents()->cross_navigation_pending());
535 EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
536 EXPECT_EQ(instance1, contents()->GetSiteInstance());
537 // The pending RFH should now be swapped out, not deleted.
538 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
539 IsOnSwappedOutList(pending_rfh));
540 EXPECT_EQ(pending_rvh_delete_count, 0);
541 pending_rvh->OnSwappedOut(false);
543 // Close contents and ensure RVHs are deleted.
544 DeleteContents();
545 EXPECT_EQ(orig_rvh_delete_count, 1);
546 EXPECT_EQ(pending_rvh_delete_count, 1);
549 // Test that navigating across a site boundary after a crash creates a new
550 // RVH without requiring a cross-site transition (i.e., PENDING state).
551 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
552 contents()->transition_cross_site = true;
553 TestRenderViewHost* orig_rvh = test_rvh();
554 int orig_rvh_delete_count = 0;
555 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
556 SiteInstance* instance1 = contents()->GetSiteInstance();
558 // Navigate to URL. First URL should use first RenderViewHost.
559 const GURL url("http://www.google.com");
560 controller().LoadURL(
561 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
562 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
564 EXPECT_FALSE(contents()->cross_navigation_pending());
565 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
567 // Crash the renderer.
568 orig_rvh->set_render_view_created(false);
570 // Navigate to new site. We should not go into PENDING.
571 const GURL url2("http://www.yahoo.com");
572 controller().LoadURL(
573 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
574 RenderViewHost* new_rvh = rvh();
575 EXPECT_FALSE(contents()->cross_navigation_pending());
576 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
577 EXPECT_NE(orig_rvh, new_rvh);
578 EXPECT_EQ(orig_rvh_delete_count, 1);
580 // DidNavigate from the new page
581 contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
582 SiteInstance* instance2 = contents()->GetSiteInstance();
584 EXPECT_FALSE(contents()->cross_navigation_pending());
585 EXPECT_EQ(new_rvh, rvh());
586 EXPECT_NE(instance1, instance2);
587 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
589 // Close contents and ensure RVHs are deleted.
590 DeleteContents();
591 EXPECT_EQ(orig_rvh_delete_count, 1);
594 // Test that opening a new contents in the same SiteInstance and then navigating
595 // both contentses to a new site will place both contentses in a single
596 // SiteInstance.
597 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
598 contents()->transition_cross_site = true;
599 TestRenderViewHost* orig_rvh = test_rvh();
600 SiteInstance* instance1 = contents()->GetSiteInstance();
602 // Navigate to URL. First URL should use first RenderViewHost.
603 const GURL url("http://www.google.com");
604 controller().LoadURL(
605 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
606 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
608 // Open a new contents with the same SiteInstance, navigated to the same site.
609 scoped_ptr<TestWebContents> contents2(
610 TestWebContents::Create(browser_context(), instance1));
611 contents2->transition_cross_site = true;
612 contents2->GetController().LoadURL(url, Referrer(),
613 PAGE_TRANSITION_TYPED,
614 std::string());
615 // Need this page id to be 2 since the site instance is the same (which is the
616 // scope of page IDs) and we want to consider this a new page.
617 contents2->TestDidNavigate(
618 contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
620 // Navigate first contents to a new site.
621 const GURL url2a("http://www.yahoo.com");
622 controller().LoadURL(
623 url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
624 orig_rvh->SendBeforeUnloadACK(true);
625 TestRenderViewHost* pending_rvh_a =
626 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
627 contents()->TestDidNavigate(
628 pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
629 SiteInstance* instance2a = contents()->GetSiteInstance();
630 EXPECT_NE(instance1, instance2a);
632 // Navigate second contents to the same site as the first tab.
633 const GURL url2b("http://mail.yahoo.com");
634 contents2->GetController().LoadURL(url2b, Referrer(),
635 PAGE_TRANSITION_TYPED,
636 std::string());
637 TestRenderViewHost* rvh2 =
638 static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
639 rvh2->SendBeforeUnloadACK(true);
640 TestRenderViewHost* pending_rvh_b =
641 static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
642 EXPECT_TRUE(pending_rvh_b != NULL);
643 EXPECT_TRUE(contents2->cross_navigation_pending());
645 // NOTE(creis): We used to be in danger of showing a crash page here if the
646 // second contents hadn't navigated somewhere first (bug 1145430). That case
647 // is now covered by the CrossSiteBoundariesAfterCrash test.
648 contents2->TestDidNavigate(
649 pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
650 SiteInstance* instance2b = contents2->GetSiteInstance();
651 EXPECT_NE(instance1, instance2b);
653 // Both contentses should now be in the same SiteInstance.
654 EXPECT_EQ(instance2a, instance2b);
657 TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
658 WebContentsImplTestBrowserClient browser_client;
659 SetBrowserClientForTesting(&browser_client);
661 contents()->transition_cross_site = true;
662 TestRenderViewHost* orig_rvh = test_rvh();
663 RenderFrameHostImpl* orig_rfh =
664 contents()->GetFrameTree()->root()->current_frame_host();
665 int orig_rvh_delete_count = 0;
666 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
667 SiteInstanceImpl* orig_instance =
668 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
670 browser_client.set_assign_site_for_url(false);
671 // Navigate to an URL that will not assign a new SiteInstance.
672 const GURL native_url("non-site-url://stuffandthings");
673 controller().LoadURL(
674 native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
675 contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
677 EXPECT_FALSE(contents()->cross_navigation_pending());
678 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
679 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
680 EXPECT_EQ(native_url, contents()->GetVisibleURL());
681 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
682 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
683 EXPECT_FALSE(orig_instance->HasSite());
685 browser_client.set_assign_site_for_url(true);
686 // Navigate to new site (should keep same site instance).
687 const GURL url("http://www.google.com");
688 controller().LoadURL(
689 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
690 EXPECT_FALSE(contents()->cross_navigation_pending());
691 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
692 EXPECT_EQ(url, contents()->GetVisibleURL());
693 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
694 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
696 // Keep the number of active views in orig_rvh's SiteInstance
697 // non-zero so that orig_rvh doesn't get deleted when it gets
698 // swapped out.
699 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
700 increment_active_view_count();
702 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
703 EXPECT_TRUE(
704 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
705 EXPECT_EQ(url, contents()->GetLastCommittedURL());
707 // Navigate to another new site (should create a new site instance).
708 const GURL url2("http://www.yahoo.com");
709 controller().LoadURL(
710 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
711 EXPECT_TRUE(contents()->cross_navigation_pending());
712 EXPECT_EQ(url, contents()->GetLastCommittedURL());
713 EXPECT_EQ(url2, contents()->GetVisibleURL());
714 TestRenderViewHost* pending_rvh =
715 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
716 int pending_rvh_delete_count = 0;
717 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
719 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
720 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
721 orig_rvh->SendBeforeUnloadACK(true);
722 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
724 // DidNavigate from the pending page.
725 contents()->TestDidNavigate(
726 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
727 SiteInstance* new_instance = contents()->GetSiteInstance();
729 EXPECT_FALSE(contents()->cross_navigation_pending());
730 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
731 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
732 EXPECT_EQ(url2, contents()->GetVisibleURL());
733 EXPECT_NE(new_instance, orig_instance);
734 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
735 // We keep the original RFH around, swapped out.
736 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
737 orig_rfh));
738 EXPECT_EQ(orig_rvh_delete_count, 0);
739 orig_rvh->OnSwappedOut(false);
741 // Close contents and ensure RVHs are deleted.
742 DeleteContents();
743 EXPECT_EQ(orig_rvh_delete_count, 1);
744 EXPECT_EQ(pending_rvh_delete_count, 1);
747 // Test that we can find an opener RVH even if it's pending.
748 // http://crbug.com/176252.
749 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
750 contents()->transition_cross_site = true;
751 TestRenderViewHost* orig_rvh = test_rvh();
753 // Navigate to a URL.
754 const GURL url("http://www.google.com");
755 controller().LoadURL(
756 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
757 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
759 // Start to navigate first tab to a new site, so that it has a pending RVH.
760 const GURL url2("http://www.yahoo.com");
761 controller().LoadURL(
762 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
763 orig_rvh->SendBeforeUnloadACK(true);
764 TestRenderViewHost* pending_rvh =
765 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
767 // While it is still pending, simulate opening a new tab with the first tab
768 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
769 // on the opener to ensure that an RVH exists.
770 int opener_routing_id = contents()->CreateOpenerRenderViews(
771 pending_rvh->GetSiteInstance());
773 // We should find the pending RVH and not create a new one.
774 EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
777 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
778 // to determine whether a navigation is cross-site.
779 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
780 contents()->transition_cross_site = true;
781 RenderViewHost* orig_rvh = rvh();
782 SiteInstance* instance1 = contents()->GetSiteInstance();
784 // Navigate to URL.
785 const GURL url("http://www.google.com");
786 controller().LoadURL(
787 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
788 contents()->TestDidNavigate(
789 orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
791 // Open a related contents to a second site.
792 scoped_ptr<TestWebContents> contents2(
793 TestWebContents::Create(browser_context(), instance1));
794 contents2->transition_cross_site = true;
795 const GURL url2("http://www.yahoo.com");
796 contents2->GetController().LoadURL(url2, Referrer(),
797 PAGE_TRANSITION_TYPED,
798 std::string());
799 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
800 // pending.
801 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
802 contents2->GetRenderViewHost());
803 EXPECT_FALSE(contents2->cross_navigation_pending());
804 contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
805 SiteInstance* instance2 = contents2->GetSiteInstance();
806 EXPECT_NE(instance1, instance2);
807 EXPECT_FALSE(contents2->cross_navigation_pending());
809 // Simulate a link click in first contents to second site. Doesn't switch
810 // SiteInstances, because we don't intercept WebKit navigations.
811 contents()->TestDidNavigate(
812 orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
813 SiteInstance* instance3 = contents()->GetSiteInstance();
814 EXPECT_EQ(instance1, instance3);
815 EXPECT_FALSE(contents()->cross_navigation_pending());
817 // Navigate to the new site. Doesn't switch SiteInstancees, because we
818 // compare against the current URL, not the SiteInstance's site.
819 const GURL url3("http://mail.yahoo.com");
820 controller().LoadURL(
821 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
822 EXPECT_FALSE(contents()->cross_navigation_pending());
823 contents()->TestDidNavigate(
824 orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
825 SiteInstance* instance4 = contents()->GetSiteInstance();
826 EXPECT_EQ(instance1, instance4);
829 // Test that the onbeforeunload and onunload handlers run when navigating
830 // across site boundaries.
831 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
832 contents()->transition_cross_site = true;
833 TestRenderViewHost* orig_rvh = test_rvh();
834 SiteInstance* instance1 = contents()->GetSiteInstance();
836 // Navigate to URL. First URL should use first RenderViewHost.
837 const GURL url("http://www.google.com");
838 controller().LoadURL(
839 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
840 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
841 EXPECT_FALSE(contents()->cross_navigation_pending());
842 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
844 // Navigate to new site, but simulate an onbeforeunload denial.
845 const GURL url2("http://www.yahoo.com");
846 controller().LoadURL(
847 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
848 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
849 base::TimeTicks now = base::TimeTicks::Now();
850 orig_rvh->GetMainFrame()->OnMessageReceived(
851 FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
852 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
853 EXPECT_FALSE(contents()->cross_navigation_pending());
854 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
856 // Navigate again, but simulate an onbeforeunload approval.
857 controller().LoadURL(
858 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
859 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
860 now = base::TimeTicks::Now();
861 orig_rvh->GetMainFrame()->OnMessageReceived(
862 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
863 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
864 EXPECT_TRUE(contents()->cross_navigation_pending());
865 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
866 contents()->GetPendingRenderViewHost());
868 // We won't hear DidNavigate until the onunload handler has finished running.
870 // DidNavigate from the pending page.
871 contents()->TestDidNavigate(
872 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
873 SiteInstance* instance2 = contents()->GetSiteInstance();
874 EXPECT_FALSE(contents()->cross_navigation_pending());
875 EXPECT_EQ(pending_rvh, rvh());
876 EXPECT_NE(instance1, instance2);
877 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
880 // Test that during a slow cross-site navigation, the original renderer can
881 // navigate to a different URL and have it displayed, canceling the slow
882 // navigation.
883 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
884 contents()->transition_cross_site = true;
885 TestRenderViewHost* orig_rvh = test_rvh();
886 SiteInstance* instance1 = contents()->GetSiteInstance();
888 // Navigate to URL. First URL should use first RenderViewHost.
889 const GURL url("http://www.google.com");
890 controller().LoadURL(
891 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
892 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
893 EXPECT_FALSE(contents()->cross_navigation_pending());
894 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
896 // Navigate to new site, simulating an onbeforeunload approval.
897 const GURL url2("http://www.yahoo.com");
898 controller().LoadURL(
899 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
900 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
901 base::TimeTicks now = base::TimeTicks::Now();
902 orig_rvh->GetMainFrame()->OnMessageReceived(
903 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
904 EXPECT_TRUE(contents()->cross_navigation_pending());
906 // Suppose the original renderer navigates before the new one is ready.
907 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
909 // Verify that the pending navigation is cancelled.
910 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
911 SiteInstance* instance2 = contents()->GetSiteInstance();
912 EXPECT_FALSE(contents()->cross_navigation_pending());
913 EXPECT_EQ(orig_rvh, rvh());
914 EXPECT_EQ(instance1, instance2);
915 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
918 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
919 contents()->transition_cross_site = true;
921 // Start with a web ui page, which gets a new RVH with WebUI bindings.
922 const GURL url1("chrome://blah");
923 controller().LoadURL(
924 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
925 TestRenderViewHost* ntp_rvh = test_rvh();
926 contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
927 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
928 SiteInstance* instance1 = contents()->GetSiteInstance();
930 EXPECT_FALSE(contents()->cross_navigation_pending());
931 EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
932 EXPECT_EQ(url1, entry1->GetURL());
933 EXPECT_EQ(instance1,
934 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
935 EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
937 // Navigate to new site.
938 const GURL url2("http://www.google.com");
939 controller().LoadURL(
940 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
941 EXPECT_TRUE(contents()->cross_navigation_pending());
942 TestRenderViewHost* google_rvh =
943 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
945 // Simulate beforeunload approval.
946 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
947 base::TimeTicks now = base::TimeTicks::Now();
948 ntp_rvh->GetMainFrame()->OnMessageReceived(
949 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
951 // DidNavigate from the pending page.
952 contents()->TestDidNavigate(
953 google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
954 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
955 SiteInstance* instance2 = contents()->GetSiteInstance();
957 EXPECT_FALSE(contents()->cross_navigation_pending());
958 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
959 EXPECT_NE(instance1, instance2);
960 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
961 EXPECT_EQ(url2, entry2->GetURL());
962 EXPECT_EQ(instance2,
963 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
964 EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
966 // Navigate to third page on same site.
967 const GURL url3("http://news.google.com");
968 controller().LoadURL(
969 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
970 EXPECT_FALSE(contents()->cross_navigation_pending());
971 contents()->TestDidNavigate(
972 google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
973 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
974 SiteInstance* instance3 = contents()->GetSiteInstance();
976 EXPECT_FALSE(contents()->cross_navigation_pending());
977 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
978 EXPECT_EQ(instance2, instance3);
979 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
980 EXPECT_EQ(url3, entry3->GetURL());
981 EXPECT_EQ(instance3,
982 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
984 // Go back within the site.
985 controller().GoBack();
986 EXPECT_FALSE(contents()->cross_navigation_pending());
987 EXPECT_EQ(entry2, controller().GetPendingEntry());
989 // Before that commits, go back again.
990 controller().GoBack();
991 EXPECT_TRUE(contents()->cross_navigation_pending());
992 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
993 EXPECT_EQ(entry1, controller().GetPendingEntry());
995 // Simulate beforeunload approval.
996 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
997 now = base::TimeTicks::Now();
998 google_rvh->GetMainFrame()->OnMessageReceived(
999 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1001 // DidNavigate from the first back. This aborts the second back's pending RVH.
1002 contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1004 // We should commit this page and forget about the second back.
1005 EXPECT_FALSE(contents()->cross_navigation_pending());
1006 EXPECT_FALSE(controller().GetPendingEntry());
1007 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
1008 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
1010 // We should not have corrupted the NTP entry.
1011 EXPECT_EQ(instance3,
1012 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1013 EXPECT_EQ(instance2,
1014 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1015 EXPECT_EQ(instance1,
1016 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1017 EXPECT_EQ(url1, entry1->GetURL());
1020 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1021 // original renderer will not cancel the slow navigation (bug 42029).
1022 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
1023 contents()->transition_cross_site = true;
1024 TestRenderViewHost* orig_rvh = test_rvh();
1026 // Navigate to URL. First URL should use first RenderViewHost.
1027 const GURL url("http://www.google.com");
1028 controller().LoadURL(
1029 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1030 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1031 EXPECT_FALSE(contents()->cross_navigation_pending());
1032 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1034 // Start navigating to new site.
1035 const GURL url2("http://www.yahoo.com");
1036 controller().LoadURL(
1037 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1039 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1040 // waiting for a before unload response.
1041 orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
1042 PAGE_TRANSITION_AUTO_SUBFRAME);
1043 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1045 // Now simulate the onbeforeunload approval and verify the navigation is
1046 // not canceled.
1047 base::TimeTicks now = base::TimeTicks::Now();
1048 orig_rvh->GetMainFrame()->OnMessageReceived(
1049 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1050 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1051 EXPECT_TRUE(contents()->cross_navigation_pending());
1054 // Test that a cross-site navigation is not preempted if the previous
1055 // renderer sends a FrameNavigate message just before being told to stop.
1056 // We should only preempt the cross-site navigation if the previous renderer
1057 // has started a new navigation. See http://crbug.com/79176.
1058 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1059 contents()->transition_cross_site = true;
1061 // Navigate to NTP URL.
1062 const GURL url("chrome://blah");
1063 controller().LoadURL(
1064 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1065 TestRenderViewHost* orig_rvh = test_rvh();
1066 EXPECT_FALSE(contents()->cross_navigation_pending());
1068 // Navigate to new site, with the beforeunload request in flight.
1069 const GURL url2("http://www.yahoo.com");
1070 controller().LoadURL(
1071 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1072 TestRenderViewHost* pending_rvh =
1073 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1074 EXPECT_TRUE(contents()->cross_navigation_pending());
1075 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1077 // Suppose the first navigation tries to commit now, with a
1078 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1079 // but it should act as if the beforeunload ack arrived.
1080 orig_rvh->SendNavigate(1, GURL("chrome://blah"));
1081 EXPECT_TRUE(contents()->cross_navigation_pending());
1082 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1083 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1085 // The pending navigation should be able to commit successfully.
1086 contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1087 EXPECT_FALSE(contents()->cross_navigation_pending());
1088 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
1091 // Test that the original renderer cannot preempt a cross-site navigation once
1092 // the unload request has been made. At this point, the cross-site navigation
1093 // is almost ready to be displayed, and the original renderer is only given a
1094 // short chance to run an unload handler. Prevents regression of bug 23942.
1095 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
1096 contents()->transition_cross_site = true;
1097 TestRenderViewHost* orig_rvh = test_rvh();
1098 SiteInstance* instance1 = contents()->GetSiteInstance();
1100 // Navigate to URL. First URL should use first RenderViewHost.
1101 const GURL url("http://www.google.com");
1102 controller().LoadURL(
1103 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1104 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1105 EXPECT_FALSE(contents()->cross_navigation_pending());
1106 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1108 // Navigate to new site, simulating an onbeforeunload approval.
1109 const GURL url2("http://www.yahoo.com");
1110 controller().LoadURL(
1111 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1112 base::TimeTicks now = base::TimeTicks::Now();
1113 orig_rvh->GetMainFrame()->OnMessageReceived(
1114 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1115 EXPECT_TRUE(contents()->cross_navigation_pending());
1116 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
1117 contents()->GetPendingRenderViewHost());
1119 // Simulate the pending renderer's response, which leads to an unload request
1120 // being sent to orig_rvh.
1121 std::vector<GURL> url_chain;
1122 url_chain.push_back(GURL());
1123 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1124 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1125 GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
1126 url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
1128 // Suppose the original renderer navigates now, while the unload request is in
1129 // flight. We should ignore it, wait for the unload ack, and let the pending
1130 // request continue. Otherwise, the contents may close spontaneously or stop
1131 // responding to navigation requests. (See bug 23942.)
1132 FrameHostMsg_DidCommitProvisionalLoad_Params params1a;
1133 InitNavigateParams(&params1a, 2, GURL("http://www.google.com/foo"),
1134 PAGE_TRANSITION_TYPED);
1135 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1137 // Verify that the pending navigation is still in progress.
1138 EXPECT_TRUE(contents()->cross_navigation_pending());
1139 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
1141 // DidNavigate from the pending page should commit it.
1142 contents()->TestDidNavigate(
1143 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1144 SiteInstance* instance2 = contents()->GetSiteInstance();
1145 EXPECT_FALSE(contents()->cross_navigation_pending());
1146 EXPECT_EQ(pending_rvh, rvh());
1147 EXPECT_NE(instance1, instance2);
1148 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1151 // Test that a cross-site navigation that doesn't commit after the unload
1152 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1153 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1154 contents()->transition_cross_site = true;
1155 TestRenderViewHost* orig_rvh = test_rvh();
1156 SiteInstance* instance1 = contents()->GetSiteInstance();
1158 // Navigate to URL. First URL should use first RenderViewHost.
1159 const GURL url("http://www.google.com");
1160 controller().LoadURL(
1161 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1162 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1163 EXPECT_FALSE(contents()->cross_navigation_pending());
1164 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1166 // Navigate to new site, simulating an onbeforeunload approval.
1167 const GURL url2("http://www.yahoo.com");
1168 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1169 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1170 base::TimeTicks now = base::TimeTicks::Now();
1171 orig_rvh->GetMainFrame()->OnMessageReceived(
1172 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1173 EXPECT_TRUE(contents()->cross_navigation_pending());
1175 // Simulate swap out message when the response arrives.
1176 orig_rvh->OnSwappedOut(false);
1178 // Suppose the navigation doesn't get a chance to commit, and the user
1179 // navigates in the current RVH's SiteInstance.
1180 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1182 // Verify that the pending navigation is cancelled and the renderer is no
1183 // longer swapped out.
1184 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1185 SiteInstance* instance2 = contents()->GetSiteInstance();
1186 EXPECT_FALSE(contents()->cross_navigation_pending());
1187 EXPECT_EQ(orig_rvh, rvh());
1188 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, orig_rvh->rvh_state());
1189 EXPECT_EQ(instance1, instance2);
1190 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1193 // Test that NavigationEntries have the correct page state after going
1194 // forward and back. Prevents regression for bug 1116137.
1195 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1196 TestRenderViewHost* orig_rvh = test_rvh();
1198 // Navigate to URL. There should be no committed entry yet.
1199 const GURL url("http://www.google.com");
1200 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1201 NavigationEntry* entry = controller().GetLastCommittedEntry();
1202 EXPECT_TRUE(entry == NULL);
1204 // Committed entry should have page state after DidNavigate.
1205 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1206 entry = controller().GetLastCommittedEntry();
1207 EXPECT_TRUE(entry->GetPageState().IsValid());
1209 // Navigate to same site.
1210 const GURL url2("http://images.google.com");
1211 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1212 entry = controller().GetLastCommittedEntry();
1213 EXPECT_TRUE(entry->GetPageState().IsValid());
1215 // Committed entry should have page state after DidNavigate.
1216 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1217 entry = controller().GetLastCommittedEntry();
1218 EXPECT_TRUE(entry->GetPageState().IsValid());
1220 // Now go back. Committed entry should still have page state.
1221 controller().GoBack();
1222 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1223 entry = controller().GetLastCommittedEntry();
1224 EXPECT_TRUE(entry->GetPageState().IsValid());
1227 // Test that NavigationEntries have the correct page state and SiteInstance
1228 // state after opening a new window to about:blank. Prevents regression for
1229 // bugs b/1116137 and http://crbug.com/111975.
1230 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1231 TestRenderViewHost* orig_rvh = test_rvh();
1233 // When opening a new window, it is navigated to about:blank internally.
1234 // Currently, this results in two DidNavigate events.
1235 const GURL url(kAboutBlankURL);
1236 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1237 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1239 // Should have a page state here.
1240 NavigationEntry* entry = controller().GetLastCommittedEntry();
1241 EXPECT_TRUE(entry->GetPageState().IsValid());
1243 // The SiteInstance should be available for other navigations to use.
1244 NavigationEntryImpl* entry_impl =
1245 NavigationEntryImpl::FromNavigationEntry(entry);
1246 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1247 int32 site_instance_id = entry_impl->site_instance()->GetId();
1249 // Navigating to a normal page should not cause a process swap.
1250 const GURL new_url("http://www.google.com");
1251 controller().LoadURL(new_url, Referrer(),
1252 PAGE_TRANSITION_TYPED, std::string());
1253 EXPECT_FALSE(contents()->cross_navigation_pending());
1254 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1255 contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1256 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1257 controller().GetLastCommittedEntry());
1258 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1259 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1262 // Tests that fullscreen is exited throughout the object hierarchy when
1263 // navigating to a new page.
1264 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
1265 FakeFullscreenDelegate fake_delegate;
1266 contents()->SetDelegate(&fake_delegate);
1267 TestRenderViewHost* orig_rvh = test_rvh();
1269 // Navigate to a site.
1270 const GURL url("http://www.google.com");
1271 controller().LoadURL(
1272 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1273 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1274 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1276 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1277 EXPECT_FALSE(orig_rvh->IsFullscreen());
1278 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1279 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1280 orig_rvh->OnMessageReceived(
1281 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1282 EXPECT_TRUE(orig_rvh->IsFullscreen());
1283 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1284 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1286 // Navigate to a new site.
1287 const GURL url2("http://www.yahoo.com");
1288 controller().LoadURL(
1289 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1290 RenderViewHost* const pending_rvh = contents()->GetPendingRenderViewHost();
1291 contents()->TestDidNavigate(
1292 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1294 // Confirm fullscreen has exited.
1295 EXPECT_FALSE(orig_rvh->IsFullscreen());
1296 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1297 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1299 contents()->SetDelegate(NULL);
1302 // Tests that fullscreen is exited throughout the object hierarchy when
1303 // instructing NavigationController to GoBack() or GoForward().
1304 TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
1305 FakeFullscreenDelegate fake_delegate;
1306 contents()->SetDelegate(&fake_delegate);
1307 TestRenderViewHost* const orig_rvh = test_rvh();
1309 // Navigate to a site.
1310 const GURL url("http://www.google.com");
1311 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1312 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1313 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1315 // Now, navigate to another page on the same site.
1316 const GURL url2("http://www.google.com/search?q=kittens");
1317 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1318 EXPECT_FALSE(contents()->cross_navigation_pending());
1319 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1320 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1322 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1323 EXPECT_FALSE(orig_rvh->IsFullscreen());
1324 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1325 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1327 for (int i = 0; i < 2; ++i) {
1328 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1329 orig_rvh->OnMessageReceived(
1330 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1331 EXPECT_TRUE(orig_rvh->IsFullscreen());
1332 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1333 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1335 // Navigate backward (or forward).
1336 if (i == 0)
1337 controller().GoBack();
1338 else
1339 controller().GoForward();
1340 EXPECT_FALSE(contents()->cross_navigation_pending());
1341 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1342 contents()->TestDidNavigate(
1343 orig_rvh, i + 1, url, PAGE_TRANSITION_FORWARD_BACK);
1345 // Confirm fullscreen has exited.
1346 EXPECT_FALSE(orig_rvh->IsFullscreen());
1347 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1348 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1351 contents()->SetDelegate(NULL);
1354 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1355 // crash.
1356 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
1357 FakeFullscreenDelegate fake_delegate;
1358 contents()->SetDelegate(&fake_delegate);
1360 // Navigate to a site.
1361 const GURL url("http://www.google.com");
1362 controller().LoadURL(
1363 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1364 contents()->TestDidNavigate(test_rvh(), 1, url, PAGE_TRANSITION_TYPED);
1365 EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
1367 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1368 EXPECT_FALSE(test_rvh()->IsFullscreen());
1369 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1370 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1371 test_rvh()->OnMessageReceived(
1372 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1373 EXPECT_TRUE(test_rvh()->IsFullscreen());
1374 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1375 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1377 // Crash the renderer.
1378 test_rvh()->OnMessageReceived(
1379 ViewHostMsg_RenderProcessGone(
1380 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1382 // Confirm fullscreen has exited.
1383 EXPECT_FALSE(test_rvh()->IsFullscreen());
1384 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1385 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1387 contents()->SetDelegate(NULL);
1390 ////////////////////////////////////////////////////////////////////////////////
1391 // Interstitial Tests
1392 ////////////////////////////////////////////////////////////////////////////////
1394 // Test navigating to a page (with the navigation initiated from the browser,
1395 // as when a URL is typed in the location bar) that shows an interstitial and
1396 // creates a new navigation entry, then hiding it without proceeding.
1397 TEST_F(WebContentsImplTest,
1398 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1399 // Navigate to a page.
1400 GURL url1("http://www.google.com");
1401 test_rvh()->SendNavigate(1, url1);
1402 EXPECT_EQ(1, controller().GetEntryCount());
1404 // Initiate a browser navigation that will trigger the interstitial
1405 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1406 PAGE_TRANSITION_TYPED, std::string());
1408 // Show an interstitial.
1409 TestInterstitialPage::InterstitialState state =
1410 TestInterstitialPage::INVALID;
1411 bool deleted = false;
1412 GURL url2("http://interstitial");
1413 TestInterstitialPage* interstitial =
1414 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1415 TestInterstitialPageStateGuard state_guard(interstitial);
1416 interstitial->Show();
1417 // The interstitial should not show until its navigation has committed.
1418 EXPECT_FALSE(interstitial->is_showing());
1419 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1420 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1421 // Let's commit the interstitial navigation.
1422 interstitial->TestDidNavigate(1, url2);
1423 EXPECT_TRUE(interstitial->is_showing());
1424 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1425 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1426 NavigationEntry* entry = controller().GetVisibleEntry();
1427 ASSERT_TRUE(entry != NULL);
1428 EXPECT_TRUE(entry->GetURL() == url2);
1430 // Now don't proceed.
1431 interstitial->DontProceed();
1432 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1433 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1434 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1435 entry = controller().GetVisibleEntry();
1436 ASSERT_TRUE(entry != NULL);
1437 EXPECT_TRUE(entry->GetURL() == url1);
1438 EXPECT_EQ(1, controller().GetEntryCount());
1440 RunAllPendingInMessageLoop();
1441 EXPECT_TRUE(deleted);
1444 // Test navigating to a page (with the navigation initiated from the renderer,
1445 // as when clicking on a link in the page) that shows an interstitial and
1446 // creates a new navigation entry, then hiding it without proceeding.
1447 TEST_F(WebContentsImplTest,
1448 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1449 // Navigate to a page.
1450 GURL url1("http://www.google.com");
1451 test_rvh()->SendNavigate(1, url1);
1452 EXPECT_EQ(1, controller().GetEntryCount());
1454 // Show an interstitial (no pending entry, the interstitial would have been
1455 // triggered by clicking on a link).
1456 TestInterstitialPage::InterstitialState state =
1457 TestInterstitialPage::INVALID;
1458 bool deleted = false;
1459 GURL url2("http://interstitial");
1460 TestInterstitialPage* interstitial =
1461 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1462 TestInterstitialPageStateGuard state_guard(interstitial);
1463 interstitial->Show();
1464 // The interstitial should not show until its navigation has committed.
1465 EXPECT_FALSE(interstitial->is_showing());
1466 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1467 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1468 // Let's commit the interstitial navigation.
1469 interstitial->TestDidNavigate(1, url2);
1470 EXPECT_TRUE(interstitial->is_showing());
1471 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1472 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1473 NavigationEntry* entry = controller().GetVisibleEntry();
1474 ASSERT_TRUE(entry != NULL);
1475 EXPECT_TRUE(entry->GetURL() == url2);
1477 // Now don't proceed.
1478 interstitial->DontProceed();
1479 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1480 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1481 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1482 entry = controller().GetVisibleEntry();
1483 ASSERT_TRUE(entry != NULL);
1484 EXPECT_TRUE(entry->GetURL() == url1);
1485 EXPECT_EQ(1, controller().GetEntryCount());
1487 RunAllPendingInMessageLoop();
1488 EXPECT_TRUE(deleted);
1491 // Test navigating to a page that shows an interstitial without creating a new
1492 // navigation entry (this happens when the interstitial is triggered by a
1493 // sub-resource in the page), then hiding it without proceeding.
1494 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1495 // Navigate to a page.
1496 GURL url1("http://www.google.com");
1497 test_rvh()->SendNavigate(1, url1);
1498 EXPECT_EQ(1, controller().GetEntryCount());
1500 // Show an interstitial.
1501 TestInterstitialPage::InterstitialState state =
1502 TestInterstitialPage::INVALID;
1503 bool deleted = false;
1504 GURL url2("http://interstitial");
1505 TestInterstitialPage* interstitial =
1506 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1507 TestInterstitialPageStateGuard state_guard(interstitial);
1508 interstitial->Show();
1509 // The interstitial should not show until its navigation has committed.
1510 EXPECT_FALSE(interstitial->is_showing());
1511 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1512 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1513 // Let's commit the interstitial navigation.
1514 interstitial->TestDidNavigate(1, url2);
1515 EXPECT_TRUE(interstitial->is_showing());
1516 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1517 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1518 NavigationEntry* entry = controller().GetVisibleEntry();
1519 ASSERT_TRUE(entry != NULL);
1520 // The URL specified to the interstitial should have been ignored.
1521 EXPECT_TRUE(entry->GetURL() == url1);
1523 // Now don't proceed.
1524 interstitial->DontProceed();
1525 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1526 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1527 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1528 entry = controller().GetVisibleEntry();
1529 ASSERT_TRUE(entry != NULL);
1530 EXPECT_TRUE(entry->GetURL() == url1);
1531 EXPECT_EQ(1, controller().GetEntryCount());
1533 RunAllPendingInMessageLoop();
1534 EXPECT_TRUE(deleted);
1537 // Test navigating to a page (with the navigation initiated from the browser,
1538 // as when a URL is typed in the location bar) that shows an interstitial and
1539 // creates a new navigation entry, then proceeding.
1540 TEST_F(WebContentsImplTest,
1541 ShowInterstitialFromBrowserNewNavigationProceed) {
1542 // Navigate to a page.
1543 GURL url1("http://www.google.com");
1544 test_rvh()->SendNavigate(1, url1);
1545 EXPECT_EQ(1, controller().GetEntryCount());
1547 // Initiate a browser navigation that will trigger the interstitial
1548 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1549 PAGE_TRANSITION_TYPED, std::string());
1551 // Show an interstitial.
1552 TestInterstitialPage::InterstitialState state =
1553 TestInterstitialPage::INVALID;
1554 bool deleted = false;
1555 GURL url2("http://interstitial");
1556 TestInterstitialPage* interstitial =
1557 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1558 TestInterstitialPageStateGuard state_guard(interstitial);
1559 interstitial->Show();
1560 // The interstitial should not show until its navigation has committed.
1561 EXPECT_FALSE(interstitial->is_showing());
1562 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1563 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1564 // Let's commit the interstitial navigation.
1565 interstitial->TestDidNavigate(1, url2);
1566 EXPECT_TRUE(interstitial->is_showing());
1567 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1568 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1569 NavigationEntry* entry = controller().GetVisibleEntry();
1570 ASSERT_TRUE(entry != NULL);
1571 EXPECT_TRUE(entry->GetURL() == url2);
1573 // Then proceed.
1574 interstitial->Proceed();
1575 // The interstitial should show until the new navigation commits.
1576 RunAllPendingInMessageLoop();
1577 ASSERT_FALSE(deleted);
1578 EXPECT_EQ(TestInterstitialPage::OKED, state);
1579 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1580 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1582 // Simulate the navigation to the page, that's when the interstitial gets
1583 // hidden.
1584 GURL url3("http://www.thepage.com");
1585 test_rvh()->SendNavigate(2, url3);
1587 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1588 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1589 entry = controller().GetVisibleEntry();
1590 ASSERT_TRUE(entry != NULL);
1591 EXPECT_TRUE(entry->GetURL() == url3);
1593 EXPECT_EQ(2, controller().GetEntryCount());
1595 RunAllPendingInMessageLoop();
1596 EXPECT_TRUE(deleted);
1599 // Test navigating to a page (with the navigation initiated from the renderer,
1600 // as when clicking on a link in the page) that shows an interstitial and
1601 // creates a new navigation entry, then proceeding.
1602 TEST_F(WebContentsImplTest,
1603 ShowInterstitialFromRendererNewNavigationProceed) {
1604 // Navigate to a page.
1605 GURL url1("http://www.google.com");
1606 test_rvh()->SendNavigate(1, url1);
1607 EXPECT_EQ(1, controller().GetEntryCount());
1609 // Show an interstitial.
1610 TestInterstitialPage::InterstitialState state =
1611 TestInterstitialPage::INVALID;
1612 bool deleted = false;
1613 GURL url2("http://interstitial");
1614 TestInterstitialPage* interstitial =
1615 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1616 TestInterstitialPageStateGuard state_guard(interstitial);
1617 interstitial->Show();
1618 // The interstitial should not show until its navigation has committed.
1619 EXPECT_FALSE(interstitial->is_showing());
1620 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1621 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1622 // Let's commit the interstitial navigation.
1623 interstitial->TestDidNavigate(1, url2);
1624 EXPECT_TRUE(interstitial->is_showing());
1625 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1626 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1627 NavigationEntry* entry = controller().GetVisibleEntry();
1628 ASSERT_TRUE(entry != NULL);
1629 EXPECT_TRUE(entry->GetURL() == url2);
1631 // Then proceed.
1632 interstitial->Proceed();
1633 // The interstitial should show until the new navigation commits.
1634 RunAllPendingInMessageLoop();
1635 ASSERT_FALSE(deleted);
1636 EXPECT_EQ(TestInterstitialPage::OKED, state);
1637 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1638 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1640 // Simulate the navigation to the page, that's when the interstitial gets
1641 // hidden.
1642 GURL url3("http://www.thepage.com");
1643 test_rvh()->SendNavigate(2, url3);
1645 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1646 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1647 entry = controller().GetVisibleEntry();
1648 ASSERT_TRUE(entry != NULL);
1649 EXPECT_TRUE(entry->GetURL() == url3);
1651 EXPECT_EQ(2, controller().GetEntryCount());
1653 RunAllPendingInMessageLoop();
1654 EXPECT_TRUE(deleted);
1657 // Test navigating to a page that shows an interstitial without creating a new
1658 // navigation entry (this happens when the interstitial is triggered by a
1659 // sub-resource in the page), then proceeding.
1660 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1661 // Navigate to a page so we have a navigation entry in the controller.
1662 GURL url1("http://www.google.com");
1663 test_rvh()->SendNavigate(1, url1);
1664 EXPECT_EQ(1, controller().GetEntryCount());
1666 // Show an interstitial.
1667 TestInterstitialPage::InterstitialState state =
1668 TestInterstitialPage::INVALID;
1669 bool deleted = false;
1670 GURL url2("http://interstitial");
1671 TestInterstitialPage* interstitial =
1672 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1673 TestInterstitialPageStateGuard state_guard(interstitial);
1674 interstitial->Show();
1675 // The interstitial should not show until its navigation has committed.
1676 EXPECT_FALSE(interstitial->is_showing());
1677 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1678 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1679 // Let's commit the interstitial navigation.
1680 interstitial->TestDidNavigate(1, url2);
1681 EXPECT_TRUE(interstitial->is_showing());
1682 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1683 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1684 NavigationEntry* entry = controller().GetVisibleEntry();
1685 ASSERT_TRUE(entry != NULL);
1686 // The URL specified to the interstitial should have been ignored.
1687 EXPECT_TRUE(entry->GetURL() == url1);
1689 // Then proceed.
1690 interstitial->Proceed();
1691 // Since this is not a new navigation, the previous page is dismissed right
1692 // away and shows the original page.
1693 EXPECT_EQ(TestInterstitialPage::OKED, state);
1694 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1695 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1696 entry = controller().GetVisibleEntry();
1697 ASSERT_TRUE(entry != NULL);
1698 EXPECT_TRUE(entry->GetURL() == url1);
1700 EXPECT_EQ(1, controller().GetEntryCount());
1702 RunAllPendingInMessageLoop();
1703 EXPECT_TRUE(deleted);
1706 // Test navigating to a page that shows an interstitial, then navigating away.
1707 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1708 // Show interstitial.
1709 TestInterstitialPage::InterstitialState state =
1710 TestInterstitialPage::INVALID;
1711 bool deleted = false;
1712 GURL url("http://interstitial");
1713 TestInterstitialPage* interstitial =
1714 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1715 TestInterstitialPageStateGuard state_guard(interstitial);
1716 interstitial->Show();
1717 interstitial->TestDidNavigate(1, url);
1719 // While interstitial showing, navigate to a new URL.
1720 const GURL url2("http://www.yahoo.com");
1721 test_rvh()->SendNavigate(1, url2);
1723 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1725 RunAllPendingInMessageLoop();
1726 EXPECT_TRUE(deleted);
1729 // Test navigating to a page that shows an interstitial, then going back.
1730 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1731 // Navigate to a page so we have a navigation entry in the controller.
1732 GURL url1("http://www.google.com");
1733 test_rvh()->SendNavigate(1, url1);
1734 EXPECT_EQ(1, controller().GetEntryCount());
1736 // Show interstitial.
1737 TestInterstitialPage::InterstitialState state =
1738 TestInterstitialPage::INVALID;
1739 bool deleted = false;
1740 GURL interstitial_url("http://interstitial");
1741 TestInterstitialPage* interstitial =
1742 new TestInterstitialPage(contents(), true, interstitial_url,
1743 &state, &deleted);
1744 TestInterstitialPageStateGuard state_guard(interstitial);
1745 interstitial->Show();
1746 interstitial->TestDidNavigate(2, interstitial_url);
1748 // While the interstitial is showing, go back.
1749 controller().GoBack();
1750 test_rvh()->SendNavigate(1, url1);
1752 // Make sure we are back to the original page and that the interstitial is
1753 // gone.
1754 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1755 NavigationEntry* entry = controller().GetVisibleEntry();
1756 ASSERT_TRUE(entry);
1757 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1759 RunAllPendingInMessageLoop();
1760 EXPECT_TRUE(deleted);
1763 // Test navigating to a page that shows an interstitial, has a renderer crash,
1764 // and then goes back.
1765 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1766 // Navigate to a page so we have a navigation entry in the controller.
1767 GURL url1("http://www.google.com");
1768 test_rvh()->SendNavigate(1, url1);
1769 EXPECT_EQ(1, controller().GetEntryCount());
1771 // Show interstitial.
1772 TestInterstitialPage::InterstitialState state =
1773 TestInterstitialPage::INVALID;
1774 bool deleted = false;
1775 GURL interstitial_url("http://interstitial");
1776 TestInterstitialPage* interstitial =
1777 new TestInterstitialPage(contents(), true, interstitial_url,
1778 &state, &deleted);
1779 TestInterstitialPageStateGuard state_guard(interstitial);
1780 interstitial->Show();
1781 interstitial->TestDidNavigate(2, interstitial_url);
1783 // Crash the renderer
1784 test_rvh()->OnMessageReceived(
1785 ViewHostMsg_RenderProcessGone(
1786 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1788 // While the interstitial is showing, go back.
1789 controller().GoBack();
1790 test_rvh()->SendNavigate(1, url1);
1792 // Make sure we are back to the original page and that the interstitial is
1793 // gone.
1794 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1795 NavigationEntry* entry = controller().GetVisibleEntry();
1796 ASSERT_TRUE(entry);
1797 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1799 RunAllPendingInMessageLoop();
1800 EXPECT_TRUE(deleted);
1803 // Test navigating to a page that shows an interstitial, has the renderer crash,
1804 // and then navigates to the interstitial.
1805 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1806 // Navigate to a page so we have a navigation entry in the controller.
1807 GURL url1("http://www.google.com");
1808 test_rvh()->SendNavigate(1, url1);
1809 EXPECT_EQ(1, controller().GetEntryCount());
1811 // Show interstitial.
1812 TestInterstitialPage::InterstitialState state =
1813 TestInterstitialPage::INVALID;
1814 bool deleted = false;
1815 GURL interstitial_url("http://interstitial");
1816 TestInterstitialPage* interstitial =
1817 new TestInterstitialPage(contents(), true, interstitial_url,
1818 &state, &deleted);
1819 TestInterstitialPageStateGuard state_guard(interstitial);
1820 interstitial->Show();
1822 // Crash the renderer
1823 test_rvh()->OnMessageReceived(
1824 ViewHostMsg_RenderProcessGone(
1825 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1827 interstitial->TestDidNavigate(2, interstitial_url);
1830 // Test navigating to a page that shows an interstitial, then close the
1831 // contents.
1832 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1833 // Show interstitial.
1834 TestInterstitialPage::InterstitialState state =
1835 TestInterstitialPage::INVALID;
1836 bool deleted = false;
1837 GURL url("http://interstitial");
1838 TestInterstitialPage* interstitial =
1839 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1840 TestInterstitialPageStateGuard state_guard(interstitial);
1841 interstitial->Show();
1842 interstitial->TestDidNavigate(1, url);
1844 // Now close the contents.
1845 DeleteContents();
1846 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1848 RunAllPendingInMessageLoop();
1849 EXPECT_TRUE(deleted);
1852 // Test navigating to a page that shows an interstitial, then close the
1853 // contents.
1854 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1855 // Show interstitial.
1856 TestInterstitialPage::InterstitialState state =
1857 TestInterstitialPage::INVALID;
1858 bool deleted = false;
1859 GURL url("http://interstitial");
1860 TestInterstitialPage* interstitial =
1861 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1862 TestInterstitialPageStateGuard state_guard(interstitial);
1863 interstitial->Show();
1864 interstitial->TestDidNavigate(1, url);
1865 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1866 interstitial->GetRenderViewHostForTesting());
1868 // Now close the contents.
1869 DeleteContents();
1870 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1872 // Before the interstitial has a chance to process its shutdown task,
1873 // simulate quitting the browser. This goes through all processes and
1874 // tells them to destruct.
1875 rvh->OnMessageReceived(
1876 ViewHostMsg_RenderProcessGone(0, 0, 0));
1878 RunAllPendingInMessageLoop();
1879 EXPECT_TRUE(deleted);
1882 // Test that after Proceed is called and an interstitial is still shown, no more
1883 // commands get executed.
1884 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1885 // Navigate to a page so we have a navigation entry in the controller.
1886 GURL url1("http://www.google.com");
1887 test_rvh()->SendNavigate(1, url1);
1888 EXPECT_EQ(1, controller().GetEntryCount());
1890 // Show an interstitial.
1891 TestInterstitialPage::InterstitialState state =
1892 TestInterstitialPage::INVALID;
1893 bool deleted = false;
1894 GURL url2("http://interstitial");
1895 TestInterstitialPage* interstitial =
1896 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1897 TestInterstitialPageStateGuard state_guard(interstitial);
1898 interstitial->Show();
1899 interstitial->TestDidNavigate(1, url2);
1901 // Run a command.
1902 EXPECT_EQ(0, interstitial->command_received_count());
1903 interstitial->TestDomOperationResponse("toto");
1904 EXPECT_EQ(1, interstitial->command_received_count());
1906 // Then proceed.
1907 interstitial->Proceed();
1908 RunAllPendingInMessageLoop();
1909 ASSERT_FALSE(deleted);
1911 // While the navigation to the new page is pending, send other commands, they
1912 // should be ignored.
1913 interstitial->TestDomOperationResponse("hello");
1914 interstitial->TestDomOperationResponse("hi");
1915 EXPECT_EQ(1, interstitial->command_received_count());
1918 // Test showing an interstitial while another interstitial is already showing.
1919 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1920 // Navigate to a page so we have a navigation entry in the controller.
1921 GURL start_url("http://www.google.com");
1922 test_rvh()->SendNavigate(1, start_url);
1923 EXPECT_EQ(1, controller().GetEntryCount());
1925 // Show an interstitial.
1926 TestInterstitialPage::InterstitialState state1 =
1927 TestInterstitialPage::INVALID;
1928 bool deleted1 = false;
1929 GURL url1("http://interstitial1");
1930 TestInterstitialPage* interstitial1 =
1931 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1932 TestInterstitialPageStateGuard state_guard1(interstitial1);
1933 interstitial1->Show();
1934 interstitial1->TestDidNavigate(1, url1);
1936 // Now show another interstitial.
1937 TestInterstitialPage::InterstitialState state2 =
1938 TestInterstitialPage::INVALID;
1939 bool deleted2 = false;
1940 GURL url2("http://interstitial2");
1941 TestInterstitialPage* interstitial2 =
1942 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1943 TestInterstitialPageStateGuard state_guard2(interstitial2);
1944 interstitial2->Show();
1945 interstitial2->TestDidNavigate(1, url2);
1947 // Showing interstitial2 should have caused interstitial1 to go away.
1948 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1949 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1951 RunAllPendingInMessageLoop();
1952 EXPECT_TRUE(deleted1);
1953 ASSERT_FALSE(deleted2);
1955 // Let's make sure interstitial2 is working as intended.
1956 interstitial2->Proceed();
1957 GURL landing_url("http://www.thepage.com");
1958 test_rvh()->SendNavigate(2, landing_url);
1960 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1961 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1962 NavigationEntry* entry = controller().GetVisibleEntry();
1963 ASSERT_TRUE(entry != NULL);
1964 EXPECT_TRUE(entry->GetURL() == landing_url);
1965 EXPECT_EQ(2, controller().GetEntryCount());
1966 RunAllPendingInMessageLoop();
1967 EXPECT_TRUE(deleted2);
1970 // Test showing an interstitial, proceeding and then navigating to another
1971 // interstitial.
1972 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
1973 // Navigate to a page so we have a navigation entry in the controller.
1974 GURL start_url("http://www.google.com");
1975 test_rvh()->SendNavigate(1, start_url);
1976 EXPECT_EQ(1, controller().GetEntryCount());
1978 // Show an interstitial.
1979 TestInterstitialPage::InterstitialState state1 =
1980 TestInterstitialPage::INVALID;
1981 bool deleted1 = false;
1982 GURL url1("http://interstitial1");
1983 TestInterstitialPage* interstitial1 =
1984 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1985 TestInterstitialPageStateGuard state_guard1(interstitial1);
1986 interstitial1->Show();
1987 interstitial1->TestDidNavigate(1, url1);
1989 // Take action. The interstitial won't be hidden until the navigation is
1990 // committed.
1991 interstitial1->Proceed();
1992 EXPECT_EQ(TestInterstitialPage::OKED, state1);
1994 // Now show another interstitial (simulating the navigation causing another
1995 // interstitial).
1996 TestInterstitialPage::InterstitialState state2 =
1997 TestInterstitialPage::INVALID;
1998 bool deleted2 = false;
1999 GURL url2("http://interstitial2");
2000 TestInterstitialPage* interstitial2 =
2001 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2002 TestInterstitialPageStateGuard state_guard2(interstitial2);
2003 interstitial2->Show();
2004 interstitial2->TestDidNavigate(1, url2);
2006 // Showing interstitial2 should have caused interstitial1 to go away.
2007 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2008 RunAllPendingInMessageLoop();
2009 EXPECT_TRUE(deleted1);
2010 ASSERT_FALSE(deleted2);
2012 // Let's make sure interstitial2 is working as intended.
2013 interstitial2->Proceed();
2014 GURL landing_url("http://www.thepage.com");
2015 test_rvh()->SendNavigate(2, landing_url);
2017 RunAllPendingInMessageLoop();
2018 EXPECT_TRUE(deleted2);
2019 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2020 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
2021 NavigationEntry* entry = controller().GetVisibleEntry();
2022 ASSERT_TRUE(entry != NULL);
2023 EXPECT_TRUE(entry->GetURL() == landing_url);
2024 EXPECT_EQ(2, controller().GetEntryCount());
2027 // Test that navigating away from an interstitial while it's loading cause it
2028 // not to show.
2029 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
2030 // Show an interstitial.
2031 TestInterstitialPage::InterstitialState state =
2032 TestInterstitialPage::INVALID;
2033 bool deleted = false;
2034 GURL interstitial_url("http://interstitial");
2035 TestInterstitialPage* interstitial =
2036 new TestInterstitialPage(contents(), true, interstitial_url,
2037 &state, &deleted);
2038 TestInterstitialPageStateGuard state_guard(interstitial);
2039 interstitial->Show();
2041 // Let's simulate a navigation initiated from the browser before the
2042 // interstitial finishes loading.
2043 const GURL url("http://www.google.com");
2044 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2045 EXPECT_FALSE(interstitial->is_showing());
2046 RunAllPendingInMessageLoop();
2047 ASSERT_FALSE(deleted);
2049 // Now let's make the interstitial navigation commit.
2050 interstitial->TestDidNavigate(1, interstitial_url);
2052 // After it loaded the interstitial should be gone.
2053 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2055 RunAllPendingInMessageLoop();
2056 EXPECT_TRUE(deleted);
2059 // Test that a new request to show an interstitial while an interstitial is
2060 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2061 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
2062 GURL interstitial_url("http://interstitial");
2064 // Show a first interstitial.
2065 TestInterstitialPage::InterstitialState state1 =
2066 TestInterstitialPage::INVALID;
2067 bool deleted1 = false;
2068 TestInterstitialPage* interstitial1 =
2069 new TestInterstitialPage(contents(), true, interstitial_url,
2070 &state1, &deleted1);
2071 TestInterstitialPageStateGuard state_guard1(interstitial1);
2072 interstitial1->Show();
2074 // Show another interstitial on that same contents before the first one had
2075 // time to load.
2076 TestInterstitialPage::InterstitialState state2 =
2077 TestInterstitialPage::INVALID;
2078 bool deleted2 = false;
2079 TestInterstitialPage* interstitial2 =
2080 new TestInterstitialPage(contents(), true, interstitial_url,
2081 &state2, &deleted2);
2082 TestInterstitialPageStateGuard state_guard2(interstitial2);
2083 interstitial2->Show();
2085 // The first interstitial should have been closed and deleted.
2086 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2087 // The 2nd one should still be OK.
2088 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2090 RunAllPendingInMessageLoop();
2091 EXPECT_TRUE(deleted1);
2092 ASSERT_FALSE(deleted2);
2094 // Make the interstitial navigation commit it should be showing.
2095 interstitial2->TestDidNavigate(1, interstitial_url);
2096 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
2099 // Test showing an interstitial and have its renderer crash.
2100 TEST_F(WebContentsImplTest, InterstitialCrasher) {
2101 // Show an interstitial.
2102 TestInterstitialPage::InterstitialState state =
2103 TestInterstitialPage::INVALID;
2104 bool deleted = false;
2105 GURL url("http://interstitial");
2106 TestInterstitialPage* interstitial =
2107 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2108 TestInterstitialPageStateGuard state_guard(interstitial);
2109 interstitial->Show();
2110 // Simulate a renderer crash before the interstitial is shown.
2111 interstitial->TestRenderViewTerminated(
2112 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2113 // The interstitial should have been dismissed.
2114 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2115 RunAllPendingInMessageLoop();
2116 EXPECT_TRUE(deleted);
2118 // Now try again but this time crash the intersitial after it was shown.
2119 interstitial =
2120 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2121 interstitial->Show();
2122 interstitial->TestDidNavigate(1, url);
2123 // Simulate a renderer crash.
2124 interstitial->TestRenderViewTerminated(
2125 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2126 // The interstitial should have been dismissed.
2127 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2128 RunAllPendingInMessageLoop();
2129 EXPECT_TRUE(deleted);
2132 // Tests that showing an interstitial as a result of a browser initiated
2133 // navigation while an interstitial is showing does not remove the pending
2134 // entry (see http://crbug.com/9791).
2135 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
2136 const char kUrl[] = "http://www.badguys.com/";
2137 const GURL kGURL(kUrl);
2139 // Start a navigation to a page
2140 contents()->GetController().LoadURL(
2141 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2143 // Simulate that navigation triggering an interstitial.
2144 TestInterstitialPage::InterstitialState state =
2145 TestInterstitialPage::INVALID;
2146 bool deleted = false;
2147 TestInterstitialPage* interstitial =
2148 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2149 TestInterstitialPageStateGuard state_guard(interstitial);
2150 interstitial->Show();
2151 interstitial->TestDidNavigate(1, kGURL);
2153 // Initiate a new navigation from the browser that also triggers an
2154 // interstitial.
2155 contents()->GetController().LoadURL(
2156 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2157 TestInterstitialPage::InterstitialState state2 =
2158 TestInterstitialPage::INVALID;
2159 bool deleted2 = false;
2160 TestInterstitialPage* interstitial2 =
2161 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
2162 TestInterstitialPageStateGuard state_guard2(interstitial2);
2163 interstitial2->Show();
2164 interstitial2->TestDidNavigate(1, kGURL);
2166 // Make sure we still have an entry.
2167 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2168 ASSERT_TRUE(entry);
2169 EXPECT_EQ(kUrl, entry->GetURL().spec());
2171 // And that the first interstitial is gone, but not the second.
2172 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2173 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2174 RunAllPendingInMessageLoop();
2175 EXPECT_TRUE(deleted);
2176 EXPECT_FALSE(deleted2);
2179 // Tests that Javascript messages are not shown while an interstitial is
2180 // showing.
2181 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2182 const char kUrl[] = "http://www.badguys.com/";
2183 const GURL kGURL(kUrl);
2185 // Start a navigation to a page
2186 contents()->GetController().LoadURL(
2187 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2188 // DidNavigate from the page
2189 contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
2191 // Simulate showing an interstitial while the page is showing.
2192 TestInterstitialPage::InterstitialState state =
2193 TestInterstitialPage::INVALID;
2194 bool deleted = false;
2195 TestInterstitialPage* interstitial =
2196 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2197 TestInterstitialPageStateGuard state_guard(interstitial);
2198 interstitial->Show();
2199 interstitial->TestDidNavigate(1, kGURL);
2201 // While the interstitial is showing, let's simulate the hidden page
2202 // attempting to show a JS message.
2203 IPC::Message* dummy_message = new IPC::Message;
2204 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2205 base::ASCIIToUTF16("This is an informative message"),
2206 base::ASCIIToUTF16("OK"),
2207 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message);
2208 EXPECT_TRUE(contents()->last_dialog_suppressed_);
2211 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2212 // interstitial it isn't copied over to the destination.
2213 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2214 // Navigate to a page.
2215 GURL url1("http://www.google.com");
2216 test_rvh()->SendNavigate(1, url1);
2217 EXPECT_EQ(1, controller().GetEntryCount());
2219 // Initiate a browser navigation that will trigger the interstitial
2220 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2221 PAGE_TRANSITION_TYPED, std::string());
2223 // Show an interstitial.
2224 TestInterstitialPage::InterstitialState state =
2225 TestInterstitialPage::INVALID;
2226 bool deleted = false;
2227 GURL url2("http://interstitial");
2228 TestInterstitialPage* interstitial =
2229 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2230 TestInterstitialPageStateGuard state_guard(interstitial);
2231 interstitial->Show();
2232 interstitial->TestDidNavigate(1, url2);
2233 EXPECT_TRUE(interstitial->is_showing());
2234 EXPECT_EQ(2, controller().GetEntryCount());
2236 // Create another NavigationController.
2237 GURL url3("http://foo2");
2238 scoped_ptr<TestWebContents> other_contents(
2239 static_cast<TestWebContents*>(CreateTestWebContents()));
2240 NavigationControllerImpl& other_controller = other_contents->GetController();
2241 other_contents->NavigateAndCommit(url3);
2242 other_contents->ExpectSetHistoryLengthAndPrune(
2243 NavigationEntryImpl::FromNavigationEntry(
2244 other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2245 other_controller.GetEntryAtIndex(0)->GetPageID());
2246 other_controller.CopyStateFromAndPrune(&controller(), false);
2248 // The merged controller should only have two entries: url1 and url2.
2249 ASSERT_EQ(2, other_controller.GetEntryCount());
2250 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2251 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2252 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2254 // And the merged controller shouldn't be showing an interstitial.
2255 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2258 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2259 // showing an interstitial.
2260 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2261 // Navigate to a page.
2262 GURL url1("http://www.google.com");
2263 contents()->NavigateAndCommit(url1);
2265 // Create another NavigationController.
2266 scoped_ptr<TestWebContents> other_contents(
2267 static_cast<TestWebContents*>(CreateTestWebContents()));
2268 NavigationControllerImpl& other_controller = other_contents->GetController();
2270 // Navigate it to url2.
2271 GURL url2("http://foo2");
2272 other_contents->NavigateAndCommit(url2);
2274 // Show an interstitial.
2275 TestInterstitialPage::InterstitialState state =
2276 TestInterstitialPage::INVALID;
2277 bool deleted = false;
2278 GURL url3("http://interstitial");
2279 TestInterstitialPage* interstitial =
2280 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2281 &deleted);
2282 TestInterstitialPageStateGuard state_guard(interstitial);
2283 interstitial->Show();
2284 interstitial->TestDidNavigate(1, url3);
2285 EXPECT_TRUE(interstitial->is_showing());
2286 EXPECT_EQ(2, other_controller.GetEntryCount());
2288 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2289 // interstitial is showing in the target.
2290 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2293 // Regression test for http://crbug.com/168611 - the URLs passed by the
2294 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2295 TEST_F(WebContentsImplTest, FilterURLs) {
2296 TestWebContentsObserver observer(contents());
2298 // A navigation to about:whatever should always look like a navigation to
2299 // about:blank
2300 GURL url_normalized(kAboutBlankURL);
2301 GURL url_from_ipc("about:whatever");
2303 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2304 // will use the given URL to create the NavigationEntry as well, and that
2305 // entry should contain the filtered URL.
2306 contents()->NavigateAndCommit(url_normalized);
2308 // Check that an IPC with about:whatever is correctly normalized.
2309 contents()->TestDidFinishLoad(url_from_ipc);
2311 EXPECT_EQ(url_normalized, observer.last_url());
2313 // Create and navigate another WebContents.
2314 scoped_ptr<TestWebContents> other_contents(
2315 static_cast<TestWebContents*>(CreateTestWebContents()));
2316 TestWebContentsObserver other_observer(other_contents.get());
2317 other_contents->NavigateAndCommit(url_normalized);
2319 // Check that an IPC with about:whatever is correctly normalized.
2320 other_contents->TestDidFailLoadWithError(
2321 url_from_ipc, 1, base::string16());
2322 EXPECT_EQ(url_normalized, other_observer.last_url());
2325 // Test that if a pending contents is deleted before it is shown, we don't
2326 // crash.
2327 TEST_F(WebContentsImplTest, PendingContents) {
2328 scoped_ptr<TestWebContents> other_contents(
2329 static_cast<TestWebContents*>(CreateTestWebContents()));
2330 contents()->AddPendingContents(other_contents.get());
2331 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2332 other_contents.reset();
2333 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2336 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
2337 const gfx::Size original_preferred_size(1024, 768);
2338 contents()->UpdatePreferredSize(original_preferred_size);
2340 // With no capturers, expect the preferred size to be the one propagated into
2341 // WebContentsImpl via the RenderViewHostDelegate interface.
2342 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2343 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2345 // Increment capturer count, but without specifying a capture size. Expect
2346 // a "not set" preferred size.
2347 contents()->IncrementCapturerCount(gfx::Size());
2348 EXPECT_EQ(1, contents()->GetCapturerCount());
2349 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2351 // Increment capturer count again, but with an overriding capture size.
2352 // Expect preferred size to now be overridden to the capture size.
2353 const gfx::Size capture_size(1280, 720);
2354 contents()->IncrementCapturerCount(capture_size);
2355 EXPECT_EQ(2, contents()->GetCapturerCount());
2356 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2358 // Increment capturer count a third time, but the expect that the preferred
2359 // size is still the first capture size.
2360 const gfx::Size another_capture_size(720, 480);
2361 contents()->IncrementCapturerCount(another_capture_size);
2362 EXPECT_EQ(3, contents()->GetCapturerCount());
2363 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2365 // Decrement capturer count twice, but expect the preferred size to still be
2366 // overridden.
2367 contents()->DecrementCapturerCount();
2368 contents()->DecrementCapturerCount();
2369 EXPECT_EQ(1, contents()->GetCapturerCount());
2370 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2372 // Decrement capturer count, and since the count has dropped to zero, the
2373 // original preferred size should be restored.
2374 contents()->DecrementCapturerCount();
2375 EXPECT_EQ(0, contents()->GetCapturerCount());
2376 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2379 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2380 // on activity.
2381 TEST_F(WebContentsImplTest, GetLastActiveTime) {
2382 // The WebContents starts with a valid creation time.
2383 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2385 // Reset the last active time to a known-bad value.
2386 contents()->last_active_time_ = base::TimeTicks();
2387 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2389 // Simulate activating the WebContents. The active time should update.
2390 contents()->WasShown();
2391 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2394 class ContentsZoomChangedDelegate : public WebContentsDelegate {
2395 public:
2396 ContentsZoomChangedDelegate() :
2397 contents_zoom_changed_call_count_(0),
2398 last_zoom_in_(false) {
2401 int GetAndResetContentsZoomChangedCallCount() {
2402 int count = contents_zoom_changed_call_count_;
2403 contents_zoom_changed_call_count_ = 0;
2404 return count;
2407 bool last_zoom_in() const {
2408 return last_zoom_in_;
2411 // WebContentsDelegate:
2412 virtual void ContentsZoomChange(bool zoom_in) OVERRIDE {
2413 contents_zoom_changed_call_count_++;
2414 last_zoom_in_ = zoom_in;
2417 private:
2418 int contents_zoom_changed_call_count_;
2419 bool last_zoom_in_;
2421 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
2424 // Tests that some mouseehweel events get turned into browser zoom requests.
2425 TEST_F(WebContentsImplTest, HandleWheelEvent) {
2426 using blink::WebInputEvent;
2428 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2429 new ContentsZoomChangedDelegate());
2430 contents()->SetDelegate(delegate.get());
2432 int modifiers = 0;
2433 // Verify that normal mouse wheel events do nothing to change the zoom level.
2434 blink::WebMouseWheelEvent event =
2435 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2436 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2437 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2439 modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey;
2440 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2441 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2442 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2444 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2445 // Except on MacOS where we never want to adjust zoom with mousewheel.
2446 modifiers = WebInputEvent::ControlKey;
2447 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2448 bool handled = contents()->HandleWheelEvent(event);
2449 #if defined(OS_MACOSX)
2450 EXPECT_FALSE(handled);
2451 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2452 #else
2453 EXPECT_TRUE(handled);
2454 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2455 EXPECT_TRUE(delegate->last_zoom_in());
2456 #endif
2458 modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
2459 WebInputEvent::AltKey;
2460 event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false);
2461 handled = contents()->HandleWheelEvent(event);
2462 #if defined(OS_MACOSX)
2463 EXPECT_FALSE(handled);
2464 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2465 #else
2466 EXPECT_TRUE(handled);
2467 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2468 EXPECT_FALSE(delegate->last_zoom_in());
2469 #endif
2471 // Unless there is no vertical movement.
2472 event = SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers, false);
2473 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2474 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2476 // Events containing precise scrolling deltas also shouldn't result in the
2477 // zoom being adjusted, to avoid accidental adjustments caused by
2478 // two-finger-scrolling on a touchpad.
2479 modifiers = WebInputEvent::ControlKey;
2480 event = SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers, true);
2481 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2482 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2484 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2485 contents()->SetDelegate(NULL);
2488 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2489 TEST_F(WebContentsImplTest, HandleGestureEvent) {
2490 using blink::WebGestureEvent;
2491 using blink::WebInputEvent;
2493 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2494 new ContentsZoomChangedDelegate());
2495 contents()->SetDelegate(delegate.get());
2497 const float kZoomStepValue = 0.6f;
2498 blink::WebGestureEvent event = SyntheticWebGestureEventBuilder::Build(
2499 WebInputEvent::GesturePinchUpdate, WebGestureEvent::Touchpad);
2501 // A pinch less than the step value doesn't change the zoom level.
2502 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 0.8f;
2503 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2504 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2506 // But repeating the event so the combined scale is greater does.
2507 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2508 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2509 EXPECT_TRUE(delegate->last_zoom_in());
2511 // Pinching back out one step goes back to 100%.
2512 event.data.pinchUpdate.scale = 1.0f - kZoomStepValue;
2513 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2514 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2515 EXPECT_FALSE(delegate->last_zoom_in());
2517 // Pinching out again doesn't zoom (step is twice as large around 100%).
2518 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2519 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2521 // And again now it zooms once per step.
2522 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2523 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2524 EXPECT_FALSE(delegate->last_zoom_in());
2526 // No other type of gesture event is handled by WebContentsImpl (for example
2527 // a touchscreen pinch gesture).
2528 event = SyntheticWebGestureEventBuilder::Build(
2529 WebInputEvent::GesturePinchUpdate, WebGestureEvent::Touchscreen);
2530 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 3;
2531 EXPECT_FALSE(contents()->HandleGestureEvent(event));
2532 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2534 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2535 contents()->SetDelegate(NULL);
2538 } // namespace content