Add a FrameHostMsg_BeginNavigation IPC
[chromium-blink-merge.git] / content / browser / web_contents / web_contents_impl_unittest.cc
blobfdee01a2bd85176d12cb1f7a8af91ee9f0fcb23f
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(RenderFrameHost* render_frame_host,
276 const GURL& validated_url) OVERRIDE {
277 last_url_ = validated_url;
279 virtual void DidFailLoad(RenderFrameHost* render_frame_host,
280 const GURL& validated_url,
281 int error_code,
282 const base::string16& error_description) OVERRIDE {
283 last_url_ = validated_url;
286 const GURL& last_url() const { return last_url_; }
288 private:
289 GURL last_url_;
291 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
294 // Pretends to be a normal browser that receives toggles and transitions to/from
295 // a fullscreened state.
296 class FakeFullscreenDelegate : public WebContentsDelegate {
297 public:
298 FakeFullscreenDelegate() : fullscreened_contents_(NULL) {}
299 virtual ~FakeFullscreenDelegate() {}
301 virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
302 bool enter_fullscreen) OVERRIDE {
303 fullscreened_contents_ = enter_fullscreen ? web_contents : NULL;
306 virtual bool IsFullscreenForTabOrPending(const WebContents* web_contents)
307 const OVERRIDE {
308 return fullscreened_contents_ && web_contents == fullscreened_contents_;
311 private:
312 WebContents* fullscreened_contents_;
314 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate);
317 class FakeValidationMessageDelegate : public WebContentsDelegate {
318 public:
319 FakeValidationMessageDelegate()
320 : hide_validation_message_was_called_(false) {}
321 virtual ~FakeValidationMessageDelegate() {}
323 virtual void HideValidationMessage(WebContents* web_contents) OVERRIDE {
324 hide_validation_message_was_called_ = true;
327 bool hide_validation_message_was_called() const {
328 return hide_validation_message_was_called_;
331 private:
332 bool hide_validation_message_was_called_;
334 DISALLOW_COPY_AND_ASSIGN(FakeValidationMessageDelegate);
337 } // namespace
339 // Test to make sure that title updates get stripped of whitespace.
340 TEST_F(WebContentsImplTest, UpdateTitle) {
341 NavigationControllerImpl& cont =
342 static_cast<NavigationControllerImpl&>(controller());
343 FrameHostMsg_DidCommitProvisionalLoad_Params params;
344 InitNavigateParams(
345 &params, 0, GURL(url::kAboutBlankURL), PAGE_TRANSITION_TYPED);
347 LoadCommittedDetails details;
348 cont.RendererDidNavigate(main_test_rfh(), params, &details);
350 contents()->UpdateTitle(main_test_rfh(), 0,
351 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
352 base::i18n::LEFT_TO_RIGHT);
353 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
356 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
357 const GURL kGURL("chrome://blah");
358 controller().LoadURL(
359 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
360 EXPECT_EQ(base::string16(), contents()->GetTitle());
363 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
364 const GURL kGURL("chrome://blah");
365 const base::string16 title = base::ASCIIToUTF16("My Title");
366 controller().LoadURL(
367 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
369 NavigationEntry* entry = controller().GetVisibleEntry();
370 ASSERT_EQ(kGURL, entry->GetURL());
371 entry->SetTitle(title);
373 EXPECT_EQ(title, contents()->GetTitle());
376 // Test view source mode for a webui page.
377 TEST_F(WebContentsImplTest, NTPViewSource) {
378 NavigationControllerImpl& cont =
379 static_cast<NavigationControllerImpl&>(controller());
380 const char kUrl[] = "view-source:chrome://blah";
381 const GURL kGURL(kUrl);
383 process()->sink().ClearMessages();
385 cont.LoadURL(
386 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
387 rvh()->GetDelegate()->RenderViewCreated(rvh());
388 // Did we get the expected message?
389 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
390 ViewMsg_EnableViewSourceMode::ID));
392 FrameHostMsg_DidCommitProvisionalLoad_Params params;
393 InitNavigateParams(&params, 0, kGURL, PAGE_TRANSITION_TYPED);
394 LoadCommittedDetails details;
395 cont.RendererDidNavigate(main_test_rfh(), params, &details);
396 // Also check title and url.
397 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
400 // Test to ensure UpdateMaxPageID is working properly.
401 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
402 SiteInstance* instance1 = contents()->GetSiteInstance();
403 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
405 // Starts at -1.
406 EXPECT_EQ(-1, contents()->GetMaxPageID());
407 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
408 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
410 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
411 contents()->UpdateMaxPageID(3);
412 contents()->UpdateMaxPageID(1);
413 EXPECT_EQ(3, contents()->GetMaxPageID());
414 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
415 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
417 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
418 EXPECT_EQ(3, contents()->GetMaxPageID());
419 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
420 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
423 // Test simple same-SiteInstance navigation.
424 TEST_F(WebContentsImplTest, SimpleNavigation) {
425 TestRenderViewHost* orig_rvh = test_rvh();
426 SiteInstance* instance1 = contents()->GetSiteInstance();
427 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
429 // Navigate to URL
430 const GURL url("http://www.google.com");
431 controller().LoadURL(
432 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
433 EXPECT_FALSE(contents()->cross_navigation_pending());
434 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
435 // Controller's pending entry will have a NULL site instance until we assign
436 // it in DidNavigate.
437 EXPECT_TRUE(
438 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
439 site_instance() == NULL);
441 // DidNavigate from the page
442 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
443 EXPECT_FALSE(contents()->cross_navigation_pending());
444 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
445 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
446 // Controller's entry should now have the SiteInstance, or else we won't be
447 // able to find it later.
448 EXPECT_EQ(
449 instance1,
450 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
451 site_instance());
454 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
455 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
456 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
457 const GURL url(std::string("http://example.org/").append(
458 GetMaxURLChars() + 1, 'a'));
460 controller().LoadURL(
461 url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
462 EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
465 // Test that navigating across a site boundary creates a new RenderViewHost
466 // with a new SiteInstance. Going back should do the same.
467 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
468 TestRenderViewHost* orig_rvh = test_rvh();
469 RenderFrameHostImpl* orig_rfh =
470 contents()->GetFrameTree()->root()->current_frame_host();
471 int orig_rvh_delete_count = 0;
472 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
473 SiteInstance* instance1 = contents()->GetSiteInstance();
475 // Navigate to URL. First URL should use first RenderViewHost.
476 const GURL url("http://www.google.com");
477 controller().LoadURL(
478 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
479 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
481 // Keep the number of active views in orig_rvh's SiteInstance
482 // non-zero so that orig_rvh doesn't get deleted when it gets
483 // swapped out.
484 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
485 increment_active_view_count();
487 EXPECT_FALSE(contents()->cross_navigation_pending());
488 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
489 EXPECT_EQ(url, contents()->GetLastCommittedURL());
490 EXPECT_EQ(url, contents()->GetVisibleURL());
492 // Navigate to new site
493 const GURL url2("http://www.yahoo.com");
494 controller().LoadURL(
495 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
496 EXPECT_TRUE(contents()->cross_navigation_pending());
497 EXPECT_EQ(url, contents()->GetLastCommittedURL());
498 EXPECT_EQ(url2, contents()->GetVisibleURL());
499 TestRenderViewHost* pending_rvh =
500 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
501 int pending_rvh_delete_count = 0;
502 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
503 RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()->
504 render_manager()->pending_frame_host();
506 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
507 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
508 orig_rvh->SendBeforeUnloadACK(true);
509 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
511 // DidNavigate from the pending page
512 contents()->TestDidNavigate(
513 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
514 SiteInstance* instance2 = contents()->GetSiteInstance();
516 // Keep the number of active views in pending_rvh's SiteInstance
517 // non-zero so that orig_rvh doesn't get deleted when it gets
518 // swapped out.
519 static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
520 increment_active_view_count();
522 EXPECT_FALSE(contents()->cross_navigation_pending());
523 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
524 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
525 EXPECT_EQ(url2, contents()->GetVisibleURL());
526 EXPECT_NE(instance1, instance2);
527 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
528 // We keep the original RFH around, swapped out.
529 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
530 orig_rfh));
531 EXPECT_EQ(orig_rvh_delete_count, 0);
533 // Going back should switch SiteInstances again. The first SiteInstance is
534 // stored in the NavigationEntry, so it should be the same as at the start.
535 // We should use the same RVH as before, swapping it back in.
536 controller().GoBack();
537 TestRenderViewHost* goback_rvh =
538 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
539 EXPECT_EQ(orig_rvh, goback_rvh);
540 EXPECT_TRUE(contents()->cross_navigation_pending());
542 // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
543 EXPECT_TRUE(goback_rvh->are_navigations_suspended());
544 pending_rvh->SendBeforeUnloadACK(true);
545 EXPECT_FALSE(goback_rvh->are_navigations_suspended());
547 // DidNavigate from the back action
548 contents()->TestDidNavigate(
549 goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
550 EXPECT_FALSE(contents()->cross_navigation_pending());
551 EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
552 EXPECT_EQ(instance1, contents()->GetSiteInstance());
553 // The pending RFH should now be swapped out, not deleted.
554 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
555 IsOnSwappedOutList(pending_rfh));
556 EXPECT_EQ(pending_rvh_delete_count, 0);
557 pending_rvh->OnSwappedOut(false);
559 // Close contents and ensure RVHs are deleted.
560 DeleteContents();
561 EXPECT_EQ(orig_rvh_delete_count, 1);
562 EXPECT_EQ(pending_rvh_delete_count, 1);
565 // Test that navigating across a site boundary after a crash creates a new
566 // RVH without requiring a cross-site transition (i.e., PENDING state).
567 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
568 TestRenderViewHost* orig_rvh = test_rvh();
569 int orig_rvh_delete_count = 0;
570 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
571 SiteInstance* instance1 = contents()->GetSiteInstance();
573 // Navigate to URL. First URL should use first RenderViewHost.
574 const GURL url("http://www.google.com");
575 controller().LoadURL(
576 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
577 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
579 EXPECT_FALSE(contents()->cross_navigation_pending());
580 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
582 // Crash the renderer.
583 orig_rvh->set_render_view_created(false);
585 // Navigate to new site. We should not go into PENDING.
586 const GURL url2("http://www.yahoo.com");
587 controller().LoadURL(
588 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
589 RenderViewHost* new_rvh = rvh();
590 EXPECT_FALSE(contents()->cross_navigation_pending());
591 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
592 EXPECT_NE(orig_rvh, new_rvh);
593 EXPECT_EQ(orig_rvh_delete_count, 1);
595 // DidNavigate from the new page
596 contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
597 SiteInstance* instance2 = contents()->GetSiteInstance();
599 EXPECT_FALSE(contents()->cross_navigation_pending());
600 EXPECT_EQ(new_rvh, rvh());
601 EXPECT_NE(instance1, instance2);
602 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
604 // Close contents and ensure RVHs are deleted.
605 DeleteContents();
606 EXPECT_EQ(orig_rvh_delete_count, 1);
609 // Test that opening a new contents in the same SiteInstance and then navigating
610 // both contentses to a new site will place both contentses in a single
611 // SiteInstance.
612 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
613 TestRenderViewHost* orig_rvh = test_rvh();
614 SiteInstance* instance1 = contents()->GetSiteInstance();
616 // Navigate to URL. First URL should use first RenderViewHost.
617 const GURL url("http://www.google.com");
618 controller().LoadURL(
619 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
620 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
622 // Open a new contents with the same SiteInstance, navigated to the same site.
623 scoped_ptr<TestWebContents> contents2(
624 TestWebContents::Create(browser_context(), instance1));
625 contents2->GetController().LoadURL(url, Referrer(),
626 PAGE_TRANSITION_TYPED,
627 std::string());
628 // Need this page id to be 2 since the site instance is the same (which is the
629 // scope of page IDs) and we want to consider this a new page.
630 contents2->TestDidNavigate(
631 contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
633 // Navigate first contents to a new site.
634 const GURL url2a("http://www.yahoo.com");
635 controller().LoadURL(
636 url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
637 orig_rvh->SendBeforeUnloadACK(true);
638 TestRenderViewHost* pending_rvh_a =
639 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
640 contents()->TestDidNavigate(
641 pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
642 SiteInstance* instance2a = contents()->GetSiteInstance();
643 EXPECT_NE(instance1, instance2a);
645 // Navigate second contents to the same site as the first tab.
646 const GURL url2b("http://mail.yahoo.com");
647 contents2->GetController().LoadURL(url2b, Referrer(),
648 PAGE_TRANSITION_TYPED,
649 std::string());
650 TestRenderViewHost* rvh2 =
651 static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
652 rvh2->SendBeforeUnloadACK(true);
653 TestRenderViewHost* pending_rvh_b =
654 static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
655 EXPECT_TRUE(pending_rvh_b != NULL);
656 EXPECT_TRUE(contents2->cross_navigation_pending());
658 // NOTE(creis): We used to be in danger of showing a crash page here if the
659 // second contents hadn't navigated somewhere first (bug 1145430). That case
660 // is now covered by the CrossSiteBoundariesAfterCrash test.
661 contents2->TestDidNavigate(
662 pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
663 SiteInstance* instance2b = contents2->GetSiteInstance();
664 EXPECT_NE(instance1, instance2b);
666 // Both contentses should now be in the same SiteInstance.
667 EXPECT_EQ(instance2a, instance2b);
670 // The embedder can request sites for certain urls not be be assigned to the
671 // SiteInstance through ShouldAssignSiteForURL() in content browser client,
672 // allowing to reuse the renderer backing certain chrome urls for subsequent
673 // navigation. The test verifies that the override is honored.
674 TEST_F(WebContentsImplTest, NavigateFromSitelessUrl) {
675 WebContentsImplTestBrowserClient browser_client;
676 SetBrowserClientForTesting(&browser_client);
678 TestRenderViewHost* orig_rvh = test_rvh();
679 RenderFrameHostImpl* orig_rfh =
680 contents()->GetFrameTree()->root()->current_frame_host();
681 int orig_rvh_delete_count = 0;
682 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
683 SiteInstanceImpl* orig_instance =
684 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
686 browser_client.set_assign_site_for_url(false);
687 // Navigate to an URL that will not assign a new SiteInstance.
688 const GURL native_url("non-site-url://stuffandthings");
689 controller().LoadURL(
690 native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
691 contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
693 EXPECT_FALSE(contents()->cross_navigation_pending());
694 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
695 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
696 EXPECT_EQ(native_url, contents()->GetVisibleURL());
697 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
698 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
699 EXPECT_FALSE(orig_instance->HasSite());
701 browser_client.set_assign_site_for_url(true);
702 // Navigate to new site (should keep same site instance).
703 const GURL url("http://www.google.com");
704 controller().LoadURL(
705 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
706 EXPECT_FALSE(contents()->cross_navigation_pending());
707 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
708 EXPECT_EQ(url, contents()->GetVisibleURL());
709 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
710 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
712 // Keep the number of active views in orig_rvh's SiteInstance
713 // non-zero so that orig_rvh doesn't get deleted when it gets
714 // swapped out.
715 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
716 increment_active_view_count();
718 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
719 EXPECT_TRUE(
720 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
721 EXPECT_EQ(url, contents()->GetLastCommittedURL());
723 // Navigate to another new site (should create a new site instance).
724 const GURL url2("http://www.yahoo.com");
725 controller().LoadURL(
726 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
727 EXPECT_TRUE(contents()->cross_navigation_pending());
728 EXPECT_EQ(url, contents()->GetLastCommittedURL());
729 EXPECT_EQ(url2, contents()->GetVisibleURL());
730 TestRenderViewHost* pending_rvh =
731 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
732 int pending_rvh_delete_count = 0;
733 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
735 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
736 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
737 orig_rvh->SendBeforeUnloadACK(true);
738 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
740 // DidNavigate from the pending page.
741 contents()->TestDidNavigate(
742 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
743 SiteInstance* new_instance = contents()->GetSiteInstance();
745 EXPECT_FALSE(contents()->cross_navigation_pending());
746 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
747 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
748 EXPECT_EQ(url2, contents()->GetVisibleURL());
749 EXPECT_NE(new_instance, orig_instance);
750 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
751 // We keep the original RFH around, swapped out.
752 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
753 orig_rfh));
754 EXPECT_EQ(orig_rvh_delete_count, 0);
755 orig_rvh->OnSwappedOut(false);
757 // Close contents and ensure RVHs are deleted.
758 DeleteContents();
759 EXPECT_EQ(orig_rvh_delete_count, 1);
760 EXPECT_EQ(pending_rvh_delete_count, 1);
763 // Regression test for http://crbug.com/386542 - variation of
764 // NavigateFromSitelessUrl in which the original navigation is a session
765 // restore.
766 TEST_F(WebContentsImplTest, NavigateFromRestoredSitelessUrl) {
767 WebContentsImplTestBrowserClient browser_client;
768 SetBrowserClientForTesting(&browser_client);
769 SiteInstanceImpl* orig_instance =
770 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
771 TestRenderViewHost* orig_rvh = test_rvh();
773 // Restore a navigation entry for URL that should not assign site to the
774 // SiteInstance.
775 browser_client.set_assign_site_for_url(false);
776 const GURL native_url("non-site-url://stuffandthings");
777 std::vector<NavigationEntry*> entries;
778 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
779 native_url, Referrer(), PAGE_TRANSITION_LINK, false, std::string(),
780 browser_context());
781 entry->SetPageID(0);
782 entries.push_back(entry);
783 controller().Restore(
785 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
786 &entries);
787 ASSERT_EQ(0u, entries.size());
788 ASSERT_EQ(1, controller().GetEntryCount());
789 controller().GoToIndex(0);
790 contents()->TestDidNavigate(orig_rvh, 0, native_url, PAGE_TRANSITION_RELOAD);
791 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
792 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
793 EXPECT_FALSE(orig_instance->HasSite());
795 // Navigate to a regular site and verify that the SiteInstance was kept.
796 browser_client.set_assign_site_for_url(true);
797 const GURL url("http://www.google.com");
798 controller().LoadURL(
799 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
800 contents()->TestDidNavigate(orig_rvh, 2, url, PAGE_TRANSITION_TYPED);
801 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
803 // Cleanup.
804 DeleteContents();
807 // Complement for NavigateFromRestoredSitelessUrl, verifying that when a regular
808 // tab is restored, the SiteInstance will change upon navigation.
809 TEST_F(WebContentsImplTest, NavigateFromRestoredRegularUrl) {
810 WebContentsImplTestBrowserClient browser_client;
811 SetBrowserClientForTesting(&browser_client);
812 SiteInstanceImpl* orig_instance =
813 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
814 TestRenderViewHost* orig_rvh = test_rvh();
816 // Restore a navigation entry for a regular URL ensuring that the embedder
817 // ShouldAssignSiteForUrl override is disabled (i.e. returns true).
818 browser_client.set_assign_site_for_url(true);
819 const GURL regular_url("http://www.yahoo.com");
820 std::vector<NavigationEntry*> entries;
821 NavigationEntry* entry = NavigationControllerImpl::CreateNavigationEntry(
822 regular_url, Referrer(), PAGE_TRANSITION_LINK, false, std::string(),
823 browser_context());
824 entry->SetPageID(0);
825 entries.push_back(entry);
826 controller().Restore(
828 NavigationController::RESTORE_LAST_SESSION_EXITED_CLEANLY,
829 &entries);
830 ASSERT_EQ(0u, entries.size());
831 ASSERT_EQ(1, controller().GetEntryCount());
832 controller().GoToIndex(0);
833 contents()->TestDidNavigate(orig_rvh, 0, regular_url, PAGE_TRANSITION_RELOAD);
834 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
835 EXPECT_TRUE(orig_instance->HasSite());
837 // Navigate to another site and verify that a new SiteInstance was created.
838 const GURL url("http://www.google.com");
839 controller().LoadURL(
840 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
841 contents()->TestDidNavigate(
842 contents()->GetPendingRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
843 EXPECT_NE(orig_instance, contents()->GetSiteInstance());
845 // Cleanup.
846 DeleteContents();
849 // Test that we can find an opener RVH even if it's pending.
850 // http://crbug.com/176252.
851 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
852 TestRenderViewHost* orig_rvh = test_rvh();
854 // Navigate to a URL.
855 const GURL url("http://www.google.com");
856 controller().LoadURL(
857 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
858 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
860 // Start to navigate first tab to a new site, so that it has a pending RVH.
861 const GURL url2("http://www.yahoo.com");
862 controller().LoadURL(
863 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
864 orig_rvh->SendBeforeUnloadACK(true);
865 TestRenderViewHost* pending_rvh =
866 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
868 // While it is still pending, simulate opening a new tab with the first tab
869 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
870 // on the opener to ensure that an RVH exists.
871 int opener_routing_id = contents()->CreateOpenerRenderViews(
872 pending_rvh->GetSiteInstance());
874 // We should find the pending RVH and not create a new one.
875 EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
878 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
879 // to determine whether a navigation is cross-site.
880 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
881 RenderViewHost* orig_rvh = rvh();
882 SiteInstance* instance1 = contents()->GetSiteInstance();
884 // Navigate to URL.
885 const GURL url("http://www.google.com");
886 controller().LoadURL(
887 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
888 contents()->TestDidNavigate(
889 orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
891 // Open a related contents to a second site.
892 scoped_ptr<TestWebContents> contents2(
893 TestWebContents::Create(browser_context(), instance1));
894 const GURL url2("http://www.yahoo.com");
895 contents2->GetController().LoadURL(url2, Referrer(),
896 PAGE_TRANSITION_TYPED,
897 std::string());
898 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
899 // pending.
900 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
901 contents2->GetRenderViewHost());
902 EXPECT_FALSE(contents2->cross_navigation_pending());
903 contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
904 SiteInstance* instance2 = contents2->GetSiteInstance();
905 EXPECT_NE(instance1, instance2);
906 EXPECT_FALSE(contents2->cross_navigation_pending());
908 // Simulate a link click in first contents to second site. Doesn't switch
909 // SiteInstances, because we don't intercept WebKit navigations.
910 contents()->TestDidNavigate(
911 orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
912 SiteInstance* instance3 = contents()->GetSiteInstance();
913 EXPECT_EQ(instance1, instance3);
914 EXPECT_FALSE(contents()->cross_navigation_pending());
916 // Navigate to the new site. Doesn't switch SiteInstancees, because we
917 // compare against the current URL, not the SiteInstance's site.
918 const GURL url3("http://mail.yahoo.com");
919 controller().LoadURL(
920 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
921 EXPECT_FALSE(contents()->cross_navigation_pending());
922 contents()->TestDidNavigate(
923 orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
924 SiteInstance* instance4 = contents()->GetSiteInstance();
925 EXPECT_EQ(instance1, instance4);
928 // Test that the onbeforeunload and onunload handlers run when navigating
929 // across site boundaries.
930 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
931 TestRenderViewHost* orig_rvh = test_rvh();
932 SiteInstance* instance1 = contents()->GetSiteInstance();
934 // Navigate to URL. First URL should use first RenderViewHost.
935 const GURL url("http://www.google.com");
936 controller().LoadURL(
937 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
938 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
939 EXPECT_FALSE(contents()->cross_navigation_pending());
940 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
942 // Navigate to new site, but simulate an onbeforeunload denial.
943 const GURL url2("http://www.yahoo.com");
944 controller().LoadURL(
945 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
946 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
947 base::TimeTicks now = base::TimeTicks::Now();
948 orig_rvh->GetMainFrame()->OnMessageReceived(
949 FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
950 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
951 EXPECT_FALSE(contents()->cross_navigation_pending());
952 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
954 // Navigate again, but simulate an onbeforeunload approval.
955 controller().LoadURL(
956 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
957 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
958 now = base::TimeTicks::Now();
959 orig_rvh->GetMainFrame()->OnMessageReceived(
960 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
961 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
962 EXPECT_TRUE(contents()->cross_navigation_pending());
963 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
964 contents()->GetPendingRenderViewHost());
966 // We won't hear DidNavigate until the onunload handler has finished running.
968 // DidNavigate from the pending page.
969 contents()->TestDidNavigate(
970 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
971 SiteInstance* instance2 = contents()->GetSiteInstance();
972 EXPECT_FALSE(contents()->cross_navigation_pending());
973 EXPECT_EQ(pending_rvh, rvh());
974 EXPECT_NE(instance1, instance2);
975 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
978 // Test that during a slow cross-site navigation, the original renderer can
979 // navigate to a different URL and have it displayed, canceling the slow
980 // navigation.
981 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
982 TestRenderViewHost* orig_rvh = test_rvh();
983 SiteInstance* instance1 = contents()->GetSiteInstance();
985 // Navigate to URL. First URL should use first RenderViewHost.
986 const GURL url("http://www.google.com");
987 controller().LoadURL(
988 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
989 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
990 EXPECT_FALSE(contents()->cross_navigation_pending());
991 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
993 // Navigate to new site, simulating an onbeforeunload approval.
994 const GURL url2("http://www.yahoo.com");
995 controller().LoadURL(
996 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
997 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
998 base::TimeTicks now = base::TimeTicks::Now();
999 orig_rvh->GetMainFrame()->OnMessageReceived(
1000 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1001 EXPECT_TRUE(contents()->cross_navigation_pending());
1003 // Suppose the original renderer navigates before the new one is ready.
1004 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1006 // Verify that the pending navigation is cancelled.
1007 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1008 SiteInstance* instance2 = contents()->GetSiteInstance();
1009 EXPECT_FALSE(contents()->cross_navigation_pending());
1010 EXPECT_EQ(orig_rvh, rvh());
1011 EXPECT_EQ(instance1, instance2);
1012 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1015 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
1016 // Start with a web ui page, which gets a new RVH with WebUI bindings.
1017 const GURL url1("chrome://blah");
1018 controller().LoadURL(
1019 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1020 TestRenderViewHost* ntp_rvh = test_rvh();
1021 contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
1022 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
1023 SiteInstance* instance1 = contents()->GetSiteInstance();
1025 EXPECT_FALSE(contents()->cross_navigation_pending());
1026 EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
1027 EXPECT_EQ(url1, entry1->GetURL());
1028 EXPECT_EQ(instance1,
1029 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1030 EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
1032 // Navigate to new site.
1033 const GURL url2("http://www.google.com");
1034 controller().LoadURL(
1035 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1036 EXPECT_TRUE(contents()->cross_navigation_pending());
1037 TestRenderViewHost* google_rvh =
1038 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1040 // Simulate beforeunload approval.
1041 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
1042 base::TimeTicks now = base::TimeTicks::Now();
1043 ntp_rvh->GetMainFrame()->OnMessageReceived(
1044 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1046 // DidNavigate from the pending page.
1047 contents()->TestDidNavigate(
1048 google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1049 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
1050 SiteInstance* instance2 = contents()->GetSiteInstance();
1052 EXPECT_FALSE(contents()->cross_navigation_pending());
1053 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
1054 EXPECT_NE(instance1, instance2);
1055 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
1056 EXPECT_EQ(url2, entry2->GetURL());
1057 EXPECT_EQ(instance2,
1058 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1059 EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
1061 // Navigate to third page on same site.
1062 const GURL url3("http://news.google.com");
1063 controller().LoadURL(
1064 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1065 EXPECT_FALSE(contents()->cross_navigation_pending());
1066 contents()->TestDidNavigate(
1067 google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
1068 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
1069 SiteInstance* instance3 = contents()->GetSiteInstance();
1071 EXPECT_FALSE(contents()->cross_navigation_pending());
1072 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
1073 EXPECT_EQ(instance2, instance3);
1074 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
1075 EXPECT_EQ(url3, entry3->GetURL());
1076 EXPECT_EQ(instance3,
1077 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1079 // Go back within the site.
1080 controller().GoBack();
1081 EXPECT_FALSE(contents()->cross_navigation_pending());
1082 EXPECT_EQ(entry2, controller().GetPendingEntry());
1084 // Before that commits, go back again.
1085 controller().GoBack();
1086 EXPECT_TRUE(contents()->cross_navigation_pending());
1087 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
1088 EXPECT_EQ(entry1, controller().GetPendingEntry());
1090 // Simulate beforeunload approval.
1091 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
1092 now = base::TimeTicks::Now();
1093 google_rvh->GetMainFrame()->OnMessageReceived(
1094 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1096 // DidNavigate from the first back. This aborts the second back's pending RVH.
1097 contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1099 // We should commit this page and forget about the second back.
1100 EXPECT_FALSE(contents()->cross_navigation_pending());
1101 EXPECT_FALSE(controller().GetPendingEntry());
1102 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
1103 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
1105 // We should not have corrupted the NTP entry.
1106 EXPECT_EQ(instance3,
1107 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1108 EXPECT_EQ(instance2,
1109 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1110 EXPECT_EQ(instance1,
1111 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1112 EXPECT_EQ(url1, entry1->GetURL());
1115 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1116 // original renderer will not cancel the slow navigation (bug 42029).
1117 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
1118 TestRenderViewHost* orig_rvh = test_rvh();
1120 // Navigate to URL. First URL should use first RenderViewHost.
1121 const GURL url("http://www.google.com");
1122 controller().LoadURL(
1123 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1124 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1125 EXPECT_FALSE(contents()->cross_navigation_pending());
1126 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1128 // Start navigating to new site.
1129 const GURL url2("http://www.yahoo.com");
1130 controller().LoadURL(
1131 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1133 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1134 // waiting for a before unload response.
1135 TestRenderFrameHost* child_rfh = static_cast<TestRenderFrameHost*>(
1136 orig_rvh->main_render_frame_host()->AppendChild("subframe"));
1137 child_rfh->SendNavigateWithTransition(
1138 1, GURL("http://google.com/frame"), PAGE_TRANSITION_AUTO_SUBFRAME);
1139 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1141 // Now simulate the onbeforeunload approval and verify the navigation is
1142 // not canceled.
1143 base::TimeTicks now = base::TimeTicks::Now();
1144 orig_rvh->GetMainFrame()->OnMessageReceived(
1145 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1146 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1147 EXPECT_TRUE(contents()->cross_navigation_pending());
1150 // Test that a cross-site navigation is not preempted if the previous
1151 // renderer sends a FrameNavigate message just before being told to stop.
1152 // We should only preempt the cross-site navigation if the previous renderer
1153 // has started a new navigation. See http://crbug.com/79176.
1154 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1155 // Navigate to NTP URL.
1156 const GURL url("chrome://blah");
1157 controller().LoadURL(
1158 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1159 TestRenderViewHost* orig_rvh = test_rvh();
1160 EXPECT_FALSE(contents()->cross_navigation_pending());
1162 // Navigate to new site, with the beforeunload request in flight.
1163 const GURL url2("http://www.yahoo.com");
1164 controller().LoadURL(
1165 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1166 TestRenderViewHost* pending_rvh =
1167 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1168 EXPECT_TRUE(contents()->cross_navigation_pending());
1169 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1171 // Suppose the first navigation tries to commit now, with a
1172 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1173 // but it should act as if the beforeunload ack arrived.
1174 orig_rvh->SendNavigate(1, GURL("chrome://blah"));
1175 EXPECT_TRUE(contents()->cross_navigation_pending());
1176 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1177 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1179 // The pending navigation should be able to commit successfully.
1180 contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1181 EXPECT_FALSE(contents()->cross_navigation_pending());
1182 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
1185 // Test that the original renderer cannot preempt a cross-site navigation once
1186 // the unload request has been made. At this point, the cross-site navigation
1187 // is almost ready to be displayed, and the original renderer is only given a
1188 // short chance to run an unload handler. Prevents regression of bug 23942.
1189 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
1190 TestRenderViewHost* orig_rvh = test_rvh();
1191 SiteInstance* instance1 = contents()->GetSiteInstance();
1193 // Navigate to URL. First URL should use first RenderViewHost.
1194 const GURL url("http://www.google.com");
1195 controller().LoadURL(
1196 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1197 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1198 EXPECT_FALSE(contents()->cross_navigation_pending());
1199 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1201 // Navigate to new site, simulating an onbeforeunload approval.
1202 const GURL url2("http://www.yahoo.com");
1203 controller().LoadURL(
1204 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1205 base::TimeTicks now = base::TimeTicks::Now();
1206 orig_rvh->GetMainFrame()->OnMessageReceived(
1207 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1208 EXPECT_TRUE(contents()->cross_navigation_pending());
1209 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
1210 contents()->GetPendingRenderViewHost());
1212 // Simulate the pending renderer's response, which leads to an unload request
1213 // being sent to orig_rvh.
1214 std::vector<GURL> url_chain;
1215 url_chain.push_back(GURL());
1216 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1217 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1218 GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
1219 url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
1221 // Suppose the original renderer navigates now, while the unload request is in
1222 // flight. We should ignore it, wait for the unload ack, and let the pending
1223 // request continue. Otherwise, the contents may close spontaneously or stop
1224 // responding to navigation requests. (See bug 23942.)
1225 FrameHostMsg_DidCommitProvisionalLoad_Params params1a;
1226 InitNavigateParams(&params1a, 2, GURL("http://www.google.com/foo"),
1227 PAGE_TRANSITION_TYPED);
1228 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1230 // Verify that the pending navigation is still in progress.
1231 EXPECT_TRUE(contents()->cross_navigation_pending());
1232 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
1234 // DidNavigate from the pending page should commit it.
1235 contents()->TestDidNavigate(
1236 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1237 SiteInstance* instance2 = contents()->GetSiteInstance();
1238 EXPECT_FALSE(contents()->cross_navigation_pending());
1239 EXPECT_EQ(pending_rvh, rvh());
1240 EXPECT_NE(instance1, instance2);
1241 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1244 // Test that a cross-site navigation that doesn't commit after the unload
1245 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1246 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1247 TestRenderViewHost* orig_rvh = test_rvh();
1248 SiteInstance* instance1 = contents()->GetSiteInstance();
1250 // Navigate to URL. First URL should use first RenderViewHost.
1251 const GURL url("http://www.google.com");
1252 controller().LoadURL(
1253 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1254 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1255 EXPECT_FALSE(contents()->cross_navigation_pending());
1256 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1258 // Navigate to new site, simulating an onbeforeunload approval.
1259 const GURL url2("http://www.yahoo.com");
1260 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1261 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1262 base::TimeTicks now = base::TimeTicks::Now();
1263 orig_rvh->GetMainFrame()->OnMessageReceived(
1264 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1265 EXPECT_TRUE(contents()->cross_navigation_pending());
1267 // Simulate swap out message when the response arrives.
1268 orig_rvh->OnSwappedOut(false);
1270 // Suppose the navigation doesn't get a chance to commit, and the user
1271 // navigates in the current RVH's SiteInstance.
1272 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1274 // Verify that the pending navigation is cancelled and the renderer is no
1275 // longer swapped out.
1276 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1277 SiteInstance* instance2 = contents()->GetSiteInstance();
1278 EXPECT_FALSE(contents()->cross_navigation_pending());
1279 EXPECT_EQ(orig_rvh, rvh());
1280 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, orig_rvh->rvh_state());
1281 EXPECT_EQ(instance1, instance2);
1282 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1285 // Test that NavigationEntries have the correct page state after going
1286 // forward and back. Prevents regression for bug 1116137.
1287 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1288 TestRenderViewHost* orig_rvh = test_rvh();
1290 // Navigate to URL. There should be no committed entry yet.
1291 const GURL url("http://www.google.com");
1292 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1293 NavigationEntry* entry = controller().GetLastCommittedEntry();
1294 EXPECT_TRUE(entry == NULL);
1296 // Committed entry should have page state after DidNavigate.
1297 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1298 entry = controller().GetLastCommittedEntry();
1299 EXPECT_TRUE(entry->GetPageState().IsValid());
1301 // Navigate to same site.
1302 const GURL url2("http://images.google.com");
1303 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1304 entry = controller().GetLastCommittedEntry();
1305 EXPECT_TRUE(entry->GetPageState().IsValid());
1307 // Committed entry should have page state after DidNavigate.
1308 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1309 entry = controller().GetLastCommittedEntry();
1310 EXPECT_TRUE(entry->GetPageState().IsValid());
1312 // Now go back. Committed entry should still have page state.
1313 controller().GoBack();
1314 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1315 entry = controller().GetLastCommittedEntry();
1316 EXPECT_TRUE(entry->GetPageState().IsValid());
1319 // Test that NavigationEntries have the correct page state and SiteInstance
1320 // state after opening a new window to about:blank. Prevents regression for
1321 // bugs b/1116137 and http://crbug.com/111975.
1322 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1323 TestRenderViewHost* orig_rvh = test_rvh();
1325 // When opening a new window, it is navigated to about:blank internally.
1326 // Currently, this results in two DidNavigate events.
1327 const GURL url(url::kAboutBlankURL);
1328 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1329 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1331 // Should have a page state here.
1332 NavigationEntry* entry = controller().GetLastCommittedEntry();
1333 EXPECT_TRUE(entry->GetPageState().IsValid());
1335 // The SiteInstance should be available for other navigations to use.
1336 NavigationEntryImpl* entry_impl =
1337 NavigationEntryImpl::FromNavigationEntry(entry);
1338 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1339 int32 site_instance_id = entry_impl->site_instance()->GetId();
1341 // Navigating to a normal page should not cause a process swap.
1342 const GURL new_url("http://www.google.com");
1343 controller().LoadURL(new_url, Referrer(),
1344 PAGE_TRANSITION_TYPED, std::string());
1345 EXPECT_FALSE(contents()->cross_navigation_pending());
1346 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1347 contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1348 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1349 controller().GetLastCommittedEntry());
1350 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1351 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1354 // Tests that fullscreen is exited throughout the object hierarchy when
1355 // navigating to a new page.
1356 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
1357 FakeFullscreenDelegate fake_delegate;
1358 contents()->SetDelegate(&fake_delegate);
1359 TestRenderViewHost* orig_rvh = test_rvh();
1361 // Navigate to a site.
1362 const GURL url("http://www.google.com");
1363 controller().LoadURL(
1364 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1365 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1366 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1368 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1369 EXPECT_FALSE(orig_rvh->IsFullscreen());
1370 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1371 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1372 orig_rvh->OnMessageReceived(
1373 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1374 EXPECT_TRUE(orig_rvh->IsFullscreen());
1375 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1376 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1378 // Navigate to a new site.
1379 const GURL url2("http://www.yahoo.com");
1380 controller().LoadURL(
1381 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1382 RenderViewHost* const pending_rvh = contents()->GetPendingRenderViewHost();
1383 contents()->TestDidNavigate(
1384 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1386 // Confirm fullscreen has exited.
1387 EXPECT_FALSE(orig_rvh->IsFullscreen());
1388 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1389 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1391 contents()->SetDelegate(NULL);
1394 // Tests that fullscreen is exited throughout the object hierarchy when
1395 // instructing NavigationController to GoBack() or GoForward().
1396 TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
1397 FakeFullscreenDelegate fake_delegate;
1398 contents()->SetDelegate(&fake_delegate);
1399 TestRenderViewHost* const orig_rvh = test_rvh();
1401 // Navigate to a site.
1402 const GURL url("http://www.google.com");
1403 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1404 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1405 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1407 // Now, navigate to another page on the same site.
1408 const GURL url2("http://www.google.com/search?q=kittens");
1409 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1410 EXPECT_FALSE(contents()->cross_navigation_pending());
1411 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1412 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1414 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1415 EXPECT_FALSE(orig_rvh->IsFullscreen());
1416 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1417 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1419 for (int i = 0; i < 2; ++i) {
1420 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1421 orig_rvh->OnMessageReceived(
1422 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1423 EXPECT_TRUE(orig_rvh->IsFullscreen());
1424 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1425 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1427 // Navigate backward (or forward).
1428 if (i == 0)
1429 controller().GoBack();
1430 else
1431 controller().GoForward();
1432 EXPECT_FALSE(contents()->cross_navigation_pending());
1433 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1434 contents()->TestDidNavigate(
1435 orig_rvh, i + 1, url, PAGE_TRANSITION_FORWARD_BACK);
1437 // Confirm fullscreen has exited.
1438 EXPECT_FALSE(orig_rvh->IsFullscreen());
1439 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1440 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1443 contents()->SetDelegate(NULL);
1446 TEST_F(WebContentsImplTest, TerminateHidesValidationMessage) {
1447 FakeValidationMessageDelegate fake_delegate;
1448 contents()->SetDelegate(&fake_delegate);
1449 EXPECT_FALSE(fake_delegate.hide_validation_message_was_called());
1451 // Crash the renderer.
1452 test_rvh()->OnMessageReceived(
1453 ViewHostMsg_RenderProcessGone(
1454 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1456 // Confirm HideValidationMessage was called.
1457 EXPECT_TRUE(fake_delegate.hide_validation_message_was_called());
1459 contents()->SetDelegate(NULL);
1462 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1463 // crash.
1464 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
1465 FakeFullscreenDelegate fake_delegate;
1466 contents()->SetDelegate(&fake_delegate);
1468 // Navigate to a site.
1469 const GURL url("http://www.google.com");
1470 controller().LoadURL(
1471 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1472 contents()->TestDidNavigate(test_rvh(), 1, url, PAGE_TRANSITION_TYPED);
1473 EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
1475 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1476 EXPECT_FALSE(test_rvh()->IsFullscreen());
1477 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1478 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1479 test_rvh()->OnMessageReceived(
1480 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1481 EXPECT_TRUE(test_rvh()->IsFullscreen());
1482 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1483 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1485 // Crash the renderer.
1486 test_rvh()->OnMessageReceived(
1487 ViewHostMsg_RenderProcessGone(
1488 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1490 // Confirm fullscreen has exited.
1491 EXPECT_FALSE(test_rvh()->IsFullscreen());
1492 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1493 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1495 contents()->SetDelegate(NULL);
1498 ////////////////////////////////////////////////////////////////////////////////
1499 // Interstitial Tests
1500 ////////////////////////////////////////////////////////////////////////////////
1502 // Test navigating to a page (with the navigation initiated from the browser,
1503 // as when a URL is typed in the location bar) that shows an interstitial and
1504 // creates a new navigation entry, then hiding it without proceeding.
1505 TEST_F(WebContentsImplTest,
1506 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1507 // Navigate to a page.
1508 GURL url1("http://www.google.com");
1509 test_rvh()->SendNavigate(1, url1);
1510 EXPECT_EQ(1, controller().GetEntryCount());
1512 // Initiate a browser navigation that will trigger the interstitial
1513 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1514 PAGE_TRANSITION_TYPED, std::string());
1516 // Show an interstitial.
1517 TestInterstitialPage::InterstitialState state =
1518 TestInterstitialPage::INVALID;
1519 bool deleted = false;
1520 GURL url2("http://interstitial");
1521 TestInterstitialPage* interstitial =
1522 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1523 TestInterstitialPageStateGuard state_guard(interstitial);
1524 interstitial->Show();
1525 // The interstitial should not show until its navigation has committed.
1526 EXPECT_FALSE(interstitial->is_showing());
1527 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1528 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1529 // Let's commit the interstitial navigation.
1530 interstitial->TestDidNavigate(1, url2);
1531 EXPECT_TRUE(interstitial->is_showing());
1532 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1533 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1534 NavigationEntry* entry = controller().GetVisibleEntry();
1535 ASSERT_TRUE(entry != NULL);
1536 EXPECT_TRUE(entry->GetURL() == url2);
1538 // Now don't proceed.
1539 interstitial->DontProceed();
1540 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1541 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1542 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1543 entry = controller().GetVisibleEntry();
1544 ASSERT_TRUE(entry != NULL);
1545 EXPECT_TRUE(entry->GetURL() == url1);
1546 EXPECT_EQ(1, controller().GetEntryCount());
1548 RunAllPendingInMessageLoop();
1549 EXPECT_TRUE(deleted);
1552 // Test navigating to a page (with the navigation initiated from the renderer,
1553 // as when clicking on a link in the page) that shows an interstitial and
1554 // creates a new navigation entry, then hiding it without proceeding.
1555 TEST_F(WebContentsImplTest,
1556 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1557 // Navigate to a page.
1558 GURL url1("http://www.google.com");
1559 test_rvh()->SendNavigate(1, url1);
1560 EXPECT_EQ(1, controller().GetEntryCount());
1562 // Show an interstitial (no pending entry, the interstitial would have been
1563 // triggered by clicking on a link).
1564 TestInterstitialPage::InterstitialState state =
1565 TestInterstitialPage::INVALID;
1566 bool deleted = false;
1567 GURL url2("http://interstitial");
1568 TestInterstitialPage* interstitial =
1569 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1570 TestInterstitialPageStateGuard state_guard(interstitial);
1571 interstitial->Show();
1572 // The interstitial should not show until its navigation has committed.
1573 EXPECT_FALSE(interstitial->is_showing());
1574 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1575 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1576 // Let's commit the interstitial navigation.
1577 interstitial->TestDidNavigate(1, url2);
1578 EXPECT_TRUE(interstitial->is_showing());
1579 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1580 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1581 NavigationEntry* entry = controller().GetVisibleEntry();
1582 ASSERT_TRUE(entry != NULL);
1583 EXPECT_TRUE(entry->GetURL() == url2);
1585 // Now don't proceed.
1586 interstitial->DontProceed();
1587 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1588 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1589 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1590 entry = controller().GetVisibleEntry();
1591 ASSERT_TRUE(entry != NULL);
1592 EXPECT_TRUE(entry->GetURL() == url1);
1593 EXPECT_EQ(1, controller().GetEntryCount());
1595 RunAllPendingInMessageLoop();
1596 EXPECT_TRUE(deleted);
1599 // Test navigating to a page that shows an interstitial without creating a new
1600 // navigation entry (this happens when the interstitial is triggered by a
1601 // sub-resource in the page), then hiding it without proceeding.
1602 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1603 // Navigate to a page.
1604 GURL url1("http://www.google.com");
1605 test_rvh()->SendNavigate(1, url1);
1606 EXPECT_EQ(1, controller().GetEntryCount());
1608 // Show an interstitial.
1609 TestInterstitialPage::InterstitialState state =
1610 TestInterstitialPage::INVALID;
1611 bool deleted = false;
1612 GURL url2("http://interstitial");
1613 TestInterstitialPage* interstitial =
1614 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1615 TestInterstitialPageStateGuard state_guard(interstitial);
1616 interstitial->Show();
1617 // The interstitial should not show until its navigation has committed.
1618 EXPECT_FALSE(interstitial->is_showing());
1619 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1620 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1621 // Let's commit the interstitial navigation.
1622 interstitial->TestDidNavigate(1, url2);
1623 EXPECT_TRUE(interstitial->is_showing());
1624 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1625 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1626 NavigationEntry* entry = controller().GetVisibleEntry();
1627 ASSERT_TRUE(entry != NULL);
1628 // The URL specified to the interstitial should have been ignored.
1629 EXPECT_TRUE(entry->GetURL() == url1);
1631 // Now don't proceed.
1632 interstitial->DontProceed();
1633 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1634 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1635 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1636 entry = controller().GetVisibleEntry();
1637 ASSERT_TRUE(entry != NULL);
1638 EXPECT_TRUE(entry->GetURL() == url1);
1639 EXPECT_EQ(1, controller().GetEntryCount());
1641 RunAllPendingInMessageLoop();
1642 EXPECT_TRUE(deleted);
1645 // Test navigating to a page (with the navigation initiated from the browser,
1646 // as when a URL is typed in the location bar) that shows an interstitial and
1647 // creates a new navigation entry, then proceeding.
1648 TEST_F(WebContentsImplTest,
1649 ShowInterstitialFromBrowserNewNavigationProceed) {
1650 // Navigate to a page.
1651 GURL url1("http://www.google.com");
1652 test_rvh()->SendNavigate(1, url1);
1653 EXPECT_EQ(1, controller().GetEntryCount());
1655 // Initiate a browser navigation that will trigger the interstitial
1656 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1657 PAGE_TRANSITION_TYPED, std::string());
1659 // Show an interstitial.
1660 TestInterstitialPage::InterstitialState state =
1661 TestInterstitialPage::INVALID;
1662 bool deleted = false;
1663 GURL url2("http://interstitial");
1664 TestInterstitialPage* interstitial =
1665 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1666 TestInterstitialPageStateGuard state_guard(interstitial);
1667 interstitial->Show();
1668 // The interstitial should not show until its navigation has committed.
1669 EXPECT_FALSE(interstitial->is_showing());
1670 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1671 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1672 // Let's commit the interstitial navigation.
1673 interstitial->TestDidNavigate(1, url2);
1674 EXPECT_TRUE(interstitial->is_showing());
1675 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1676 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1677 NavigationEntry* entry = controller().GetVisibleEntry();
1678 ASSERT_TRUE(entry != NULL);
1679 EXPECT_TRUE(entry->GetURL() == url2);
1681 // Then proceed.
1682 interstitial->Proceed();
1683 // The interstitial should show until the new navigation commits.
1684 RunAllPendingInMessageLoop();
1685 ASSERT_FALSE(deleted);
1686 EXPECT_EQ(TestInterstitialPage::OKED, state);
1687 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1688 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1690 // Simulate the navigation to the page, that's when the interstitial gets
1691 // hidden.
1692 GURL url3("http://www.thepage.com");
1693 test_rvh()->SendNavigate(2, url3);
1695 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1696 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1697 entry = controller().GetVisibleEntry();
1698 ASSERT_TRUE(entry != NULL);
1699 EXPECT_TRUE(entry->GetURL() == url3);
1701 EXPECT_EQ(2, controller().GetEntryCount());
1703 RunAllPendingInMessageLoop();
1704 EXPECT_TRUE(deleted);
1707 // Test navigating to a page (with the navigation initiated from the renderer,
1708 // as when clicking on a link in the page) that shows an interstitial and
1709 // creates a new navigation entry, then proceeding.
1710 TEST_F(WebContentsImplTest,
1711 ShowInterstitialFromRendererNewNavigationProceed) {
1712 // Navigate to a page.
1713 GURL url1("http://www.google.com");
1714 test_rvh()->SendNavigate(1, url1);
1715 EXPECT_EQ(1, controller().GetEntryCount());
1717 // Show an interstitial.
1718 TestInterstitialPage::InterstitialState state =
1719 TestInterstitialPage::INVALID;
1720 bool deleted = false;
1721 GURL url2("http://interstitial");
1722 TestInterstitialPage* interstitial =
1723 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1724 TestInterstitialPageStateGuard state_guard(interstitial);
1725 interstitial->Show();
1726 // The interstitial should not show until its navigation has committed.
1727 EXPECT_FALSE(interstitial->is_showing());
1728 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1729 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1730 // Let's commit the interstitial navigation.
1731 interstitial->TestDidNavigate(1, url2);
1732 EXPECT_TRUE(interstitial->is_showing());
1733 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1734 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1735 NavigationEntry* entry = controller().GetVisibleEntry();
1736 ASSERT_TRUE(entry != NULL);
1737 EXPECT_TRUE(entry->GetURL() == url2);
1739 // Then proceed.
1740 interstitial->Proceed();
1741 // The interstitial should show until the new navigation commits.
1742 RunAllPendingInMessageLoop();
1743 ASSERT_FALSE(deleted);
1744 EXPECT_EQ(TestInterstitialPage::OKED, state);
1745 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1746 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1748 // Simulate the navigation to the page, that's when the interstitial gets
1749 // hidden.
1750 GURL url3("http://www.thepage.com");
1751 test_rvh()->SendNavigate(2, url3);
1753 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1754 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1755 entry = controller().GetVisibleEntry();
1756 ASSERT_TRUE(entry != NULL);
1757 EXPECT_TRUE(entry->GetURL() == url3);
1759 EXPECT_EQ(2, controller().GetEntryCount());
1761 RunAllPendingInMessageLoop();
1762 EXPECT_TRUE(deleted);
1765 // Test navigating to a page that shows an interstitial without creating a new
1766 // navigation entry (this happens when the interstitial is triggered by a
1767 // sub-resource in the page), then proceeding.
1768 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1769 // Navigate to a page so we have a navigation entry in the controller.
1770 GURL url1("http://www.google.com");
1771 test_rvh()->SendNavigate(1, url1);
1772 EXPECT_EQ(1, controller().GetEntryCount());
1774 // Show an interstitial.
1775 TestInterstitialPage::InterstitialState state =
1776 TestInterstitialPage::INVALID;
1777 bool deleted = false;
1778 GURL url2("http://interstitial");
1779 TestInterstitialPage* interstitial =
1780 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1781 TestInterstitialPageStateGuard state_guard(interstitial);
1782 interstitial->Show();
1783 // The interstitial should not show until its navigation has committed.
1784 EXPECT_FALSE(interstitial->is_showing());
1785 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1786 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1787 // Let's commit the interstitial navigation.
1788 interstitial->TestDidNavigate(1, url2);
1789 EXPECT_TRUE(interstitial->is_showing());
1790 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1791 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1792 NavigationEntry* entry = controller().GetVisibleEntry();
1793 ASSERT_TRUE(entry != NULL);
1794 // The URL specified to the interstitial should have been ignored.
1795 EXPECT_TRUE(entry->GetURL() == url1);
1797 // Then proceed.
1798 interstitial->Proceed();
1799 // Since this is not a new navigation, the previous page is dismissed right
1800 // away and shows the original page.
1801 EXPECT_EQ(TestInterstitialPage::OKED, state);
1802 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1803 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1804 entry = controller().GetVisibleEntry();
1805 ASSERT_TRUE(entry != NULL);
1806 EXPECT_TRUE(entry->GetURL() == url1);
1808 EXPECT_EQ(1, controller().GetEntryCount());
1810 RunAllPendingInMessageLoop();
1811 EXPECT_TRUE(deleted);
1814 // Test navigating to a page that shows an interstitial, then navigating away.
1815 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1816 // Show interstitial.
1817 TestInterstitialPage::InterstitialState state =
1818 TestInterstitialPage::INVALID;
1819 bool deleted = false;
1820 GURL url("http://interstitial");
1821 TestInterstitialPage* interstitial =
1822 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1823 TestInterstitialPageStateGuard state_guard(interstitial);
1824 interstitial->Show();
1825 interstitial->TestDidNavigate(1, url);
1827 // While interstitial showing, navigate to a new URL.
1828 const GURL url2("http://www.yahoo.com");
1829 test_rvh()->SendNavigate(1, url2);
1831 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1833 RunAllPendingInMessageLoop();
1834 EXPECT_TRUE(deleted);
1837 // Test navigating to a page that shows an interstitial, then going back.
1838 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1839 // Navigate to a page so we have a navigation entry in the controller.
1840 GURL url1("http://www.google.com");
1841 test_rvh()->SendNavigate(1, url1);
1842 EXPECT_EQ(1, controller().GetEntryCount());
1844 // Show interstitial.
1845 TestInterstitialPage::InterstitialState state =
1846 TestInterstitialPage::INVALID;
1847 bool deleted = false;
1848 GURL interstitial_url("http://interstitial");
1849 TestInterstitialPage* interstitial =
1850 new TestInterstitialPage(contents(), true, interstitial_url,
1851 &state, &deleted);
1852 TestInterstitialPageStateGuard state_guard(interstitial);
1853 interstitial->Show();
1854 interstitial->TestDidNavigate(2, interstitial_url);
1856 // While the interstitial is showing, go back.
1857 controller().GoBack();
1858 test_rvh()->SendNavigate(1, url1);
1860 // Make sure we are back to the original page and that the interstitial is
1861 // gone.
1862 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1863 NavigationEntry* entry = controller().GetVisibleEntry();
1864 ASSERT_TRUE(entry);
1865 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1867 RunAllPendingInMessageLoop();
1868 EXPECT_TRUE(deleted);
1871 // Test navigating to a page that shows an interstitial, has a renderer crash,
1872 // and then goes back.
1873 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1874 // Navigate to a page so we have a navigation entry in the controller.
1875 GURL url1("http://www.google.com");
1876 test_rvh()->SendNavigate(1, url1);
1877 EXPECT_EQ(1, controller().GetEntryCount());
1879 // Show interstitial.
1880 TestInterstitialPage::InterstitialState state =
1881 TestInterstitialPage::INVALID;
1882 bool deleted = false;
1883 GURL interstitial_url("http://interstitial");
1884 TestInterstitialPage* interstitial =
1885 new TestInterstitialPage(contents(), true, interstitial_url,
1886 &state, &deleted);
1887 TestInterstitialPageStateGuard state_guard(interstitial);
1888 interstitial->Show();
1889 interstitial->TestDidNavigate(2, interstitial_url);
1891 // Crash the renderer
1892 test_rvh()->OnMessageReceived(
1893 ViewHostMsg_RenderProcessGone(
1894 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1896 // While the interstitial is showing, go back.
1897 controller().GoBack();
1898 test_rvh()->SendNavigate(1, url1);
1900 // Make sure we are back to the original page and that the interstitial is
1901 // gone.
1902 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1903 NavigationEntry* entry = controller().GetVisibleEntry();
1904 ASSERT_TRUE(entry);
1905 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1907 RunAllPendingInMessageLoop();
1908 EXPECT_TRUE(deleted);
1911 // Test navigating to a page that shows an interstitial, has the renderer crash,
1912 // and then navigates to the interstitial.
1913 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1914 // Navigate to a page so we have a navigation entry in the controller.
1915 GURL url1("http://www.google.com");
1916 test_rvh()->SendNavigate(1, url1);
1917 EXPECT_EQ(1, controller().GetEntryCount());
1919 // Show interstitial.
1920 TestInterstitialPage::InterstitialState state =
1921 TestInterstitialPage::INVALID;
1922 bool deleted = false;
1923 GURL interstitial_url("http://interstitial");
1924 TestInterstitialPage* interstitial =
1925 new TestInterstitialPage(contents(), true, interstitial_url,
1926 &state, &deleted);
1927 TestInterstitialPageStateGuard state_guard(interstitial);
1928 interstitial->Show();
1930 // Crash the renderer
1931 test_rvh()->OnMessageReceived(
1932 ViewHostMsg_RenderProcessGone(
1933 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1935 interstitial->TestDidNavigate(2, interstitial_url);
1938 // Test navigating to a page that shows an interstitial, then close the
1939 // contents.
1940 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1941 // Show interstitial.
1942 TestInterstitialPage::InterstitialState state =
1943 TestInterstitialPage::INVALID;
1944 bool deleted = false;
1945 GURL url("http://interstitial");
1946 TestInterstitialPage* interstitial =
1947 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1948 TestInterstitialPageStateGuard state_guard(interstitial);
1949 interstitial->Show();
1950 interstitial->TestDidNavigate(1, url);
1952 // Now close the contents.
1953 DeleteContents();
1954 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1956 RunAllPendingInMessageLoop();
1957 EXPECT_TRUE(deleted);
1960 // Test navigating to a page that shows an interstitial, then close the
1961 // contents.
1962 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1963 // Show interstitial.
1964 TestInterstitialPage::InterstitialState state =
1965 TestInterstitialPage::INVALID;
1966 bool deleted = false;
1967 GURL url("http://interstitial");
1968 TestInterstitialPage* interstitial =
1969 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1970 TestInterstitialPageStateGuard state_guard(interstitial);
1971 interstitial->Show();
1972 interstitial->TestDidNavigate(1, url);
1973 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1974 interstitial->GetRenderViewHostForTesting());
1976 // Now close the contents.
1977 DeleteContents();
1978 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1980 // Before the interstitial has a chance to process its shutdown task,
1981 // simulate quitting the browser. This goes through all processes and
1982 // tells them to destruct.
1983 rvh->OnMessageReceived(
1984 ViewHostMsg_RenderProcessGone(0, 0, 0));
1986 RunAllPendingInMessageLoop();
1987 EXPECT_TRUE(deleted);
1990 // Test that after Proceed is called and an interstitial is still shown, no more
1991 // commands get executed.
1992 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1993 // Navigate to a page so we have a navigation entry in the controller.
1994 GURL url1("http://www.google.com");
1995 test_rvh()->SendNavigate(1, url1);
1996 EXPECT_EQ(1, controller().GetEntryCount());
1998 // Show an interstitial.
1999 TestInterstitialPage::InterstitialState state =
2000 TestInterstitialPage::INVALID;
2001 bool deleted = false;
2002 GURL url2("http://interstitial");
2003 TestInterstitialPage* interstitial =
2004 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2005 TestInterstitialPageStateGuard state_guard(interstitial);
2006 interstitial->Show();
2007 interstitial->TestDidNavigate(1, url2);
2009 // Run a command.
2010 EXPECT_EQ(0, interstitial->command_received_count());
2011 interstitial->TestDomOperationResponse("toto");
2012 EXPECT_EQ(1, interstitial->command_received_count());
2014 // Then proceed.
2015 interstitial->Proceed();
2016 RunAllPendingInMessageLoop();
2017 ASSERT_FALSE(deleted);
2019 // While the navigation to the new page is pending, send other commands, they
2020 // should be ignored.
2021 interstitial->TestDomOperationResponse("hello");
2022 interstitial->TestDomOperationResponse("hi");
2023 EXPECT_EQ(1, interstitial->command_received_count());
2026 // Test showing an interstitial while another interstitial is already showing.
2027 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
2028 // Navigate to a page so we have a navigation entry in the controller.
2029 GURL start_url("http://www.google.com");
2030 test_rvh()->SendNavigate(1, start_url);
2031 EXPECT_EQ(1, controller().GetEntryCount());
2033 // Show an interstitial.
2034 TestInterstitialPage::InterstitialState state1 =
2035 TestInterstitialPage::INVALID;
2036 bool deleted1 = false;
2037 GURL url1("http://interstitial1");
2038 TestInterstitialPage* interstitial1 =
2039 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
2040 TestInterstitialPageStateGuard state_guard1(interstitial1);
2041 interstitial1->Show();
2042 interstitial1->TestDidNavigate(1, url1);
2044 // Now show another interstitial.
2045 TestInterstitialPage::InterstitialState state2 =
2046 TestInterstitialPage::INVALID;
2047 bool deleted2 = false;
2048 GURL url2("http://interstitial2");
2049 TestInterstitialPage* interstitial2 =
2050 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2051 TestInterstitialPageStateGuard state_guard2(interstitial2);
2052 interstitial2->Show();
2053 interstitial2->TestDidNavigate(1, url2);
2055 // Showing interstitial2 should have caused interstitial1 to go away.
2056 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2057 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2059 RunAllPendingInMessageLoop();
2060 EXPECT_TRUE(deleted1);
2061 ASSERT_FALSE(deleted2);
2063 // Let's make sure interstitial2 is working as intended.
2064 interstitial2->Proceed();
2065 GURL landing_url("http://www.thepage.com");
2066 test_rvh()->SendNavigate(2, landing_url);
2068 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2069 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
2070 NavigationEntry* entry = controller().GetVisibleEntry();
2071 ASSERT_TRUE(entry != NULL);
2072 EXPECT_TRUE(entry->GetURL() == landing_url);
2073 EXPECT_EQ(2, controller().GetEntryCount());
2074 RunAllPendingInMessageLoop();
2075 EXPECT_TRUE(deleted2);
2078 // Test showing an interstitial, proceeding and then navigating to another
2079 // interstitial.
2080 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
2081 // Navigate to a page so we have a navigation entry in the controller.
2082 GURL start_url("http://www.google.com");
2083 test_rvh()->SendNavigate(1, start_url);
2084 EXPECT_EQ(1, controller().GetEntryCount());
2086 // Show an interstitial.
2087 TestInterstitialPage::InterstitialState state1 =
2088 TestInterstitialPage::INVALID;
2089 bool deleted1 = false;
2090 GURL url1("http://interstitial1");
2091 TestInterstitialPage* interstitial1 =
2092 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
2093 TestInterstitialPageStateGuard state_guard1(interstitial1);
2094 interstitial1->Show();
2095 interstitial1->TestDidNavigate(1, url1);
2097 // Take action. The interstitial won't be hidden until the navigation is
2098 // committed.
2099 interstitial1->Proceed();
2100 EXPECT_EQ(TestInterstitialPage::OKED, state1);
2102 // Now show another interstitial (simulating the navigation causing another
2103 // interstitial).
2104 TestInterstitialPage::InterstitialState state2 =
2105 TestInterstitialPage::INVALID;
2106 bool deleted2 = false;
2107 GURL url2("http://interstitial2");
2108 TestInterstitialPage* interstitial2 =
2109 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2110 TestInterstitialPageStateGuard state_guard2(interstitial2);
2111 interstitial2->Show();
2112 interstitial2->TestDidNavigate(1, url2);
2114 // Showing interstitial2 should have caused interstitial1 to go away.
2115 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2116 RunAllPendingInMessageLoop();
2117 EXPECT_TRUE(deleted1);
2118 ASSERT_FALSE(deleted2);
2120 // Let's make sure interstitial2 is working as intended.
2121 interstitial2->Proceed();
2122 GURL landing_url("http://www.thepage.com");
2123 test_rvh()->SendNavigate(2, landing_url);
2125 RunAllPendingInMessageLoop();
2126 EXPECT_TRUE(deleted2);
2127 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2128 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
2129 NavigationEntry* entry = controller().GetVisibleEntry();
2130 ASSERT_TRUE(entry != NULL);
2131 EXPECT_TRUE(entry->GetURL() == landing_url);
2132 EXPECT_EQ(2, controller().GetEntryCount());
2135 // Test that navigating away from an interstitial while it's loading cause it
2136 // not to show.
2137 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
2138 // Show an interstitial.
2139 TestInterstitialPage::InterstitialState state =
2140 TestInterstitialPage::INVALID;
2141 bool deleted = false;
2142 GURL interstitial_url("http://interstitial");
2143 TestInterstitialPage* interstitial =
2144 new TestInterstitialPage(contents(), true, interstitial_url,
2145 &state, &deleted);
2146 TestInterstitialPageStateGuard state_guard(interstitial);
2147 interstitial->Show();
2149 // Let's simulate a navigation initiated from the browser before the
2150 // interstitial finishes loading.
2151 const GURL url("http://www.google.com");
2152 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2153 EXPECT_FALSE(interstitial->is_showing());
2154 RunAllPendingInMessageLoop();
2155 ASSERT_FALSE(deleted);
2157 // Now let's make the interstitial navigation commit.
2158 interstitial->TestDidNavigate(1, interstitial_url);
2160 // After it loaded the interstitial should be gone.
2161 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2163 RunAllPendingInMessageLoop();
2164 EXPECT_TRUE(deleted);
2167 // Test that a new request to show an interstitial while an interstitial is
2168 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2169 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
2170 GURL interstitial_url("http://interstitial");
2172 // Show a first interstitial.
2173 TestInterstitialPage::InterstitialState state1 =
2174 TestInterstitialPage::INVALID;
2175 bool deleted1 = false;
2176 TestInterstitialPage* interstitial1 =
2177 new TestInterstitialPage(contents(), true, interstitial_url,
2178 &state1, &deleted1);
2179 TestInterstitialPageStateGuard state_guard1(interstitial1);
2180 interstitial1->Show();
2182 // Show another interstitial on that same contents before the first one had
2183 // time to load.
2184 TestInterstitialPage::InterstitialState state2 =
2185 TestInterstitialPage::INVALID;
2186 bool deleted2 = false;
2187 TestInterstitialPage* interstitial2 =
2188 new TestInterstitialPage(contents(), true, interstitial_url,
2189 &state2, &deleted2);
2190 TestInterstitialPageStateGuard state_guard2(interstitial2);
2191 interstitial2->Show();
2193 // The first interstitial should have been closed and deleted.
2194 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2195 // The 2nd one should still be OK.
2196 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2198 RunAllPendingInMessageLoop();
2199 EXPECT_TRUE(deleted1);
2200 ASSERT_FALSE(deleted2);
2202 // Make the interstitial navigation commit it should be showing.
2203 interstitial2->TestDidNavigate(1, interstitial_url);
2204 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
2207 // Test showing an interstitial and have its renderer crash.
2208 TEST_F(WebContentsImplTest, InterstitialCrasher) {
2209 // Show an interstitial.
2210 TestInterstitialPage::InterstitialState state =
2211 TestInterstitialPage::INVALID;
2212 bool deleted = false;
2213 GURL url("http://interstitial");
2214 TestInterstitialPage* interstitial =
2215 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2216 TestInterstitialPageStateGuard state_guard(interstitial);
2217 interstitial->Show();
2218 // Simulate a renderer crash before the interstitial is shown.
2219 interstitial->TestRenderViewTerminated(
2220 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2221 // The interstitial should have been dismissed.
2222 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2223 RunAllPendingInMessageLoop();
2224 EXPECT_TRUE(deleted);
2226 // Now try again but this time crash the intersitial after it was shown.
2227 interstitial =
2228 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2229 interstitial->Show();
2230 interstitial->TestDidNavigate(1, url);
2231 // Simulate a renderer crash.
2232 interstitial->TestRenderViewTerminated(
2233 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2234 // The interstitial should have been dismissed.
2235 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2236 RunAllPendingInMessageLoop();
2237 EXPECT_TRUE(deleted);
2240 // Tests that showing an interstitial as a result of a browser initiated
2241 // navigation while an interstitial is showing does not remove the pending
2242 // entry (see http://crbug.com/9791).
2243 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
2244 const char kUrl[] = "http://www.badguys.com/";
2245 const GURL kGURL(kUrl);
2247 // Start a navigation to a page
2248 contents()->GetController().LoadURL(
2249 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2251 // Simulate that navigation triggering an interstitial.
2252 TestInterstitialPage::InterstitialState state =
2253 TestInterstitialPage::INVALID;
2254 bool deleted = false;
2255 TestInterstitialPage* interstitial =
2256 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2257 TestInterstitialPageStateGuard state_guard(interstitial);
2258 interstitial->Show();
2259 interstitial->TestDidNavigate(1, kGURL);
2261 // Initiate a new navigation from the browser that also triggers an
2262 // interstitial.
2263 contents()->GetController().LoadURL(
2264 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2265 TestInterstitialPage::InterstitialState state2 =
2266 TestInterstitialPage::INVALID;
2267 bool deleted2 = false;
2268 TestInterstitialPage* interstitial2 =
2269 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
2270 TestInterstitialPageStateGuard state_guard2(interstitial2);
2271 interstitial2->Show();
2272 interstitial2->TestDidNavigate(1, kGURL);
2274 // Make sure we still have an entry.
2275 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2276 ASSERT_TRUE(entry);
2277 EXPECT_EQ(kUrl, entry->GetURL().spec());
2279 // And that the first interstitial is gone, but not the second.
2280 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2281 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2282 RunAllPendingInMessageLoop();
2283 EXPECT_TRUE(deleted);
2284 EXPECT_FALSE(deleted2);
2287 // Tests that Javascript messages are not shown while an interstitial is
2288 // showing.
2289 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2290 const char kUrl[] = "http://www.badguys.com/";
2291 const GURL kGURL(kUrl);
2293 // Start a navigation to a page
2294 contents()->GetController().LoadURL(
2295 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2296 // DidNavigate from the page
2297 contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
2299 // Simulate showing an interstitial while the page is showing.
2300 TestInterstitialPage::InterstitialState state =
2301 TestInterstitialPage::INVALID;
2302 bool deleted = false;
2303 TestInterstitialPage* interstitial =
2304 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2305 TestInterstitialPageStateGuard state_guard(interstitial);
2306 interstitial->Show();
2307 interstitial->TestDidNavigate(1, kGURL);
2309 // While the interstitial is showing, let's simulate the hidden page
2310 // attempting to show a JS message.
2311 IPC::Message* dummy_message = new IPC::Message;
2312 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2313 base::ASCIIToUTF16("This is an informative message"),
2314 base::ASCIIToUTF16("OK"),
2315 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message);
2316 EXPECT_TRUE(contents()->last_dialog_suppressed_);
2319 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2320 // interstitial it isn't copied over to the destination.
2321 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2322 // Navigate to a page.
2323 GURL url1("http://www.google.com");
2324 test_rvh()->SendNavigate(1, url1);
2325 EXPECT_EQ(1, controller().GetEntryCount());
2327 // Initiate a browser navigation that will trigger the interstitial
2328 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2329 PAGE_TRANSITION_TYPED, std::string());
2331 // Show an interstitial.
2332 TestInterstitialPage::InterstitialState state =
2333 TestInterstitialPage::INVALID;
2334 bool deleted = false;
2335 GURL url2("http://interstitial");
2336 TestInterstitialPage* interstitial =
2337 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2338 TestInterstitialPageStateGuard state_guard(interstitial);
2339 interstitial->Show();
2340 interstitial->TestDidNavigate(1, url2);
2341 EXPECT_TRUE(interstitial->is_showing());
2342 EXPECT_EQ(2, controller().GetEntryCount());
2344 // Create another NavigationController.
2345 GURL url3("http://foo2");
2346 scoped_ptr<TestWebContents> other_contents(
2347 static_cast<TestWebContents*>(CreateTestWebContents()));
2348 NavigationControllerImpl& other_controller = other_contents->GetController();
2349 other_contents->NavigateAndCommit(url3);
2350 other_contents->ExpectSetHistoryLengthAndPrune(
2351 NavigationEntryImpl::FromNavigationEntry(
2352 other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2353 other_controller.GetEntryAtIndex(0)->GetPageID());
2354 other_controller.CopyStateFromAndPrune(&controller(), false);
2356 // The merged controller should only have two entries: url1 and url2.
2357 ASSERT_EQ(2, other_controller.GetEntryCount());
2358 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2359 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2360 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2362 // And the merged controller shouldn't be showing an interstitial.
2363 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2366 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2367 // showing an interstitial.
2368 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2369 // Navigate to a page.
2370 GURL url1("http://www.google.com");
2371 contents()->NavigateAndCommit(url1);
2373 // Create another NavigationController.
2374 scoped_ptr<TestWebContents> other_contents(
2375 static_cast<TestWebContents*>(CreateTestWebContents()));
2376 NavigationControllerImpl& other_controller = other_contents->GetController();
2378 // Navigate it to url2.
2379 GURL url2("http://foo2");
2380 other_contents->NavigateAndCommit(url2);
2382 // Show an interstitial.
2383 TestInterstitialPage::InterstitialState state =
2384 TestInterstitialPage::INVALID;
2385 bool deleted = false;
2386 GURL url3("http://interstitial");
2387 TestInterstitialPage* interstitial =
2388 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2389 &deleted);
2390 TestInterstitialPageStateGuard state_guard(interstitial);
2391 interstitial->Show();
2392 interstitial->TestDidNavigate(1, url3);
2393 EXPECT_TRUE(interstitial->is_showing());
2394 EXPECT_EQ(2, other_controller.GetEntryCount());
2396 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2397 // interstitial is showing in the target.
2398 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2401 // Regression test for http://crbug.com/168611 - the URLs passed by the
2402 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2403 TEST_F(WebContentsImplTest, FilterURLs) {
2404 TestWebContentsObserver observer(contents());
2406 // A navigation to about:whatever should always look like a navigation to
2407 // about:blank
2408 GURL url_normalized(url::kAboutBlankURL);
2409 GURL url_from_ipc("about:whatever");
2411 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2412 // will use the given URL to create the NavigationEntry as well, and that
2413 // entry should contain the filtered URL.
2414 contents()->NavigateAndCommit(url_normalized);
2416 // Check that an IPC with about:whatever is correctly normalized.
2417 contents()->TestDidFinishLoad(url_from_ipc);
2419 EXPECT_EQ(url_normalized, observer.last_url());
2421 // Create and navigate another WebContents.
2422 scoped_ptr<TestWebContents> other_contents(
2423 static_cast<TestWebContents*>(CreateTestWebContents()));
2424 TestWebContentsObserver other_observer(other_contents.get());
2425 other_contents->NavigateAndCommit(url_normalized);
2427 // Check that an IPC with about:whatever is correctly normalized.
2428 other_contents->TestDidFailLoadWithError(
2429 url_from_ipc, 1, base::string16());
2430 EXPECT_EQ(url_normalized, other_observer.last_url());
2433 // Test that if a pending contents is deleted before it is shown, we don't
2434 // crash.
2435 TEST_F(WebContentsImplTest, PendingContents) {
2436 scoped_ptr<TestWebContents> other_contents(
2437 static_cast<TestWebContents*>(CreateTestWebContents()));
2438 contents()->AddPendingContents(other_contents.get());
2439 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2440 other_contents.reset();
2441 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2444 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
2445 const gfx::Size original_preferred_size(1024, 768);
2446 contents()->UpdatePreferredSize(original_preferred_size);
2448 // With no capturers, expect the preferred size to be the one propagated into
2449 // WebContentsImpl via the RenderViewHostDelegate interface.
2450 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2451 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2453 // Increment capturer count, but without specifying a capture size. Expect
2454 // a "not set" preferred size.
2455 contents()->IncrementCapturerCount(gfx::Size());
2456 EXPECT_EQ(1, contents()->GetCapturerCount());
2457 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2459 // Increment capturer count again, but with an overriding capture size.
2460 // Expect preferred size to now be overridden to the capture size.
2461 const gfx::Size capture_size(1280, 720);
2462 contents()->IncrementCapturerCount(capture_size);
2463 EXPECT_EQ(2, contents()->GetCapturerCount());
2464 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2466 // Increment capturer count a third time, but the expect that the preferred
2467 // size is still the first capture size.
2468 const gfx::Size another_capture_size(720, 480);
2469 contents()->IncrementCapturerCount(another_capture_size);
2470 EXPECT_EQ(3, contents()->GetCapturerCount());
2471 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2473 // Decrement capturer count twice, but expect the preferred size to still be
2474 // overridden.
2475 contents()->DecrementCapturerCount();
2476 contents()->DecrementCapturerCount();
2477 EXPECT_EQ(1, contents()->GetCapturerCount());
2478 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2480 // Decrement capturer count, and since the count has dropped to zero, the
2481 // original preferred size should be restored.
2482 contents()->DecrementCapturerCount();
2483 EXPECT_EQ(0, contents()->GetCapturerCount());
2484 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2487 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2488 // on activity.
2489 TEST_F(WebContentsImplTest, GetLastActiveTime) {
2490 // The WebContents starts with a valid creation time.
2491 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2493 // Reset the last active time to a known-bad value.
2494 contents()->last_active_time_ = base::TimeTicks();
2495 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2497 // Simulate activating the WebContents. The active time should update.
2498 contents()->WasShown();
2499 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2502 class ContentsZoomChangedDelegate : public WebContentsDelegate {
2503 public:
2504 ContentsZoomChangedDelegate() :
2505 contents_zoom_changed_call_count_(0),
2506 last_zoom_in_(false) {
2509 int GetAndResetContentsZoomChangedCallCount() {
2510 int count = contents_zoom_changed_call_count_;
2511 contents_zoom_changed_call_count_ = 0;
2512 return count;
2515 bool last_zoom_in() const {
2516 return last_zoom_in_;
2519 // WebContentsDelegate:
2520 virtual void ContentsZoomChange(bool zoom_in) OVERRIDE {
2521 contents_zoom_changed_call_count_++;
2522 last_zoom_in_ = zoom_in;
2525 private:
2526 int contents_zoom_changed_call_count_;
2527 bool last_zoom_in_;
2529 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
2532 // Tests that some mouseehweel events get turned into browser zoom requests.
2533 TEST_F(WebContentsImplTest, HandleWheelEvent) {
2534 using blink::WebInputEvent;
2536 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2537 new ContentsZoomChangedDelegate());
2538 contents()->SetDelegate(delegate.get());
2540 int modifiers = 0;
2541 // Verify that normal mouse wheel events do nothing to change the zoom level.
2542 blink::WebMouseWheelEvent event =
2543 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2544 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2545 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2547 modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey;
2548 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2549 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2550 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2552 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2553 // Except on MacOS where we never want to adjust zoom with mousewheel.
2554 modifiers = WebInputEvent::ControlKey;
2555 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2556 bool handled = contents()->HandleWheelEvent(event);
2557 #if defined(OS_MACOSX)
2558 EXPECT_FALSE(handled);
2559 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2560 #else
2561 EXPECT_TRUE(handled);
2562 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2563 EXPECT_TRUE(delegate->last_zoom_in());
2564 #endif
2566 modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
2567 WebInputEvent::AltKey;
2568 event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false);
2569 handled = contents()->HandleWheelEvent(event);
2570 #if defined(OS_MACOSX)
2571 EXPECT_FALSE(handled);
2572 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2573 #else
2574 EXPECT_TRUE(handled);
2575 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2576 EXPECT_FALSE(delegate->last_zoom_in());
2577 #endif
2579 // Unless there is no vertical movement.
2580 event = SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers, false);
2581 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2582 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2584 // Events containing precise scrolling deltas also shouldn't result in the
2585 // zoom being adjusted, to avoid accidental adjustments caused by
2586 // two-finger-scrolling on a touchpad.
2587 modifiers = WebInputEvent::ControlKey;
2588 event = SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers, true);
2589 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2590 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2592 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2593 contents()->SetDelegate(NULL);
2596 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2597 TEST_F(WebContentsImplTest, HandleGestureEvent) {
2598 using blink::WebGestureEvent;
2599 using blink::WebInputEvent;
2601 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2602 new ContentsZoomChangedDelegate());
2603 contents()->SetDelegate(delegate.get());
2605 const float kZoomStepValue = 0.6f;
2606 blink::WebGestureEvent event = SyntheticWebGestureEventBuilder::Build(
2607 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchpad);
2609 // A pinch less than the step value doesn't change the zoom level.
2610 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 0.8f;
2611 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2612 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2614 // But repeating the event so the combined scale is greater does.
2615 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2616 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2617 EXPECT_TRUE(delegate->last_zoom_in());
2619 // Pinching back out one step goes back to 100%.
2620 event.data.pinchUpdate.scale = 1.0f - kZoomStepValue;
2621 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2622 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2623 EXPECT_FALSE(delegate->last_zoom_in());
2625 // Pinching out again doesn't zoom (step is twice as large around 100%).
2626 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2627 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2629 // And again now it zooms once per step.
2630 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2631 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2632 EXPECT_FALSE(delegate->last_zoom_in());
2634 // No other type of gesture event is handled by WebContentsImpl (for example
2635 // a touchscreen pinch gesture).
2636 event = SyntheticWebGestureEventBuilder::Build(
2637 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchscreen);
2638 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 3;
2639 EXPECT_FALSE(contents()->HandleGestureEvent(event));
2640 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2642 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2643 contents()->SetDelegate(NULL);
2646 // Tests that GetRelatedActiveContentsCount is shared between related
2647 // SiteInstances and includes WebContents that have not navigated yet.
2648 TEST_F(WebContentsImplTest, ActiveContentsCountBasic) {
2649 scoped_refptr<SiteInstance> instance1(
2650 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2651 scoped_refptr<SiteInstance> instance2(
2652 instance1->GetRelatedSiteInstance(GURL("http://b.com")));
2654 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2655 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2657 scoped_ptr<TestWebContents> contents1(
2658 TestWebContents::Create(browser_context(), instance1));
2659 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2660 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2662 scoped_ptr<TestWebContents> contents2(
2663 TestWebContents::Create(browser_context(), instance1));
2664 EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount());
2665 EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount());
2667 contents1.reset();
2668 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2669 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2671 contents2.reset();
2672 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2673 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2676 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2677 // same-site and cross-site navigations.
2678 TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
2679 scoped_refptr<SiteInstance> instance(
2680 SiteInstance::Create(browser_context()));
2682 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2684 scoped_ptr<TestWebContents> contents(
2685 TestWebContents::Create(browser_context(), instance));
2686 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2688 // Navigate to a URL.
2689 contents->GetController().LoadURL(
2690 GURL("http://a.com/1"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2691 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2692 contents->CommitPendingNavigation();
2693 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2695 // Navigate to a URL in the same site.
2696 contents->GetController().LoadURL(
2697 GURL("http://a.com/2"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2698 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2699 contents->CommitPendingNavigation();
2700 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2702 // Navigate to a URL in a different site.
2703 contents->GetController().LoadURL(
2704 GURL("http://b.com"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2705 EXPECT_TRUE(contents->cross_navigation_pending());
2706 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2707 contents->CommitPendingNavigation();
2708 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2710 contents.reset();
2711 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2714 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2715 // from WebUI.
2716 TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
2717 scoped_refptr<SiteInstance> instance(
2718 SiteInstance::Create(browser_context()));
2720 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2722 scoped_ptr<TestWebContents> contents(
2723 TestWebContents::Create(browser_context(), instance));
2724 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2726 // Navigate to a URL.
2727 contents->NavigateAndCommit(GURL("http://a.com"));
2728 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2730 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2731 contents->GetController().LoadURL(
2732 GURL(kTestWebUIUrl), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2733 EXPECT_TRUE(contents->cross_navigation_pending());
2734 scoped_refptr<SiteInstance> instance_webui(
2735 contents->GetPendingRenderViewHost()->GetSiteInstance());
2736 EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
2738 // At this point, contents still counts for the old BrowsingInstance.
2739 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2740 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2742 // Commit and contents counts for the new one.
2743 contents->CommitPendingNavigation();
2744 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2745 EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount());
2747 contents.reset();
2748 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2749 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2752 } // namespace content