Move about://-related constants from //content to //url
[chromium-blink-merge.git] / content / browser / web_contents / web_contents_impl_unittest.cc
blobb487a163b66d2208d91d80b834907c0c8a6e4bb0
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/logging.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "content/browser/frame_host/cross_site_transferring_request.h"
8 #include "content/browser/frame_host/interstitial_page_impl.h"
9 #include "content/browser/frame_host/navigation_entry_impl.h"
10 #include "content/browser/renderer_host/render_view_host_impl.h"
11 #include "content/browser/site_instance_impl.h"
12 #include "content/browser/webui/web_ui_controller_factory_registry.h"
13 #include "content/common/frame_messages.h"
14 #include "content/common/input/synthetic_web_input_event_builders.h"
15 #include "content/common/view_messages.h"
16 #include "content/public/browser/global_request_id.h"
17 #include "content/public/browser/interstitial_page_delegate.h"
18 #include "content/public/browser/navigation_details.h"
19 #include "content/public/browser/notification_details.h"
20 #include "content/public/browser/notification_source.h"
21 #include "content/public/browser/render_widget_host_view.h"
22 #include "content/public/browser/web_contents_delegate.h"
23 #include "content/public/browser/web_contents_observer.h"
24 #include "content/public/browser/web_ui_controller.h"
25 #include "content/public/common/bindings_policy.h"
26 #include "content/public/common/content_constants.h"
27 #include "content/public/common/url_constants.h"
28 #include "content/public/common/url_utils.h"
29 #include "content/public/test/mock_render_process_host.h"
30 #include "content/public/test/test_utils.h"
31 #include "content/test/test_content_browser_client.h"
32 #include "content/test/test_content_client.h"
33 #include "content/test/test_render_view_host.h"
34 #include "content/test/test_web_contents.h"
35 #include "testing/gtest/include/gtest/gtest.h"
37 namespace content {
38 namespace {
40 const char kTestWebUIUrl[] = "chrome://blah";
42 class WebContentsImplTestWebUIControllerFactory
43 : public WebUIControllerFactory {
44 public:
45 virtual WebUIController* CreateWebUIControllerForURL(
46 WebUI* web_ui, const GURL& url) const OVERRIDE {
47 if (!UseWebUI(url))
48 return NULL;
49 return new WebUIController(web_ui);
52 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
53 const GURL& url) const OVERRIDE {
54 return WebUI::kNoWebUI;
57 virtual bool UseWebUIForURL(BrowserContext* browser_context,
58 const GURL& url) const OVERRIDE {
59 return UseWebUI(url);
62 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
63 const GURL& url) const OVERRIDE {
64 return UseWebUI(url);
67 private:
68 bool UseWebUI(const GURL& url) const {
69 return url == GURL(kTestWebUIUrl);
73 class TestInterstitialPage;
75 class TestInterstitialPageDelegate : public InterstitialPageDelegate {
76 public:
77 explicit TestInterstitialPageDelegate(TestInterstitialPage* interstitial_page)
78 : interstitial_page_(interstitial_page) {}
79 virtual void CommandReceived(const std::string& command) OVERRIDE;
80 virtual std::string GetHTMLContents() OVERRIDE { return std::string(); }
81 virtual void OnDontProceed() OVERRIDE;
82 virtual void OnProceed() OVERRIDE;
83 private:
84 TestInterstitialPage* interstitial_page_;
87 class TestInterstitialPage : public InterstitialPageImpl {
88 public:
89 enum InterstitialState {
90 INVALID = 0, // Hasn't yet been initialized.
91 UNDECIDED, // Initialized, but no decision taken yet.
92 OKED, // Proceed was called.
93 CANCELED // DontProceed was called.
96 class Delegate {
97 public:
98 virtual void TestInterstitialPageDeleted(
99 TestInterstitialPage* interstitial) = 0;
101 protected:
102 virtual ~Delegate() {}
105 // IMPORTANT NOTE: if you pass stack allocated values for |state| and
106 // |deleted| (like all interstitial related tests do at this point), make sure
107 // to create an instance of the TestInterstitialPageStateGuard class on the
108 // stack in your test. This will ensure that the TestInterstitialPage states
109 // are cleared when the test finishes.
110 // Not doing so will cause stack trashing if your test does not hide the
111 // interstitial, as in such a case it will be destroyed in the test TearDown
112 // method and will dereference the |deleted| local variable which by then is
113 // out of scope.
114 TestInterstitialPage(WebContentsImpl* contents,
115 bool new_navigation,
116 const GURL& url,
117 InterstitialState* state,
118 bool* deleted)
119 : InterstitialPageImpl(
120 contents,
121 static_cast<RenderWidgetHostDelegate*>(contents),
122 new_navigation, url, new TestInterstitialPageDelegate(this)),
123 state_(state),
124 deleted_(deleted),
125 command_received_count_(0),
126 delegate_(NULL) {
127 *state_ = UNDECIDED;
128 *deleted_ = false;
131 virtual ~TestInterstitialPage() {
132 if (deleted_)
133 *deleted_ = true;
134 if (delegate_)
135 delegate_->TestInterstitialPageDeleted(this);
138 void OnDontProceed() {
139 if (state_)
140 *state_ = CANCELED;
142 void OnProceed() {
143 if (state_)
144 *state_ = OKED;
147 int command_received_count() const {
148 return command_received_count_;
151 void TestDomOperationResponse(const std::string& json_string) {
152 if (enabled())
153 CommandReceived();
156 void TestDidNavigate(int page_id, const GURL& url) {
157 FrameHostMsg_DidCommitProvisionalLoad_Params params;
158 InitNavigateParams(&params, page_id, url, PAGE_TRANSITION_TYPED);
159 DidNavigate(GetRenderViewHostForTesting(), params);
162 void TestRenderViewTerminated(base::TerminationStatus status,
163 int error_code) {
164 RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code);
167 bool is_showing() const {
168 return static_cast<TestRenderWidgetHostView*>(
169 GetRenderViewHostForTesting()->GetView())->is_showing();
172 void ClearStates() {
173 state_ = NULL;
174 deleted_ = NULL;
175 delegate_ = NULL;
178 void CommandReceived() {
179 command_received_count_++;
182 void set_delegate(Delegate* delegate) {
183 delegate_ = delegate;
186 protected:
187 virtual WebContentsView* CreateWebContentsView() OVERRIDE {
188 return NULL;
191 private:
192 InterstitialState* state_;
193 bool* deleted_;
194 int command_received_count_;
195 Delegate* delegate_;
198 void TestInterstitialPageDelegate::CommandReceived(const std::string& command) {
199 interstitial_page_->CommandReceived();
202 void TestInterstitialPageDelegate::OnDontProceed() {
203 interstitial_page_->OnDontProceed();
206 void TestInterstitialPageDelegate::OnProceed() {
207 interstitial_page_->OnProceed();
210 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate {
211 public:
212 explicit TestInterstitialPageStateGuard(
213 TestInterstitialPage* interstitial_page)
214 : interstitial_page_(interstitial_page) {
215 DCHECK(interstitial_page_);
216 interstitial_page_->set_delegate(this);
218 virtual ~TestInterstitialPageStateGuard() {
219 if (interstitial_page_)
220 interstitial_page_->ClearStates();
223 virtual void TestInterstitialPageDeleted(
224 TestInterstitialPage* interstitial) OVERRIDE {
225 DCHECK(interstitial_page_ == interstitial);
226 interstitial_page_ = NULL;
229 private:
230 TestInterstitialPage* interstitial_page_;
233 class WebContentsImplTestBrowserClient : public TestContentBrowserClient {
234 public:
235 WebContentsImplTestBrowserClient()
236 : assign_site_for_url_(false) {}
238 virtual ~WebContentsImplTestBrowserClient() {}
240 virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE {
241 return assign_site_for_url_;
244 void set_assign_site_for_url(bool assign) {
245 assign_site_for_url_ = assign;
248 private:
249 bool assign_site_for_url_;
252 class WebContentsImplTest : public RenderViewHostImplTestHarness {
253 public:
254 virtual void SetUp() {
255 RenderViewHostImplTestHarness::SetUp();
256 WebUIControllerFactory::RegisterFactory(&factory_);
259 virtual void TearDown() {
260 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
261 RenderViewHostImplTestHarness::TearDown();
264 private:
265 WebContentsImplTestWebUIControllerFactory factory_;
268 class TestWebContentsObserver : public WebContentsObserver {
269 public:
270 explicit TestWebContentsObserver(WebContents* contents)
271 : WebContentsObserver(contents) {
273 virtual ~TestWebContentsObserver() {}
275 virtual void DidFinishLoad(int64 frame_id,
276 const GURL& validated_url,
277 bool is_main_frame,
278 RenderViewHost* render_view_host) OVERRIDE {
279 last_url_ = validated_url;
281 virtual void DidFailLoad(int64 frame_id,
282 const GURL& validated_url,
283 bool is_main_frame,
284 int error_code,
285 const base::string16& error_description,
286 RenderViewHost* render_view_host) OVERRIDE {
287 last_url_ = validated_url;
290 const GURL& last_url() const { return last_url_; }
292 private:
293 GURL last_url_;
295 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver);
298 // Pretends to be a normal browser that receives toggles and transitions to/from
299 // a fullscreened state.
300 class FakeFullscreenDelegate : public WebContentsDelegate {
301 public:
302 FakeFullscreenDelegate() : fullscreened_contents_(NULL) {}
303 virtual ~FakeFullscreenDelegate() {}
305 virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
306 bool enter_fullscreen) OVERRIDE {
307 fullscreened_contents_ = enter_fullscreen ? web_contents : NULL;
310 virtual bool IsFullscreenForTabOrPending(const WebContents* web_contents)
311 const OVERRIDE {
312 return fullscreened_contents_ && web_contents == fullscreened_contents_;
315 private:
316 WebContents* fullscreened_contents_;
318 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate);
321 } // namespace
323 // Test to make sure that title updates get stripped of whitespace.
324 TEST_F(WebContentsImplTest, UpdateTitle) {
325 NavigationControllerImpl& cont =
326 static_cast<NavigationControllerImpl&>(controller());
327 FrameHostMsg_DidCommitProvisionalLoad_Params params;
328 InitNavigateParams(
329 &params, 0, GURL(url::kAboutBlankURL), PAGE_TRANSITION_TYPED);
331 LoadCommittedDetails details;
332 cont.RendererDidNavigate(main_test_rfh(), params, &details);
334 contents()->UpdateTitle(main_test_rfh(), 0,
335 base::ASCIIToUTF16(" Lots O' Whitespace\n"),
336 base::i18n::LEFT_TO_RIGHT);
337 EXPECT_EQ(base::ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle());
340 TEST_F(WebContentsImplTest, DontUseTitleFromPendingEntry) {
341 const GURL kGURL("chrome://blah");
342 controller().LoadURL(
343 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
344 EXPECT_EQ(base::string16(), contents()->GetTitle());
347 TEST_F(WebContentsImplTest, UseTitleFromPendingEntryIfSet) {
348 const GURL kGURL("chrome://blah");
349 const base::string16 title = base::ASCIIToUTF16("My Title");
350 controller().LoadURL(
351 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
353 NavigationEntry* entry = controller().GetVisibleEntry();
354 ASSERT_EQ(kGURL, entry->GetURL());
355 entry->SetTitle(title);
357 EXPECT_EQ(title, contents()->GetTitle());
360 // Test view source mode for a webui page.
361 TEST_F(WebContentsImplTest, NTPViewSource) {
362 NavigationControllerImpl& cont =
363 static_cast<NavigationControllerImpl&>(controller());
364 const char kUrl[] = "view-source:chrome://blah";
365 const GURL kGURL(kUrl);
367 process()->sink().ClearMessages();
369 cont.LoadURL(
370 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
371 rvh()->GetDelegate()->RenderViewCreated(rvh());
372 // Did we get the expected message?
373 EXPECT_TRUE(process()->sink().GetFirstMessageMatching(
374 ViewMsg_EnableViewSourceMode::ID));
376 FrameHostMsg_DidCommitProvisionalLoad_Params params;
377 InitNavigateParams(&params, 0, kGURL, PAGE_TRANSITION_TYPED);
378 LoadCommittedDetails details;
379 cont.RendererDidNavigate(main_test_rfh(), params, &details);
380 // Also check title and url.
381 EXPECT_EQ(base::ASCIIToUTF16(kUrl), contents()->GetTitle());
384 // Test to ensure UpdateMaxPageID is working properly.
385 TEST_F(WebContentsImplTest, UpdateMaxPageID) {
386 SiteInstance* instance1 = contents()->GetSiteInstance();
387 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL));
389 // Starts at -1.
390 EXPECT_EQ(-1, contents()->GetMaxPageID());
391 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance1));
392 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
394 // Make sure max_page_id_ is monotonically increasing per SiteInstance.
395 contents()->UpdateMaxPageID(3);
396 contents()->UpdateMaxPageID(1);
397 EXPECT_EQ(3, contents()->GetMaxPageID());
398 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
399 EXPECT_EQ(-1, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
401 contents()->UpdateMaxPageIDForSiteInstance(instance2.get(), 7);
402 EXPECT_EQ(3, contents()->GetMaxPageID());
403 EXPECT_EQ(3, contents()->GetMaxPageIDForSiteInstance(instance1));
404 EXPECT_EQ(7, contents()->GetMaxPageIDForSiteInstance(instance2.get()));
407 // Test simple same-SiteInstance navigation.
408 TEST_F(WebContentsImplTest, SimpleNavigation) {
409 TestRenderViewHost* orig_rvh = test_rvh();
410 SiteInstance* instance1 = contents()->GetSiteInstance();
411 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
413 // Navigate to URL
414 const GURL url("http://www.google.com");
415 controller().LoadURL(
416 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
417 EXPECT_FALSE(contents()->cross_navigation_pending());
418 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
419 // Controller's pending entry will have a NULL site instance until we assign
420 // it in DidNavigate.
421 EXPECT_TRUE(
422 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
423 site_instance() == NULL);
425 // DidNavigate from the page
426 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
427 EXPECT_FALSE(contents()->cross_navigation_pending());
428 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
429 EXPECT_EQ(instance1, orig_rvh->GetSiteInstance());
430 // Controller's entry should now have the SiteInstance, or else we won't be
431 // able to find it later.
432 EXPECT_EQ(
433 instance1,
434 NavigationEntryImpl::FromNavigationEntry(controller().GetVisibleEntry())->
435 site_instance());
438 // Test that we reject NavigateToEntry if the url is over kMaxURLChars.
439 TEST_F(WebContentsImplTest, NavigateToExcessivelyLongURL) {
440 // Construct a URL that's kMaxURLChars + 1 long of all 'a's.
441 const GURL url(std::string("http://example.org/").append(
442 GetMaxURLChars() + 1, 'a'));
444 controller().LoadURL(
445 url, Referrer(), PAGE_TRANSITION_GENERATED, std::string());
446 EXPECT_TRUE(controller().GetVisibleEntry() == NULL);
449 // Test that navigating across a site boundary creates a new RenderViewHost
450 // with a new SiteInstance. Going back should do the same.
451 TEST_F(WebContentsImplTest, CrossSiteBoundaries) {
452 contents()->transition_cross_site = true;
453 TestRenderViewHost* orig_rvh = test_rvh();
454 RenderFrameHostImpl* orig_rfh =
455 contents()->GetFrameTree()->root()->current_frame_host();
456 int orig_rvh_delete_count = 0;
457 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
458 SiteInstance* instance1 = contents()->GetSiteInstance();
460 // Navigate to URL. First URL should use first RenderViewHost.
461 const GURL url("http://www.google.com");
462 controller().LoadURL(
463 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
464 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
466 // Keep the number of active views in orig_rvh's SiteInstance
467 // non-zero so that orig_rvh doesn't get deleted when it gets
468 // swapped out.
469 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
470 increment_active_view_count();
472 EXPECT_FALSE(contents()->cross_navigation_pending());
473 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
474 EXPECT_EQ(url, contents()->GetLastCommittedURL());
475 EXPECT_EQ(url, contents()->GetVisibleURL());
477 // Navigate to new site
478 const GURL url2("http://www.yahoo.com");
479 controller().LoadURL(
480 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
481 EXPECT_TRUE(contents()->cross_navigation_pending());
482 EXPECT_EQ(url, contents()->GetLastCommittedURL());
483 EXPECT_EQ(url2, contents()->GetVisibleURL());
484 TestRenderViewHost* pending_rvh =
485 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
486 int pending_rvh_delete_count = 0;
487 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
488 RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()->
489 render_manager()->pending_frame_host();
491 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
492 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
493 orig_rvh->SendBeforeUnloadACK(true);
494 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
496 // DidNavigate from the pending page
497 contents()->TestDidNavigate(
498 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
499 SiteInstance* instance2 = contents()->GetSiteInstance();
501 // Keep the number of active views in pending_rvh's SiteInstance
502 // non-zero so that orig_rvh doesn't get deleted when it gets
503 // swapped out.
504 static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())->
505 increment_active_view_count();
507 EXPECT_FALSE(contents()->cross_navigation_pending());
508 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
509 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
510 EXPECT_EQ(url2, contents()->GetVisibleURL());
511 EXPECT_NE(instance1, instance2);
512 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
513 // We keep the original RFH around, swapped out.
514 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
515 orig_rfh));
516 EXPECT_EQ(orig_rvh_delete_count, 0);
518 // Going back should switch SiteInstances again. The first SiteInstance is
519 // stored in the NavigationEntry, so it should be the same as at the start.
520 // We should use the same RVH as before, swapping it back in.
521 controller().GoBack();
522 TestRenderViewHost* goback_rvh =
523 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
524 EXPECT_EQ(orig_rvh, goback_rvh);
525 EXPECT_TRUE(contents()->cross_navigation_pending());
527 // Navigations should be suspended in goback_rvh until BeforeUnloadACK.
528 EXPECT_TRUE(goback_rvh->are_navigations_suspended());
529 pending_rvh->SendBeforeUnloadACK(true);
530 EXPECT_FALSE(goback_rvh->are_navigations_suspended());
532 // DidNavigate from the back action
533 contents()->TestDidNavigate(
534 goback_rvh, 1, url2, PAGE_TRANSITION_TYPED);
535 EXPECT_FALSE(contents()->cross_navigation_pending());
536 EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost());
537 EXPECT_EQ(instance1, contents()->GetSiteInstance());
538 // The pending RFH should now be swapped out, not deleted.
539 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->
540 IsOnSwappedOutList(pending_rfh));
541 EXPECT_EQ(pending_rvh_delete_count, 0);
542 pending_rvh->OnSwappedOut(false);
544 // Close contents and ensure RVHs are deleted.
545 DeleteContents();
546 EXPECT_EQ(orig_rvh_delete_count, 1);
547 EXPECT_EQ(pending_rvh_delete_count, 1);
550 // Test that navigating across a site boundary after a crash creates a new
551 // RVH without requiring a cross-site transition (i.e., PENDING state).
552 TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) {
553 contents()->transition_cross_site = true;
554 TestRenderViewHost* orig_rvh = test_rvh();
555 int orig_rvh_delete_count = 0;
556 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
557 SiteInstance* instance1 = contents()->GetSiteInstance();
559 // Navigate to URL. First URL should use first RenderViewHost.
560 const GURL url("http://www.google.com");
561 controller().LoadURL(
562 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
563 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
565 EXPECT_FALSE(contents()->cross_navigation_pending());
566 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
568 // Crash the renderer.
569 orig_rvh->set_render_view_created(false);
571 // Navigate to new site. We should not go into PENDING.
572 const GURL url2("http://www.yahoo.com");
573 controller().LoadURL(
574 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
575 RenderViewHost* new_rvh = rvh();
576 EXPECT_FALSE(contents()->cross_navigation_pending());
577 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
578 EXPECT_NE(orig_rvh, new_rvh);
579 EXPECT_EQ(orig_rvh_delete_count, 1);
581 // DidNavigate from the new page
582 contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED);
583 SiteInstance* instance2 = contents()->GetSiteInstance();
585 EXPECT_FALSE(contents()->cross_navigation_pending());
586 EXPECT_EQ(new_rvh, rvh());
587 EXPECT_NE(instance1, instance2);
588 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
590 // Close contents and ensure RVHs are deleted.
591 DeleteContents();
592 EXPECT_EQ(orig_rvh_delete_count, 1);
595 // Test that opening a new contents in the same SiteInstance and then navigating
596 // both contentses to a new site will place both contentses in a single
597 // SiteInstance.
598 TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) {
599 contents()->transition_cross_site = true;
600 TestRenderViewHost* orig_rvh = test_rvh();
601 SiteInstance* instance1 = contents()->GetSiteInstance();
603 // Navigate to URL. First URL should use first RenderViewHost.
604 const GURL url("http://www.google.com");
605 controller().LoadURL(
606 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
607 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
609 // Open a new contents with the same SiteInstance, navigated to the same site.
610 scoped_ptr<TestWebContents> contents2(
611 TestWebContents::Create(browser_context(), instance1));
612 contents2->transition_cross_site = true;
613 contents2->GetController().LoadURL(url, Referrer(),
614 PAGE_TRANSITION_TYPED,
615 std::string());
616 // Need this page id to be 2 since the site instance is the same (which is the
617 // scope of page IDs) and we want to consider this a new page.
618 contents2->TestDidNavigate(
619 contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED);
621 // Navigate first contents to a new site.
622 const GURL url2a("http://www.yahoo.com");
623 controller().LoadURL(
624 url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string());
625 orig_rvh->SendBeforeUnloadACK(true);
626 TestRenderViewHost* pending_rvh_a =
627 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
628 contents()->TestDidNavigate(
629 pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED);
630 SiteInstance* instance2a = contents()->GetSiteInstance();
631 EXPECT_NE(instance1, instance2a);
633 // Navigate second contents to the same site as the first tab.
634 const GURL url2b("http://mail.yahoo.com");
635 contents2->GetController().LoadURL(url2b, Referrer(),
636 PAGE_TRANSITION_TYPED,
637 std::string());
638 TestRenderViewHost* rvh2 =
639 static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost());
640 rvh2->SendBeforeUnloadACK(true);
641 TestRenderViewHost* pending_rvh_b =
642 static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost());
643 EXPECT_TRUE(pending_rvh_b != NULL);
644 EXPECT_TRUE(contents2->cross_navigation_pending());
646 // NOTE(creis): We used to be in danger of showing a crash page here if the
647 // second contents hadn't navigated somewhere first (bug 1145430). That case
648 // is now covered by the CrossSiteBoundariesAfterCrash test.
649 contents2->TestDidNavigate(
650 pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED);
651 SiteInstance* instance2b = contents2->GetSiteInstance();
652 EXPECT_NE(instance1, instance2b);
654 // Both contentses should now be in the same SiteInstance.
655 EXPECT_EQ(instance2a, instance2b);
658 TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) {
659 WebContentsImplTestBrowserClient browser_client;
660 SetBrowserClientForTesting(&browser_client);
662 contents()->transition_cross_site = true;
663 TestRenderViewHost* orig_rvh = test_rvh();
664 RenderFrameHostImpl* orig_rfh =
665 contents()->GetFrameTree()->root()->current_frame_host();
666 int orig_rvh_delete_count = 0;
667 orig_rvh->set_delete_counter(&orig_rvh_delete_count);
668 SiteInstanceImpl* orig_instance =
669 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance());
671 browser_client.set_assign_site_for_url(false);
672 // Navigate to an URL that will not assign a new SiteInstance.
673 const GURL native_url("non-site-url://stuffandthings");
674 controller().LoadURL(
675 native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
676 contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED);
678 EXPECT_FALSE(contents()->cross_navigation_pending());
679 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
680 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
681 EXPECT_EQ(native_url, contents()->GetVisibleURL());
682 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
683 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL());
684 EXPECT_FALSE(orig_instance->HasSite());
686 browser_client.set_assign_site_for_url(true);
687 // Navigate to new site (should keep same site instance).
688 const GURL url("http://www.google.com");
689 controller().LoadURL(
690 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
691 EXPECT_FALSE(contents()->cross_navigation_pending());
692 EXPECT_EQ(native_url, contents()->GetLastCommittedURL());
693 EXPECT_EQ(url, contents()->GetVisibleURL());
694 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
695 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
697 // Keep the number of active views in orig_rvh's SiteInstance
698 // non-zero so that orig_rvh doesn't get deleted when it gets
699 // swapped out.
700 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())->
701 increment_active_view_count();
703 EXPECT_EQ(orig_instance, contents()->GetSiteInstance());
704 EXPECT_TRUE(
705 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com"));
706 EXPECT_EQ(url, contents()->GetLastCommittedURL());
708 // Navigate to another new site (should create a new site instance).
709 const GURL url2("http://www.yahoo.com");
710 controller().LoadURL(
711 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
712 EXPECT_TRUE(contents()->cross_navigation_pending());
713 EXPECT_EQ(url, contents()->GetLastCommittedURL());
714 EXPECT_EQ(url2, contents()->GetVisibleURL());
715 TestRenderViewHost* pending_rvh =
716 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
717 int pending_rvh_delete_count = 0;
718 pending_rvh->set_delete_counter(&pending_rvh_delete_count);
720 // Navigations should be suspended in pending_rvh until BeforeUnloadACK.
721 EXPECT_TRUE(pending_rvh->are_navigations_suspended());
722 orig_rvh->SendBeforeUnloadACK(true);
723 EXPECT_FALSE(pending_rvh->are_navigations_suspended());
725 // DidNavigate from the pending page.
726 contents()->TestDidNavigate(
727 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
728 SiteInstance* new_instance = contents()->GetSiteInstance();
730 EXPECT_FALSE(contents()->cross_navigation_pending());
731 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
732 EXPECT_EQ(url2, contents()->GetLastCommittedURL());
733 EXPECT_EQ(url2, contents()->GetVisibleURL());
734 EXPECT_NE(new_instance, orig_instance);
735 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
736 // We keep the original RFH around, swapped out.
737 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList(
738 orig_rfh));
739 EXPECT_EQ(orig_rvh_delete_count, 0);
740 orig_rvh->OnSwappedOut(false);
742 // Close contents and ensure RVHs are deleted.
743 DeleteContents();
744 EXPECT_EQ(orig_rvh_delete_count, 1);
745 EXPECT_EQ(pending_rvh_delete_count, 1);
748 // Test that we can find an opener RVH even if it's pending.
749 // http://crbug.com/176252.
750 TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) {
751 contents()->transition_cross_site = true;
752 TestRenderViewHost* orig_rvh = test_rvh();
754 // Navigate to a URL.
755 const GURL url("http://www.google.com");
756 controller().LoadURL(
757 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
758 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
760 // Start to navigate first tab to a new site, so that it has a pending RVH.
761 const GURL url2("http://www.yahoo.com");
762 controller().LoadURL(
763 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
764 orig_rvh->SendBeforeUnloadACK(true);
765 TestRenderViewHost* pending_rvh =
766 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
768 // While it is still pending, simulate opening a new tab with the first tab
769 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews
770 // on the opener to ensure that an RVH exists.
771 int opener_routing_id = contents()->CreateOpenerRenderViews(
772 pending_rvh->GetSiteInstance());
774 // We should find the pending RVH and not create a new one.
775 EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id);
778 // Tests that WebContentsImpl uses the current URL, not the SiteInstance's site,
779 // to determine whether a navigation is cross-site.
780 TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) {
781 contents()->transition_cross_site = true;
782 RenderViewHost* orig_rvh = rvh();
783 SiteInstance* instance1 = contents()->GetSiteInstance();
785 // Navigate to URL.
786 const GURL url("http://www.google.com");
787 controller().LoadURL(
788 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
789 contents()->TestDidNavigate(
790 orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
792 // Open a related contents to a second site.
793 scoped_ptr<TestWebContents> contents2(
794 TestWebContents::Create(browser_context(), instance1));
795 contents2->transition_cross_site = true;
796 const GURL url2("http://www.yahoo.com");
797 contents2->GetController().LoadURL(url2, Referrer(),
798 PAGE_TRANSITION_TYPED,
799 std::string());
800 // The first RVH in contents2 isn't live yet, so we shortcut the cross site
801 // pending.
802 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>(
803 contents2->GetRenderViewHost());
804 EXPECT_FALSE(contents2->cross_navigation_pending());
805 contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED);
806 SiteInstance* instance2 = contents2->GetSiteInstance();
807 EXPECT_NE(instance1, instance2);
808 EXPECT_FALSE(contents2->cross_navigation_pending());
810 // Simulate a link click in first contents to second site. Doesn't switch
811 // SiteInstances, because we don't intercept WebKit navigations.
812 contents()->TestDidNavigate(
813 orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
814 SiteInstance* instance3 = contents()->GetSiteInstance();
815 EXPECT_EQ(instance1, instance3);
816 EXPECT_FALSE(contents()->cross_navigation_pending());
818 // Navigate to the new site. Doesn't switch SiteInstancees, because we
819 // compare against the current URL, not the SiteInstance's site.
820 const GURL url3("http://mail.yahoo.com");
821 controller().LoadURL(
822 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
823 EXPECT_FALSE(contents()->cross_navigation_pending());
824 contents()->TestDidNavigate(
825 orig_rvh, 3, url3, PAGE_TRANSITION_TYPED);
826 SiteInstance* instance4 = contents()->GetSiteInstance();
827 EXPECT_EQ(instance1, instance4);
830 // Test that the onbeforeunload and onunload handlers run when navigating
831 // across site boundaries.
832 TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) {
833 contents()->transition_cross_site = true;
834 TestRenderViewHost* orig_rvh = test_rvh();
835 SiteInstance* instance1 = contents()->GetSiteInstance();
837 // Navigate to URL. First URL should use first RenderViewHost.
838 const GURL url("http://www.google.com");
839 controller().LoadURL(
840 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
841 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
842 EXPECT_FALSE(contents()->cross_navigation_pending());
843 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
845 // Navigate to new site, but simulate an onbeforeunload denial.
846 const GURL url2("http://www.yahoo.com");
847 controller().LoadURL(
848 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
849 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
850 base::TimeTicks now = base::TimeTicks::Now();
851 orig_rvh->GetMainFrame()->OnMessageReceived(
852 FrameHostMsg_BeforeUnload_ACK(0, false, now, now));
853 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
854 EXPECT_FALSE(contents()->cross_navigation_pending());
855 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
857 // Navigate again, but simulate an onbeforeunload approval.
858 controller().LoadURL(
859 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
860 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
861 now = base::TimeTicks::Now();
862 orig_rvh->GetMainFrame()->OnMessageReceived(
863 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
864 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
865 EXPECT_TRUE(contents()->cross_navigation_pending());
866 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
867 contents()->GetPendingRenderViewHost());
869 // We won't hear DidNavigate until the onunload handler has finished running.
871 // DidNavigate from the pending page.
872 contents()->TestDidNavigate(
873 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
874 SiteInstance* instance2 = contents()->GetSiteInstance();
875 EXPECT_FALSE(contents()->cross_navigation_pending());
876 EXPECT_EQ(pending_rvh, rvh());
877 EXPECT_NE(instance1, instance2);
878 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
881 // Test that during a slow cross-site navigation, the original renderer can
882 // navigate to a different URL and have it displayed, canceling the slow
883 // navigation.
884 TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) {
885 contents()->transition_cross_site = true;
886 TestRenderViewHost* orig_rvh = test_rvh();
887 SiteInstance* instance1 = contents()->GetSiteInstance();
889 // Navigate to URL. First URL should use first RenderViewHost.
890 const GURL url("http://www.google.com");
891 controller().LoadURL(
892 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
893 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
894 EXPECT_FALSE(contents()->cross_navigation_pending());
895 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
897 // Navigate to new site, simulating an onbeforeunload approval.
898 const GURL url2("http://www.yahoo.com");
899 controller().LoadURL(
900 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
901 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
902 base::TimeTicks now = base::TimeTicks::Now();
903 orig_rvh->GetMainFrame()->OnMessageReceived(
904 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
905 EXPECT_TRUE(contents()->cross_navigation_pending());
907 // Suppose the original renderer navigates before the new one is ready.
908 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
910 // Verify that the pending navigation is cancelled.
911 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
912 SiteInstance* instance2 = contents()->GetSiteInstance();
913 EXPECT_FALSE(contents()->cross_navigation_pending());
914 EXPECT_EQ(orig_rvh, rvh());
915 EXPECT_EQ(instance1, instance2);
916 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
919 TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) {
920 contents()->transition_cross_site = true;
922 // Start with a web ui page, which gets a new RVH with WebUI bindings.
923 const GURL url1("chrome://blah");
924 controller().LoadURL(
925 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string());
926 TestRenderViewHost* ntp_rvh = test_rvh();
927 contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED);
928 NavigationEntry* entry1 = controller().GetLastCommittedEntry();
929 SiteInstance* instance1 = contents()->GetSiteInstance();
931 EXPECT_FALSE(contents()->cross_navigation_pending());
932 EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost());
933 EXPECT_EQ(url1, entry1->GetURL());
934 EXPECT_EQ(instance1,
935 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
936 EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
938 // Navigate to new site.
939 const GURL url2("http://www.google.com");
940 controller().LoadURL(
941 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
942 EXPECT_TRUE(contents()->cross_navigation_pending());
943 TestRenderViewHost* google_rvh =
944 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
946 // Simulate beforeunload approval.
947 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack());
948 base::TimeTicks now = base::TimeTicks::Now();
949 ntp_rvh->GetMainFrame()->OnMessageReceived(
950 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
952 // DidNavigate from the pending page.
953 contents()->TestDidNavigate(
954 google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
955 NavigationEntry* entry2 = controller().GetLastCommittedEntry();
956 SiteInstance* instance2 = contents()->GetSiteInstance();
958 EXPECT_FALSE(contents()->cross_navigation_pending());
959 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
960 EXPECT_NE(instance1, instance2);
961 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
962 EXPECT_EQ(url2, entry2->GetURL());
963 EXPECT_EQ(instance2,
964 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
965 EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI);
967 // Navigate to third page on same site.
968 const GURL url3("http://news.google.com");
969 controller().LoadURL(
970 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string());
971 EXPECT_FALSE(contents()->cross_navigation_pending());
972 contents()->TestDidNavigate(
973 google_rvh, 2, url3, PAGE_TRANSITION_TYPED);
974 NavigationEntry* entry3 = controller().GetLastCommittedEntry();
975 SiteInstance* instance3 = contents()->GetSiteInstance();
977 EXPECT_FALSE(contents()->cross_navigation_pending());
978 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
979 EXPECT_EQ(instance2, instance3);
980 EXPECT_FALSE(contents()->GetPendingRenderViewHost());
981 EXPECT_EQ(url3, entry3->GetURL());
982 EXPECT_EQ(instance3,
983 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
985 // Go back within the site.
986 controller().GoBack();
987 EXPECT_FALSE(contents()->cross_navigation_pending());
988 EXPECT_EQ(entry2, controller().GetPendingEntry());
990 // Before that commits, go back again.
991 controller().GoBack();
992 EXPECT_TRUE(contents()->cross_navigation_pending());
993 EXPECT_TRUE(contents()->GetPendingRenderViewHost());
994 EXPECT_EQ(entry1, controller().GetPendingEntry());
996 // Simulate beforeunload approval.
997 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack());
998 now = base::TimeTicks::Now();
999 google_rvh->GetMainFrame()->OnMessageReceived(
1000 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1002 // DidNavigate from the first back. This aborts the second back's pending RVH.
1003 contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1005 // We should commit this page and forget about the second back.
1006 EXPECT_FALSE(contents()->cross_navigation_pending());
1007 EXPECT_FALSE(controller().GetPendingEntry());
1008 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost());
1009 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL());
1011 // We should not have corrupted the NTP entry.
1012 EXPECT_EQ(instance3,
1013 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance());
1014 EXPECT_EQ(instance2,
1015 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance());
1016 EXPECT_EQ(instance1,
1017 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance());
1018 EXPECT_EQ(url1, entry1->GetURL());
1021 // Test that during a slow cross-site navigation, a sub-frame navigation in the
1022 // original renderer will not cancel the slow navigation (bug 42029).
1023 TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) {
1024 contents()->transition_cross_site = true;
1025 TestRenderViewHost* orig_rvh = test_rvh();
1027 // Navigate to URL. First URL should use first RenderViewHost.
1028 const GURL url("http://www.google.com");
1029 controller().LoadURL(
1030 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1031 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1032 EXPECT_FALSE(contents()->cross_navigation_pending());
1033 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1035 // Start navigating to new site.
1036 const GURL url2("http://www.yahoo.com");
1037 controller().LoadURL(
1038 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1040 // Simulate a sub-frame navigation arriving and ensure the RVH is still
1041 // waiting for a before unload response.
1042 orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"),
1043 PAGE_TRANSITION_AUTO_SUBFRAME);
1044 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1046 // Now simulate the onbeforeunload approval and verify the navigation is
1047 // not canceled.
1048 base::TimeTicks now = base::TimeTicks::Now();
1049 orig_rvh->GetMainFrame()->OnMessageReceived(
1050 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1051 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1052 EXPECT_TRUE(contents()->cross_navigation_pending());
1055 // Test that a cross-site navigation is not preempted if the previous
1056 // renderer sends a FrameNavigate message just before being told to stop.
1057 // We should only preempt the cross-site navigation if the previous renderer
1058 // has started a new navigation. See http://crbug.com/79176.
1059 TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) {
1060 contents()->transition_cross_site = true;
1062 // Navigate to NTP URL.
1063 const GURL url("chrome://blah");
1064 controller().LoadURL(
1065 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1066 TestRenderViewHost* orig_rvh = test_rvh();
1067 EXPECT_FALSE(contents()->cross_navigation_pending());
1069 // Navigate to new site, with the beforeunload request in flight.
1070 const GURL url2("http://www.yahoo.com");
1071 controller().LoadURL(
1072 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1073 TestRenderViewHost* pending_rvh =
1074 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost());
1075 EXPECT_TRUE(contents()->cross_navigation_pending());
1076 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1078 // Suppose the first navigation tries to commit now, with a
1079 // ViewMsg_Stop in flight. This should not cancel the pending navigation,
1080 // but it should act as if the beforeunload ack arrived.
1081 orig_rvh->SendNavigate(1, GURL("chrome://blah"));
1082 EXPECT_TRUE(contents()->cross_navigation_pending());
1083 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1084 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1086 // The pending navigation should be able to commit successfully.
1087 contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1088 EXPECT_FALSE(contents()->cross_navigation_pending());
1089 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost());
1092 // Test that the original renderer cannot preempt a cross-site navigation once
1093 // the unload request has been made. At this point, the cross-site navigation
1094 // is almost ready to be displayed, and the original renderer is only given a
1095 // short chance to run an unload handler. Prevents regression of bug 23942.
1096 TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) {
1097 contents()->transition_cross_site = true;
1098 TestRenderViewHost* orig_rvh = test_rvh();
1099 SiteInstance* instance1 = contents()->GetSiteInstance();
1101 // Navigate to URL. First URL should use first RenderViewHost.
1102 const GURL url("http://www.google.com");
1103 controller().LoadURL(
1104 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1105 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1106 EXPECT_FALSE(contents()->cross_navigation_pending());
1107 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1109 // Navigate to new site, simulating an onbeforeunload approval.
1110 const GURL url2("http://www.yahoo.com");
1111 controller().LoadURL(
1112 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1113 base::TimeTicks now = base::TimeTicks::Now();
1114 orig_rvh->GetMainFrame()->OnMessageReceived(
1115 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1116 EXPECT_TRUE(contents()->cross_navigation_pending());
1117 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>(
1118 contents()->GetPendingRenderViewHost());
1120 // Simulate the pending renderer's response, which leads to an unload request
1121 // being sent to orig_rvh.
1122 std::vector<GURL> url_chain;
1123 url_chain.push_back(GURL());
1124 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse(
1125 contents()->GetRenderManagerForTesting()->pending_frame_host(),
1126 GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(),
1127 url_chain, Referrer(), PAGE_TRANSITION_TYPED, false);
1129 // Suppose the original renderer navigates now, while the unload request is in
1130 // flight. We should ignore it, wait for the unload ack, and let the pending
1131 // request continue. Otherwise, the contents may close spontaneously or stop
1132 // responding to navigation requests. (See bug 23942.)
1133 FrameHostMsg_DidCommitProvisionalLoad_Params params1a;
1134 InitNavigateParams(&params1a, 2, GURL("http://www.google.com/foo"),
1135 PAGE_TRANSITION_TYPED);
1136 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo"));
1138 // Verify that the pending navigation is still in progress.
1139 EXPECT_TRUE(contents()->cross_navigation_pending());
1140 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL);
1142 // DidNavigate from the pending page should commit it.
1143 contents()->TestDidNavigate(
1144 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1145 SiteInstance* instance2 = contents()->GetSiteInstance();
1146 EXPECT_FALSE(contents()->cross_navigation_pending());
1147 EXPECT_EQ(pending_rvh, rvh());
1148 EXPECT_NE(instance1, instance2);
1149 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1152 // Test that a cross-site navigation that doesn't commit after the unload
1153 // handler doesn't leave the contents in a stuck state. http://crbug.com/88562
1154 TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) {
1155 contents()->transition_cross_site = true;
1156 TestRenderViewHost* orig_rvh = test_rvh();
1157 SiteInstance* instance1 = contents()->GetSiteInstance();
1159 // Navigate to URL. First URL should use first RenderViewHost.
1160 const GURL url("http://www.google.com");
1161 controller().LoadURL(
1162 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1163 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1164 EXPECT_FALSE(contents()->cross_navigation_pending());
1165 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1167 // Navigate to new site, simulating an onbeforeunload approval.
1168 const GURL url2("http://www.yahoo.com");
1169 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1170 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack());
1171 base::TimeTicks now = base::TimeTicks::Now();
1172 orig_rvh->GetMainFrame()->OnMessageReceived(
1173 FrameHostMsg_BeforeUnload_ACK(0, true, now, now));
1174 EXPECT_TRUE(contents()->cross_navigation_pending());
1176 // Simulate swap out message when the response arrives.
1177 orig_rvh->OnSwappedOut(false);
1179 // Suppose the navigation doesn't get a chance to commit, and the user
1180 // navigates in the current RVH's SiteInstance.
1181 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1183 // Verify that the pending navigation is cancelled and the renderer is no
1184 // longer swapped out.
1185 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack());
1186 SiteInstance* instance2 = contents()->GetSiteInstance();
1187 EXPECT_FALSE(contents()->cross_navigation_pending());
1188 EXPECT_EQ(orig_rvh, rvh());
1189 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, orig_rvh->rvh_state());
1190 EXPECT_EQ(instance1, instance2);
1191 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL);
1194 // Test that NavigationEntries have the correct page state after going
1195 // forward and back. Prevents regression for bug 1116137.
1196 TEST_F(WebContentsImplTest, NavigationEntryContentState) {
1197 TestRenderViewHost* orig_rvh = test_rvh();
1199 // Navigate to URL. There should be no committed entry yet.
1200 const GURL url("http://www.google.com");
1201 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1202 NavigationEntry* entry = controller().GetLastCommittedEntry();
1203 EXPECT_TRUE(entry == NULL);
1205 // Committed entry should have page state after DidNavigate.
1206 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1207 entry = controller().GetLastCommittedEntry();
1208 EXPECT_TRUE(entry->GetPageState().IsValid());
1210 // Navigate to same site.
1211 const GURL url2("http://images.google.com");
1212 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1213 entry = controller().GetLastCommittedEntry();
1214 EXPECT_TRUE(entry->GetPageState().IsValid());
1216 // Committed entry should have page state after DidNavigate.
1217 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1218 entry = controller().GetLastCommittedEntry();
1219 EXPECT_TRUE(entry->GetPageState().IsValid());
1221 // Now go back. Committed entry should still have page state.
1222 controller().GoBack();
1223 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1224 entry = controller().GetLastCommittedEntry();
1225 EXPECT_TRUE(entry->GetPageState().IsValid());
1228 // Test that NavigationEntries have the correct page state and SiteInstance
1229 // state after opening a new window to about:blank. Prevents regression for
1230 // bugs b/1116137 and http://crbug.com/111975.
1231 TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) {
1232 TestRenderViewHost* orig_rvh = test_rvh();
1234 // When opening a new window, it is navigated to about:blank internally.
1235 // Currently, this results in two DidNavigate events.
1236 const GURL url(url::kAboutBlankURL);
1237 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1238 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1240 // Should have a page state here.
1241 NavigationEntry* entry = controller().GetLastCommittedEntry();
1242 EXPECT_TRUE(entry->GetPageState().IsValid());
1244 // The SiteInstance should be available for other navigations to use.
1245 NavigationEntryImpl* entry_impl =
1246 NavigationEntryImpl::FromNavigationEntry(entry);
1247 EXPECT_FALSE(entry_impl->site_instance()->HasSite());
1248 int32 site_instance_id = entry_impl->site_instance()->GetId();
1250 // Navigating to a normal page should not cause a process swap.
1251 const GURL new_url("http://www.google.com");
1252 controller().LoadURL(new_url, Referrer(),
1253 PAGE_TRANSITION_TYPED, std::string());
1254 EXPECT_FALSE(contents()->cross_navigation_pending());
1255 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1256 contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED);
1257 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry(
1258 controller().GetLastCommittedEntry());
1259 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId());
1260 EXPECT_TRUE(entry_impl2->site_instance()->HasSite());
1263 // Tests that fullscreen is exited throughout the object hierarchy when
1264 // navigating to a new page.
1265 TEST_F(WebContentsImplTest, NavigationExitsFullscreen) {
1266 FakeFullscreenDelegate fake_delegate;
1267 contents()->SetDelegate(&fake_delegate);
1268 TestRenderViewHost* orig_rvh = test_rvh();
1270 // Navigate to a site.
1271 const GURL url("http://www.google.com");
1272 controller().LoadURL(
1273 url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1274 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1275 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1277 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1278 EXPECT_FALSE(orig_rvh->IsFullscreen());
1279 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1280 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1281 orig_rvh->OnMessageReceived(
1282 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1283 EXPECT_TRUE(orig_rvh->IsFullscreen());
1284 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1285 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1287 // Navigate to a new site.
1288 const GURL url2("http://www.yahoo.com");
1289 controller().LoadURL(
1290 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1291 RenderViewHost* const pending_rvh = contents()->GetPendingRenderViewHost();
1292 contents()->TestDidNavigate(
1293 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED);
1295 // Confirm fullscreen has exited.
1296 EXPECT_FALSE(orig_rvh->IsFullscreen());
1297 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1298 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1300 contents()->SetDelegate(NULL);
1303 // Tests that fullscreen is exited throughout the object hierarchy when
1304 // instructing NavigationController to GoBack() or GoForward().
1305 TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) {
1306 FakeFullscreenDelegate fake_delegate;
1307 contents()->SetDelegate(&fake_delegate);
1308 TestRenderViewHost* const orig_rvh = test_rvh();
1310 // Navigate to a site.
1311 const GURL url("http://www.google.com");
1312 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1313 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED);
1314 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1316 // Now, navigate to another page on the same site.
1317 const GURL url2("http://www.google.com/search?q=kittens");
1318 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string());
1319 EXPECT_FALSE(contents()->cross_navigation_pending());
1320 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED);
1321 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1323 // Sanity-check: Confirm we're not starting out in fullscreen mode.
1324 EXPECT_FALSE(orig_rvh->IsFullscreen());
1325 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1326 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1328 for (int i = 0; i < 2; ++i) {
1329 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1330 orig_rvh->OnMessageReceived(
1331 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true));
1332 EXPECT_TRUE(orig_rvh->IsFullscreen());
1333 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1334 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1336 // Navigate backward (or forward).
1337 if (i == 0)
1338 controller().GoBack();
1339 else
1340 controller().GoForward();
1341 EXPECT_FALSE(contents()->cross_navigation_pending());
1342 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost());
1343 contents()->TestDidNavigate(
1344 orig_rvh, i + 1, url, PAGE_TRANSITION_FORWARD_BACK);
1346 // Confirm fullscreen has exited.
1347 EXPECT_FALSE(orig_rvh->IsFullscreen());
1348 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1349 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1352 contents()->SetDelegate(NULL);
1355 // Tests that fullscreen is exited throughout the object hierarchy on a renderer
1356 // crash.
1357 TEST_F(WebContentsImplTest, CrashExitsFullscreen) {
1358 FakeFullscreenDelegate fake_delegate;
1359 contents()->SetDelegate(&fake_delegate);
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(test_rvh(), 1, url, PAGE_TRANSITION_TYPED);
1366 EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost());
1368 // Toggle fullscreen mode on (as if initiated via IPC from renderer).
1369 EXPECT_FALSE(test_rvh()->IsFullscreen());
1370 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1371 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1372 test_rvh()->OnMessageReceived(
1373 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true));
1374 EXPECT_TRUE(test_rvh()->IsFullscreen());
1375 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab());
1376 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1378 // Crash the renderer.
1379 test_rvh()->OnMessageReceived(
1380 ViewHostMsg_RenderProcessGone(
1381 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1383 // Confirm fullscreen has exited.
1384 EXPECT_FALSE(test_rvh()->IsFullscreen());
1385 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab());
1386 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents()));
1388 contents()->SetDelegate(NULL);
1391 ////////////////////////////////////////////////////////////////////////////////
1392 // Interstitial Tests
1393 ////////////////////////////////////////////////////////////////////////////////
1395 // Test navigating to a page (with the navigation initiated from the browser,
1396 // as when a URL is typed in the location bar) that shows an interstitial and
1397 // creates a new navigation entry, then hiding it without proceeding.
1398 TEST_F(WebContentsImplTest,
1399 ShowInterstitialFromBrowserWithNewNavigationDontProceed) {
1400 // Navigate to a page.
1401 GURL url1("http://www.google.com");
1402 test_rvh()->SendNavigate(1, url1);
1403 EXPECT_EQ(1, controller().GetEntryCount());
1405 // Initiate a browser navigation that will trigger the interstitial
1406 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1407 PAGE_TRANSITION_TYPED, std::string());
1409 // Show an interstitial.
1410 TestInterstitialPage::InterstitialState state =
1411 TestInterstitialPage::INVALID;
1412 bool deleted = false;
1413 GURL url2("http://interstitial");
1414 TestInterstitialPage* interstitial =
1415 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1416 TestInterstitialPageStateGuard state_guard(interstitial);
1417 interstitial->Show();
1418 // The interstitial should not show until its navigation has committed.
1419 EXPECT_FALSE(interstitial->is_showing());
1420 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1421 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1422 // Let's commit the interstitial navigation.
1423 interstitial->TestDidNavigate(1, url2);
1424 EXPECT_TRUE(interstitial->is_showing());
1425 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1426 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1427 NavigationEntry* entry = controller().GetVisibleEntry();
1428 ASSERT_TRUE(entry != NULL);
1429 EXPECT_TRUE(entry->GetURL() == url2);
1431 // Now don't proceed.
1432 interstitial->DontProceed();
1433 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1434 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1435 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1436 entry = controller().GetVisibleEntry();
1437 ASSERT_TRUE(entry != NULL);
1438 EXPECT_TRUE(entry->GetURL() == url1);
1439 EXPECT_EQ(1, controller().GetEntryCount());
1441 RunAllPendingInMessageLoop();
1442 EXPECT_TRUE(deleted);
1445 // Test navigating to a page (with the navigation initiated from the renderer,
1446 // as when clicking on a link in the page) that shows an interstitial and
1447 // creates a new navigation entry, then hiding it without proceeding.
1448 TEST_F(WebContentsImplTest,
1449 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) {
1450 // Navigate to a page.
1451 GURL url1("http://www.google.com");
1452 test_rvh()->SendNavigate(1, url1);
1453 EXPECT_EQ(1, controller().GetEntryCount());
1455 // Show an interstitial (no pending entry, the interstitial would have been
1456 // triggered by clicking on a link).
1457 TestInterstitialPage::InterstitialState state =
1458 TestInterstitialPage::INVALID;
1459 bool deleted = false;
1460 GURL url2("http://interstitial");
1461 TestInterstitialPage* interstitial =
1462 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1463 TestInterstitialPageStateGuard state_guard(interstitial);
1464 interstitial->Show();
1465 // The interstitial should not show until its navigation has committed.
1466 EXPECT_FALSE(interstitial->is_showing());
1467 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1468 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1469 // Let's commit the interstitial navigation.
1470 interstitial->TestDidNavigate(1, url2);
1471 EXPECT_TRUE(interstitial->is_showing());
1472 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1473 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1474 NavigationEntry* entry = controller().GetVisibleEntry();
1475 ASSERT_TRUE(entry != NULL);
1476 EXPECT_TRUE(entry->GetURL() == url2);
1478 // Now don't proceed.
1479 interstitial->DontProceed();
1480 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1481 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1482 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1483 entry = controller().GetVisibleEntry();
1484 ASSERT_TRUE(entry != NULL);
1485 EXPECT_TRUE(entry->GetURL() == url1);
1486 EXPECT_EQ(1, controller().GetEntryCount());
1488 RunAllPendingInMessageLoop();
1489 EXPECT_TRUE(deleted);
1492 // Test navigating to a page that shows an interstitial without creating a new
1493 // navigation entry (this happens when the interstitial is triggered by a
1494 // sub-resource in the page), then hiding it without proceeding.
1495 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) {
1496 // Navigate to a page.
1497 GURL url1("http://www.google.com");
1498 test_rvh()->SendNavigate(1, url1);
1499 EXPECT_EQ(1, controller().GetEntryCount());
1501 // Show an interstitial.
1502 TestInterstitialPage::InterstitialState state =
1503 TestInterstitialPage::INVALID;
1504 bool deleted = false;
1505 GURL url2("http://interstitial");
1506 TestInterstitialPage* interstitial =
1507 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1508 TestInterstitialPageStateGuard state_guard(interstitial);
1509 interstitial->Show();
1510 // The interstitial should not show until its navigation has committed.
1511 EXPECT_FALSE(interstitial->is_showing());
1512 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1513 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1514 // Let's commit the interstitial navigation.
1515 interstitial->TestDidNavigate(1, url2);
1516 EXPECT_TRUE(interstitial->is_showing());
1517 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1518 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1519 NavigationEntry* entry = controller().GetVisibleEntry();
1520 ASSERT_TRUE(entry != NULL);
1521 // The URL specified to the interstitial should have been ignored.
1522 EXPECT_TRUE(entry->GetURL() == url1);
1524 // Now don't proceed.
1525 interstitial->DontProceed();
1526 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1527 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1528 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1529 entry = controller().GetVisibleEntry();
1530 ASSERT_TRUE(entry != NULL);
1531 EXPECT_TRUE(entry->GetURL() == url1);
1532 EXPECT_EQ(1, controller().GetEntryCount());
1534 RunAllPendingInMessageLoop();
1535 EXPECT_TRUE(deleted);
1538 // Test navigating to a page (with the navigation initiated from the browser,
1539 // as when a URL is typed in the location bar) that shows an interstitial and
1540 // creates a new navigation entry, then proceeding.
1541 TEST_F(WebContentsImplTest,
1542 ShowInterstitialFromBrowserNewNavigationProceed) {
1543 // Navigate to a page.
1544 GURL url1("http://www.google.com");
1545 test_rvh()->SendNavigate(1, url1);
1546 EXPECT_EQ(1, controller().GetEntryCount());
1548 // Initiate a browser navigation that will trigger the interstitial
1549 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
1550 PAGE_TRANSITION_TYPED, std::string());
1552 // Show an interstitial.
1553 TestInterstitialPage::InterstitialState state =
1554 TestInterstitialPage::INVALID;
1555 bool deleted = false;
1556 GURL url2("http://interstitial");
1557 TestInterstitialPage* interstitial =
1558 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1559 TestInterstitialPageStateGuard state_guard(interstitial);
1560 interstitial->Show();
1561 // The interstitial should not show until its navigation has committed.
1562 EXPECT_FALSE(interstitial->is_showing());
1563 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1564 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1565 // Let's commit the interstitial navigation.
1566 interstitial->TestDidNavigate(1, url2);
1567 EXPECT_TRUE(interstitial->is_showing());
1568 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1569 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1570 NavigationEntry* entry = controller().GetVisibleEntry();
1571 ASSERT_TRUE(entry != NULL);
1572 EXPECT_TRUE(entry->GetURL() == url2);
1574 // Then proceed.
1575 interstitial->Proceed();
1576 // The interstitial should show until the new navigation commits.
1577 RunAllPendingInMessageLoop();
1578 ASSERT_FALSE(deleted);
1579 EXPECT_EQ(TestInterstitialPage::OKED, state);
1580 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1581 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1583 // Simulate the navigation to the page, that's when the interstitial gets
1584 // hidden.
1585 GURL url3("http://www.thepage.com");
1586 test_rvh()->SendNavigate(2, url3);
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() == url3);
1594 EXPECT_EQ(2, controller().GetEntryCount());
1596 RunAllPendingInMessageLoop();
1597 EXPECT_TRUE(deleted);
1600 // Test navigating to a page (with the navigation initiated from the renderer,
1601 // as when clicking on a link in the page) that shows an interstitial and
1602 // creates a new navigation entry, then proceeding.
1603 TEST_F(WebContentsImplTest,
1604 ShowInterstitialFromRendererNewNavigationProceed) {
1605 // Navigate to a page.
1606 GURL url1("http://www.google.com");
1607 test_rvh()->SendNavigate(1, url1);
1608 EXPECT_EQ(1, controller().GetEntryCount());
1610 // Show an interstitial.
1611 TestInterstitialPage::InterstitialState state =
1612 TestInterstitialPage::INVALID;
1613 bool deleted = false;
1614 GURL url2("http://interstitial");
1615 TestInterstitialPage* interstitial =
1616 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1617 TestInterstitialPageStateGuard state_guard(interstitial);
1618 interstitial->Show();
1619 // The interstitial should not show until its navigation has committed.
1620 EXPECT_FALSE(interstitial->is_showing());
1621 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1622 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1623 // Let's commit the interstitial navigation.
1624 interstitial->TestDidNavigate(1, url2);
1625 EXPECT_TRUE(interstitial->is_showing());
1626 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1627 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1628 NavigationEntry* entry = controller().GetVisibleEntry();
1629 ASSERT_TRUE(entry != NULL);
1630 EXPECT_TRUE(entry->GetURL() == url2);
1632 // Then proceed.
1633 interstitial->Proceed();
1634 // The interstitial should show until the new navigation commits.
1635 RunAllPendingInMessageLoop();
1636 ASSERT_FALSE(deleted);
1637 EXPECT_EQ(TestInterstitialPage::OKED, state);
1638 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1639 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1641 // Simulate the navigation to the page, that's when the interstitial gets
1642 // hidden.
1643 GURL url3("http://www.thepage.com");
1644 test_rvh()->SendNavigate(2, url3);
1646 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1647 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1648 entry = controller().GetVisibleEntry();
1649 ASSERT_TRUE(entry != NULL);
1650 EXPECT_TRUE(entry->GetURL() == url3);
1652 EXPECT_EQ(2, controller().GetEntryCount());
1654 RunAllPendingInMessageLoop();
1655 EXPECT_TRUE(deleted);
1658 // Test navigating to a page that shows an interstitial without creating a new
1659 // navigation entry (this happens when the interstitial is triggered by a
1660 // sub-resource in the page), then proceeding.
1661 TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) {
1662 // Navigate to a page so we have a navigation entry in the controller.
1663 GURL url1("http://www.google.com");
1664 test_rvh()->SendNavigate(1, url1);
1665 EXPECT_EQ(1, controller().GetEntryCount());
1667 // Show an interstitial.
1668 TestInterstitialPage::InterstitialState state =
1669 TestInterstitialPage::INVALID;
1670 bool deleted = false;
1671 GURL url2("http://interstitial");
1672 TestInterstitialPage* interstitial =
1673 new TestInterstitialPage(contents(), false, url2, &state, &deleted);
1674 TestInterstitialPageStateGuard state_guard(interstitial);
1675 interstitial->Show();
1676 // The interstitial should not show until its navigation has committed.
1677 EXPECT_FALSE(interstitial->is_showing());
1678 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1679 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1680 // Let's commit the interstitial navigation.
1681 interstitial->TestDidNavigate(1, url2);
1682 EXPECT_TRUE(interstitial->is_showing());
1683 EXPECT_TRUE(contents()->ShowingInterstitialPage());
1684 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial);
1685 NavigationEntry* entry = controller().GetVisibleEntry();
1686 ASSERT_TRUE(entry != NULL);
1687 // The URL specified to the interstitial should have been ignored.
1688 EXPECT_TRUE(entry->GetURL() == url1);
1690 // Then proceed.
1691 interstitial->Proceed();
1692 // Since this is not a new navigation, the previous page is dismissed right
1693 // away and shows the original page.
1694 EXPECT_EQ(TestInterstitialPage::OKED, state);
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() == url1);
1701 EXPECT_EQ(1, controller().GetEntryCount());
1703 RunAllPendingInMessageLoop();
1704 EXPECT_TRUE(deleted);
1707 // Test navigating to a page that shows an interstitial, then navigating away.
1708 TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) {
1709 // Show interstitial.
1710 TestInterstitialPage::InterstitialState state =
1711 TestInterstitialPage::INVALID;
1712 bool deleted = false;
1713 GURL url("http://interstitial");
1714 TestInterstitialPage* interstitial =
1715 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1716 TestInterstitialPageStateGuard state_guard(interstitial);
1717 interstitial->Show();
1718 interstitial->TestDidNavigate(1, url);
1720 // While interstitial showing, navigate to a new URL.
1721 const GURL url2("http://www.yahoo.com");
1722 test_rvh()->SendNavigate(1, url2);
1724 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1726 RunAllPendingInMessageLoop();
1727 EXPECT_TRUE(deleted);
1730 // Test navigating to a page that shows an interstitial, then going back.
1731 TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) {
1732 // Navigate to a page so we have a navigation entry in the controller.
1733 GURL url1("http://www.google.com");
1734 test_rvh()->SendNavigate(1, url1);
1735 EXPECT_EQ(1, controller().GetEntryCount());
1737 // Show interstitial.
1738 TestInterstitialPage::InterstitialState state =
1739 TestInterstitialPage::INVALID;
1740 bool deleted = false;
1741 GURL interstitial_url("http://interstitial");
1742 TestInterstitialPage* interstitial =
1743 new TestInterstitialPage(contents(), true, interstitial_url,
1744 &state, &deleted);
1745 TestInterstitialPageStateGuard state_guard(interstitial);
1746 interstitial->Show();
1747 interstitial->TestDidNavigate(2, interstitial_url);
1749 // While the interstitial is showing, go back.
1750 controller().GoBack();
1751 test_rvh()->SendNavigate(1, url1);
1753 // Make sure we are back to the original page and that the interstitial is
1754 // gone.
1755 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1756 NavigationEntry* entry = controller().GetVisibleEntry();
1757 ASSERT_TRUE(entry);
1758 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1760 RunAllPendingInMessageLoop();
1761 EXPECT_TRUE(deleted);
1764 // Test navigating to a page that shows an interstitial, has a renderer crash,
1765 // and then goes back.
1766 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) {
1767 // Navigate to a page so we have a navigation entry in the controller.
1768 GURL url1("http://www.google.com");
1769 test_rvh()->SendNavigate(1, url1);
1770 EXPECT_EQ(1, controller().GetEntryCount());
1772 // Show interstitial.
1773 TestInterstitialPage::InterstitialState state =
1774 TestInterstitialPage::INVALID;
1775 bool deleted = false;
1776 GURL interstitial_url("http://interstitial");
1777 TestInterstitialPage* interstitial =
1778 new TestInterstitialPage(contents(), true, interstitial_url,
1779 &state, &deleted);
1780 TestInterstitialPageStateGuard state_guard(interstitial);
1781 interstitial->Show();
1782 interstitial->TestDidNavigate(2, interstitial_url);
1784 // Crash the renderer
1785 test_rvh()->OnMessageReceived(
1786 ViewHostMsg_RenderProcessGone(
1787 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1789 // While the interstitial is showing, go back.
1790 controller().GoBack();
1791 test_rvh()->SendNavigate(1, url1);
1793 // Make sure we are back to the original page and that the interstitial is
1794 // gone.
1795 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1796 NavigationEntry* entry = controller().GetVisibleEntry();
1797 ASSERT_TRUE(entry);
1798 EXPECT_EQ(url1.spec(), entry->GetURL().spec());
1800 RunAllPendingInMessageLoop();
1801 EXPECT_TRUE(deleted);
1804 // Test navigating to a page that shows an interstitial, has the renderer crash,
1805 // and then navigates to the interstitial.
1806 TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) {
1807 // Navigate to a page so we have a navigation entry in the controller.
1808 GURL url1("http://www.google.com");
1809 test_rvh()->SendNavigate(1, url1);
1810 EXPECT_EQ(1, controller().GetEntryCount());
1812 // Show interstitial.
1813 TestInterstitialPage::InterstitialState state =
1814 TestInterstitialPage::INVALID;
1815 bool deleted = false;
1816 GURL interstitial_url("http://interstitial");
1817 TestInterstitialPage* interstitial =
1818 new TestInterstitialPage(contents(), true, interstitial_url,
1819 &state, &deleted);
1820 TestInterstitialPageStateGuard state_guard(interstitial);
1821 interstitial->Show();
1823 // Crash the renderer
1824 test_rvh()->OnMessageReceived(
1825 ViewHostMsg_RenderProcessGone(
1826 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1));
1828 interstitial->TestDidNavigate(2, interstitial_url);
1831 // Test navigating to a page that shows an interstitial, then close the
1832 // contents.
1833 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) {
1834 // Show interstitial.
1835 TestInterstitialPage::InterstitialState state =
1836 TestInterstitialPage::INVALID;
1837 bool deleted = false;
1838 GURL url("http://interstitial");
1839 TestInterstitialPage* interstitial =
1840 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1841 TestInterstitialPageStateGuard state_guard(interstitial);
1842 interstitial->Show();
1843 interstitial->TestDidNavigate(1, url);
1845 // Now close the contents.
1846 DeleteContents();
1847 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1849 RunAllPendingInMessageLoop();
1850 EXPECT_TRUE(deleted);
1853 // Test navigating to a page that shows an interstitial, then close the
1854 // contents.
1855 TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) {
1856 // Show interstitial.
1857 TestInterstitialPage::InterstitialState state =
1858 TestInterstitialPage::INVALID;
1859 bool deleted = false;
1860 GURL url("http://interstitial");
1861 TestInterstitialPage* interstitial =
1862 new TestInterstitialPage(contents(), true, url, &state, &deleted);
1863 TestInterstitialPageStateGuard state_guard(interstitial);
1864 interstitial->Show();
1865 interstitial->TestDidNavigate(1, url);
1866 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>(
1867 interstitial->GetRenderViewHostForTesting());
1869 // Now close the contents.
1870 DeleteContents();
1871 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
1873 // Before the interstitial has a chance to process its shutdown task,
1874 // simulate quitting the browser. This goes through all processes and
1875 // tells them to destruct.
1876 rvh->OnMessageReceived(
1877 ViewHostMsg_RenderProcessGone(0, 0, 0));
1879 RunAllPendingInMessageLoop();
1880 EXPECT_TRUE(deleted);
1883 // Test that after Proceed is called and an interstitial is still shown, no more
1884 // commands get executed.
1885 TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) {
1886 // Navigate to a page so we have a navigation entry in the controller.
1887 GURL url1("http://www.google.com");
1888 test_rvh()->SendNavigate(1, url1);
1889 EXPECT_EQ(1, controller().GetEntryCount());
1891 // Show an interstitial.
1892 TestInterstitialPage::InterstitialState state =
1893 TestInterstitialPage::INVALID;
1894 bool deleted = false;
1895 GURL url2("http://interstitial");
1896 TestInterstitialPage* interstitial =
1897 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
1898 TestInterstitialPageStateGuard state_guard(interstitial);
1899 interstitial->Show();
1900 interstitial->TestDidNavigate(1, url2);
1902 // Run a command.
1903 EXPECT_EQ(0, interstitial->command_received_count());
1904 interstitial->TestDomOperationResponse("toto");
1905 EXPECT_EQ(1, interstitial->command_received_count());
1907 // Then proceed.
1908 interstitial->Proceed();
1909 RunAllPendingInMessageLoop();
1910 ASSERT_FALSE(deleted);
1912 // While the navigation to the new page is pending, send other commands, they
1913 // should be ignored.
1914 interstitial->TestDomOperationResponse("hello");
1915 interstitial->TestDomOperationResponse("hi");
1916 EXPECT_EQ(1, interstitial->command_received_count());
1919 // Test showing an interstitial while another interstitial is already showing.
1920 TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) {
1921 // Navigate to a page so we have a navigation entry in the controller.
1922 GURL start_url("http://www.google.com");
1923 test_rvh()->SendNavigate(1, start_url);
1924 EXPECT_EQ(1, controller().GetEntryCount());
1926 // Show an interstitial.
1927 TestInterstitialPage::InterstitialState state1 =
1928 TestInterstitialPage::INVALID;
1929 bool deleted1 = false;
1930 GURL url1("http://interstitial1");
1931 TestInterstitialPage* interstitial1 =
1932 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1933 TestInterstitialPageStateGuard state_guard1(interstitial1);
1934 interstitial1->Show();
1935 interstitial1->TestDidNavigate(1, url1);
1937 // Now show another interstitial.
1938 TestInterstitialPage::InterstitialState state2 =
1939 TestInterstitialPage::INVALID;
1940 bool deleted2 = false;
1941 GURL url2("http://interstitial2");
1942 TestInterstitialPage* interstitial2 =
1943 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
1944 TestInterstitialPageStateGuard state_guard2(interstitial2);
1945 interstitial2->Show();
1946 interstitial2->TestDidNavigate(1, url2);
1948 // Showing interstitial2 should have caused interstitial1 to go away.
1949 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
1950 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
1952 RunAllPendingInMessageLoop();
1953 EXPECT_TRUE(deleted1);
1954 ASSERT_FALSE(deleted2);
1956 // Let's make sure interstitial2 is working as intended.
1957 interstitial2->Proceed();
1958 GURL landing_url("http://www.thepage.com");
1959 test_rvh()->SendNavigate(2, landing_url);
1961 EXPECT_FALSE(contents()->ShowingInterstitialPage());
1962 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
1963 NavigationEntry* entry = controller().GetVisibleEntry();
1964 ASSERT_TRUE(entry != NULL);
1965 EXPECT_TRUE(entry->GetURL() == landing_url);
1966 EXPECT_EQ(2, controller().GetEntryCount());
1967 RunAllPendingInMessageLoop();
1968 EXPECT_TRUE(deleted2);
1971 // Test showing an interstitial, proceeding and then navigating to another
1972 // interstitial.
1973 TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) {
1974 // Navigate to a page so we have a navigation entry in the controller.
1975 GURL start_url("http://www.google.com");
1976 test_rvh()->SendNavigate(1, start_url);
1977 EXPECT_EQ(1, controller().GetEntryCount());
1979 // Show an interstitial.
1980 TestInterstitialPage::InterstitialState state1 =
1981 TestInterstitialPage::INVALID;
1982 bool deleted1 = false;
1983 GURL url1("http://interstitial1");
1984 TestInterstitialPage* interstitial1 =
1985 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1);
1986 TestInterstitialPageStateGuard state_guard1(interstitial1);
1987 interstitial1->Show();
1988 interstitial1->TestDidNavigate(1, url1);
1990 // Take action. The interstitial won't be hidden until the navigation is
1991 // committed.
1992 interstitial1->Proceed();
1993 EXPECT_EQ(TestInterstitialPage::OKED, state1);
1995 // Now show another interstitial (simulating the navigation causing another
1996 // interstitial).
1997 TestInterstitialPage::InterstitialState state2 =
1998 TestInterstitialPage::INVALID;
1999 bool deleted2 = false;
2000 GURL url2("http://interstitial2");
2001 TestInterstitialPage* interstitial2 =
2002 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2);
2003 TestInterstitialPageStateGuard state_guard2(interstitial2);
2004 interstitial2->Show();
2005 interstitial2->TestDidNavigate(1, url2);
2007 // Showing interstitial2 should have caused interstitial1 to go away.
2008 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2009 RunAllPendingInMessageLoop();
2010 EXPECT_TRUE(deleted1);
2011 ASSERT_FALSE(deleted2);
2013 // Let's make sure interstitial2 is working as intended.
2014 interstitial2->Proceed();
2015 GURL landing_url("http://www.thepage.com");
2016 test_rvh()->SendNavigate(2, landing_url);
2018 RunAllPendingInMessageLoop();
2019 EXPECT_TRUE(deleted2);
2020 EXPECT_FALSE(contents()->ShowingInterstitialPage());
2021 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL);
2022 NavigationEntry* entry = controller().GetVisibleEntry();
2023 ASSERT_TRUE(entry != NULL);
2024 EXPECT_TRUE(entry->GetURL() == landing_url);
2025 EXPECT_EQ(2, controller().GetEntryCount());
2028 // Test that navigating away from an interstitial while it's loading cause it
2029 // not to show.
2030 TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) {
2031 // Show an interstitial.
2032 TestInterstitialPage::InterstitialState state =
2033 TestInterstitialPage::INVALID;
2034 bool deleted = false;
2035 GURL interstitial_url("http://interstitial");
2036 TestInterstitialPage* interstitial =
2037 new TestInterstitialPage(contents(), true, interstitial_url,
2038 &state, &deleted);
2039 TestInterstitialPageStateGuard state_guard(interstitial);
2040 interstitial->Show();
2042 // Let's simulate a navigation initiated from the browser before the
2043 // interstitial finishes loading.
2044 const GURL url("http://www.google.com");
2045 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2046 EXPECT_FALSE(interstitial->is_showing());
2047 RunAllPendingInMessageLoop();
2048 ASSERT_FALSE(deleted);
2050 // Now let's make the interstitial navigation commit.
2051 interstitial->TestDidNavigate(1, interstitial_url);
2053 // After it loaded the interstitial should be gone.
2054 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2056 RunAllPendingInMessageLoop();
2057 EXPECT_TRUE(deleted);
2060 // Test that a new request to show an interstitial while an interstitial is
2061 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442.
2062 TEST_F(WebContentsImplTest, TwoQuickInterstitials) {
2063 GURL interstitial_url("http://interstitial");
2065 // Show a first interstitial.
2066 TestInterstitialPage::InterstitialState state1 =
2067 TestInterstitialPage::INVALID;
2068 bool deleted1 = false;
2069 TestInterstitialPage* interstitial1 =
2070 new TestInterstitialPage(contents(), true, interstitial_url,
2071 &state1, &deleted1);
2072 TestInterstitialPageStateGuard state_guard1(interstitial1);
2073 interstitial1->Show();
2075 // Show another interstitial on that same contents before the first one had
2076 // time to load.
2077 TestInterstitialPage::InterstitialState state2 =
2078 TestInterstitialPage::INVALID;
2079 bool deleted2 = false;
2080 TestInterstitialPage* interstitial2 =
2081 new TestInterstitialPage(contents(), true, interstitial_url,
2082 &state2, &deleted2);
2083 TestInterstitialPageStateGuard state_guard2(interstitial2);
2084 interstitial2->Show();
2086 // The first interstitial should have been closed and deleted.
2087 EXPECT_EQ(TestInterstitialPage::CANCELED, state1);
2088 // The 2nd one should still be OK.
2089 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2091 RunAllPendingInMessageLoop();
2092 EXPECT_TRUE(deleted1);
2093 ASSERT_FALSE(deleted2);
2095 // Make the interstitial navigation commit it should be showing.
2096 interstitial2->TestDidNavigate(1, interstitial_url);
2097 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage());
2100 // Test showing an interstitial and have its renderer crash.
2101 TEST_F(WebContentsImplTest, InterstitialCrasher) {
2102 // Show an interstitial.
2103 TestInterstitialPage::InterstitialState state =
2104 TestInterstitialPage::INVALID;
2105 bool deleted = false;
2106 GURL url("http://interstitial");
2107 TestInterstitialPage* interstitial =
2108 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2109 TestInterstitialPageStateGuard state_guard(interstitial);
2110 interstitial->Show();
2111 // Simulate a renderer crash before the interstitial is shown.
2112 interstitial->TestRenderViewTerminated(
2113 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2114 // The interstitial should have been dismissed.
2115 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2116 RunAllPendingInMessageLoop();
2117 EXPECT_TRUE(deleted);
2119 // Now try again but this time crash the intersitial after it was shown.
2120 interstitial =
2121 new TestInterstitialPage(contents(), true, url, &state, &deleted);
2122 interstitial->Show();
2123 interstitial->TestDidNavigate(1, url);
2124 // Simulate a renderer crash.
2125 interstitial->TestRenderViewTerminated(
2126 base::TERMINATION_STATUS_PROCESS_CRASHED, -1);
2127 // The interstitial should have been dismissed.
2128 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2129 RunAllPendingInMessageLoop();
2130 EXPECT_TRUE(deleted);
2133 // Tests that showing an interstitial as a result of a browser initiated
2134 // navigation while an interstitial is showing does not remove the pending
2135 // entry (see http://crbug.com/9791).
2136 TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) {
2137 const char kUrl[] = "http://www.badguys.com/";
2138 const GURL kGURL(kUrl);
2140 // Start a navigation to a page
2141 contents()->GetController().LoadURL(
2142 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2144 // Simulate that navigation triggering an interstitial.
2145 TestInterstitialPage::InterstitialState state =
2146 TestInterstitialPage::INVALID;
2147 bool deleted = false;
2148 TestInterstitialPage* interstitial =
2149 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2150 TestInterstitialPageStateGuard state_guard(interstitial);
2151 interstitial->Show();
2152 interstitial->TestDidNavigate(1, kGURL);
2154 // Initiate a new navigation from the browser that also triggers an
2155 // interstitial.
2156 contents()->GetController().LoadURL(
2157 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2158 TestInterstitialPage::InterstitialState state2 =
2159 TestInterstitialPage::INVALID;
2160 bool deleted2 = false;
2161 TestInterstitialPage* interstitial2 =
2162 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2);
2163 TestInterstitialPageStateGuard state_guard2(interstitial2);
2164 interstitial2->Show();
2165 interstitial2->TestDidNavigate(1, kGURL);
2167 // Make sure we still have an entry.
2168 NavigationEntry* entry = contents()->GetController().GetPendingEntry();
2169 ASSERT_TRUE(entry);
2170 EXPECT_EQ(kUrl, entry->GetURL().spec());
2172 // And that the first interstitial is gone, but not the second.
2173 EXPECT_EQ(TestInterstitialPage::CANCELED, state);
2174 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2);
2175 RunAllPendingInMessageLoop();
2176 EXPECT_TRUE(deleted);
2177 EXPECT_FALSE(deleted2);
2180 // Tests that Javascript messages are not shown while an interstitial is
2181 // showing.
2182 TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) {
2183 const char kUrl[] = "http://www.badguys.com/";
2184 const GURL kGURL(kUrl);
2186 // Start a navigation to a page
2187 contents()->GetController().LoadURL(
2188 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string());
2189 // DidNavigate from the page
2190 contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED);
2192 // Simulate showing an interstitial while the page is showing.
2193 TestInterstitialPage::InterstitialState state =
2194 TestInterstitialPage::INVALID;
2195 bool deleted = false;
2196 TestInterstitialPage* interstitial =
2197 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted);
2198 TestInterstitialPageStateGuard state_guard(interstitial);
2199 interstitial->Show();
2200 interstitial->TestDidNavigate(1, kGURL);
2202 // While the interstitial is showing, let's simulate the hidden page
2203 // attempting to show a JS message.
2204 IPC::Message* dummy_message = new IPC::Message;
2205 contents()->RunJavaScriptMessage(contents()->GetMainFrame(),
2206 base::ASCIIToUTF16("This is an informative message"),
2207 base::ASCIIToUTF16("OK"),
2208 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message);
2209 EXPECT_TRUE(contents()->last_dialog_suppressed_);
2212 // Makes sure that if the source passed to CopyStateFromAndPrune has an
2213 // interstitial it isn't copied over to the destination.
2214 TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) {
2215 // Navigate to a page.
2216 GURL url1("http://www.google.com");
2217 test_rvh()->SendNavigate(1, url1);
2218 EXPECT_EQ(1, controller().GetEntryCount());
2220 // Initiate a browser navigation that will trigger the interstitial
2221 controller().LoadURL(GURL("http://www.evil.com"), Referrer(),
2222 PAGE_TRANSITION_TYPED, std::string());
2224 // Show an interstitial.
2225 TestInterstitialPage::InterstitialState state =
2226 TestInterstitialPage::INVALID;
2227 bool deleted = false;
2228 GURL url2("http://interstitial");
2229 TestInterstitialPage* interstitial =
2230 new TestInterstitialPage(contents(), true, url2, &state, &deleted);
2231 TestInterstitialPageStateGuard state_guard(interstitial);
2232 interstitial->Show();
2233 interstitial->TestDidNavigate(1, url2);
2234 EXPECT_TRUE(interstitial->is_showing());
2235 EXPECT_EQ(2, controller().GetEntryCount());
2237 // Create another NavigationController.
2238 GURL url3("http://foo2");
2239 scoped_ptr<TestWebContents> other_contents(
2240 static_cast<TestWebContents*>(CreateTestWebContents()));
2241 NavigationControllerImpl& other_controller = other_contents->GetController();
2242 other_contents->NavigateAndCommit(url3);
2243 other_contents->ExpectSetHistoryLengthAndPrune(
2244 NavigationEntryImpl::FromNavigationEntry(
2245 other_controller.GetEntryAtIndex(0))->site_instance(), 1,
2246 other_controller.GetEntryAtIndex(0)->GetPageID());
2247 other_controller.CopyStateFromAndPrune(&controller(), false);
2249 // The merged controller should only have two entries: url1 and url2.
2250 ASSERT_EQ(2, other_controller.GetEntryCount());
2251 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex());
2252 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL());
2253 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL());
2255 // And the merged controller shouldn't be showing an interstitial.
2256 EXPECT_FALSE(other_contents->ShowingInterstitialPage());
2259 // Makes sure that CopyStateFromAndPrune cannot be called if the target is
2260 // showing an interstitial.
2261 TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) {
2262 // Navigate to a page.
2263 GURL url1("http://www.google.com");
2264 contents()->NavigateAndCommit(url1);
2266 // Create another NavigationController.
2267 scoped_ptr<TestWebContents> other_contents(
2268 static_cast<TestWebContents*>(CreateTestWebContents()));
2269 NavigationControllerImpl& other_controller = other_contents->GetController();
2271 // Navigate it to url2.
2272 GURL url2("http://foo2");
2273 other_contents->NavigateAndCommit(url2);
2275 // Show an interstitial.
2276 TestInterstitialPage::InterstitialState state =
2277 TestInterstitialPage::INVALID;
2278 bool deleted = false;
2279 GURL url3("http://interstitial");
2280 TestInterstitialPage* interstitial =
2281 new TestInterstitialPage(other_contents.get(), true, url3, &state,
2282 &deleted);
2283 TestInterstitialPageStateGuard state_guard(interstitial);
2284 interstitial->Show();
2285 interstitial->TestDidNavigate(1, url3);
2286 EXPECT_TRUE(interstitial->is_showing());
2287 EXPECT_EQ(2, other_controller.GetEntryCount());
2289 // Ensure that we do not allow calling CopyStateFromAndPrune when an
2290 // interstitial is showing in the target.
2291 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted());
2294 // Regression test for http://crbug.com/168611 - the URLs passed by the
2295 // DidFinishLoad and DidFailLoadWithError IPCs should get filtered.
2296 TEST_F(WebContentsImplTest, FilterURLs) {
2297 TestWebContentsObserver observer(contents());
2299 // A navigation to about:whatever should always look like a navigation to
2300 // about:blank
2301 GURL url_normalized(url::kAboutBlankURL);
2302 GURL url_from_ipc("about:whatever");
2304 // We navigate the test WebContents to about:blank, since NavigateAndCommit
2305 // will use the given URL to create the NavigationEntry as well, and that
2306 // entry should contain the filtered URL.
2307 contents()->NavigateAndCommit(url_normalized);
2309 // Check that an IPC with about:whatever is correctly normalized.
2310 contents()->TestDidFinishLoad(url_from_ipc);
2312 EXPECT_EQ(url_normalized, observer.last_url());
2314 // Create and navigate another WebContents.
2315 scoped_ptr<TestWebContents> other_contents(
2316 static_cast<TestWebContents*>(CreateTestWebContents()));
2317 TestWebContentsObserver other_observer(other_contents.get());
2318 other_contents->NavigateAndCommit(url_normalized);
2320 // Check that an IPC with about:whatever is correctly normalized.
2321 other_contents->TestDidFailLoadWithError(
2322 url_from_ipc, 1, base::string16());
2323 EXPECT_EQ(url_normalized, other_observer.last_url());
2326 // Test that if a pending contents is deleted before it is shown, we don't
2327 // crash.
2328 TEST_F(WebContentsImplTest, PendingContents) {
2329 scoped_ptr<TestWebContents> other_contents(
2330 static_cast<TestWebContents*>(CreateTestWebContents()));
2331 contents()->AddPendingContents(other_contents.get());
2332 int route_id = other_contents->GetRenderViewHost()->GetRoutingID();
2333 other_contents.reset();
2334 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id));
2337 TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) {
2338 const gfx::Size original_preferred_size(1024, 768);
2339 contents()->UpdatePreferredSize(original_preferred_size);
2341 // With no capturers, expect the preferred size to be the one propagated into
2342 // WebContentsImpl via the RenderViewHostDelegate interface.
2343 EXPECT_EQ(contents()->GetCapturerCount(), 0);
2344 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2346 // Increment capturer count, but without specifying a capture size. Expect
2347 // a "not set" preferred size.
2348 contents()->IncrementCapturerCount(gfx::Size());
2349 EXPECT_EQ(1, contents()->GetCapturerCount());
2350 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize());
2352 // Increment capturer count again, but with an overriding capture size.
2353 // Expect preferred size to now be overridden to the capture size.
2354 const gfx::Size capture_size(1280, 720);
2355 contents()->IncrementCapturerCount(capture_size);
2356 EXPECT_EQ(2, contents()->GetCapturerCount());
2357 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2359 // Increment capturer count a third time, but the expect that the preferred
2360 // size is still the first capture size.
2361 const gfx::Size another_capture_size(720, 480);
2362 contents()->IncrementCapturerCount(another_capture_size);
2363 EXPECT_EQ(3, contents()->GetCapturerCount());
2364 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2366 // Decrement capturer count twice, but expect the preferred size to still be
2367 // overridden.
2368 contents()->DecrementCapturerCount();
2369 contents()->DecrementCapturerCount();
2370 EXPECT_EQ(1, contents()->GetCapturerCount());
2371 EXPECT_EQ(capture_size, contents()->GetPreferredSize());
2373 // Decrement capturer count, and since the count has dropped to zero, the
2374 // original preferred size should be restored.
2375 contents()->DecrementCapturerCount();
2376 EXPECT_EQ(0, contents()->GetCapturerCount());
2377 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize());
2380 // Tests that GetLastActiveTime starts with a real, non-zero time and updates
2381 // on activity.
2382 TEST_F(WebContentsImplTest, GetLastActiveTime) {
2383 // The WebContents starts with a valid creation time.
2384 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2386 // Reset the last active time to a known-bad value.
2387 contents()->last_active_time_ = base::TimeTicks();
2388 ASSERT_TRUE(contents()->GetLastActiveTime().is_null());
2390 // Simulate activating the WebContents. The active time should update.
2391 contents()->WasShown();
2392 EXPECT_FALSE(contents()->GetLastActiveTime().is_null());
2395 class ContentsZoomChangedDelegate : public WebContentsDelegate {
2396 public:
2397 ContentsZoomChangedDelegate() :
2398 contents_zoom_changed_call_count_(0),
2399 last_zoom_in_(false) {
2402 int GetAndResetContentsZoomChangedCallCount() {
2403 int count = contents_zoom_changed_call_count_;
2404 contents_zoom_changed_call_count_ = 0;
2405 return count;
2408 bool last_zoom_in() const {
2409 return last_zoom_in_;
2412 // WebContentsDelegate:
2413 virtual void ContentsZoomChange(bool zoom_in) OVERRIDE {
2414 contents_zoom_changed_call_count_++;
2415 last_zoom_in_ = zoom_in;
2418 private:
2419 int contents_zoom_changed_call_count_;
2420 bool last_zoom_in_;
2422 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate);
2425 // Tests that some mouseehweel events get turned into browser zoom requests.
2426 TEST_F(WebContentsImplTest, HandleWheelEvent) {
2427 using blink::WebInputEvent;
2429 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2430 new ContentsZoomChangedDelegate());
2431 contents()->SetDelegate(delegate.get());
2433 int modifiers = 0;
2434 // Verify that normal mouse wheel events do nothing to change the zoom level.
2435 blink::WebMouseWheelEvent event =
2436 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2437 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2438 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2440 modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey;
2441 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2442 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2443 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2445 // But whenever the ctrl modifier is applied, they can increase/decrease zoom.
2446 // Except on MacOS where we never want to adjust zoom with mousewheel.
2447 modifiers = WebInputEvent::ControlKey;
2448 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false);
2449 bool handled = contents()->HandleWheelEvent(event);
2450 #if defined(OS_MACOSX)
2451 EXPECT_FALSE(handled);
2452 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2453 #else
2454 EXPECT_TRUE(handled);
2455 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2456 EXPECT_TRUE(delegate->last_zoom_in());
2457 #endif
2459 modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey |
2460 WebInputEvent::AltKey;
2461 event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false);
2462 handled = contents()->HandleWheelEvent(event);
2463 #if defined(OS_MACOSX)
2464 EXPECT_FALSE(handled);
2465 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2466 #else
2467 EXPECT_TRUE(handled);
2468 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2469 EXPECT_FALSE(delegate->last_zoom_in());
2470 #endif
2472 // Unless there is no vertical movement.
2473 event = SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers, false);
2474 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2475 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2477 // Events containing precise scrolling deltas also shouldn't result in the
2478 // zoom being adjusted, to avoid accidental adjustments caused by
2479 // two-finger-scrolling on a touchpad.
2480 modifiers = WebInputEvent::ControlKey;
2481 event = SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers, true);
2482 EXPECT_FALSE(contents()->HandleWheelEvent(event));
2483 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2485 // Ensure pointers to the delegate aren't kept beyond its lifetime.
2486 contents()->SetDelegate(NULL);
2489 // Tests that trackpad GesturePinchUpdate events get turned into browser zoom.
2490 TEST_F(WebContentsImplTest, HandleGestureEvent) {
2491 using blink::WebGestureEvent;
2492 using blink::WebInputEvent;
2494 scoped_ptr<ContentsZoomChangedDelegate> delegate(
2495 new ContentsZoomChangedDelegate());
2496 contents()->SetDelegate(delegate.get());
2498 const float kZoomStepValue = 0.6f;
2499 blink::WebGestureEvent event = SyntheticWebGestureEventBuilder::Build(
2500 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchpad);
2502 // A pinch less than the step value doesn't change the zoom level.
2503 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 0.8f;
2504 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2505 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2507 // But repeating the event so the combined scale is greater does.
2508 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2509 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2510 EXPECT_TRUE(delegate->last_zoom_in());
2512 // Pinching back out one step goes back to 100%.
2513 event.data.pinchUpdate.scale = 1.0f - kZoomStepValue;
2514 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2515 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2516 EXPECT_FALSE(delegate->last_zoom_in());
2518 // Pinching out again doesn't zoom (step is twice as large around 100%).
2519 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2520 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2522 // And again now it zooms once per step.
2523 EXPECT_TRUE(contents()->HandleGestureEvent(event));
2524 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount());
2525 EXPECT_FALSE(delegate->last_zoom_in());
2527 // No other type of gesture event is handled by WebContentsImpl (for example
2528 // a touchscreen pinch gesture).
2529 event = SyntheticWebGestureEventBuilder::Build(
2530 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchscreen);
2531 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 3;
2532 EXPECT_FALSE(contents()->HandleGestureEvent(event));
2533 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount());
2535 // Ensure pointers to the delegate aren't kept beyond it's lifetime.
2536 contents()->SetDelegate(NULL);
2539 // Tests that GetRelatedActiveContentsCount is shared between related
2540 // SiteInstances and includes WebContents that have not navigated yet.
2541 TEST_F(WebContentsImplTest, ActiveContentsCountBasic) {
2542 scoped_refptr<SiteInstance> instance1(
2543 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com")));
2544 scoped_refptr<SiteInstance> instance2(
2545 instance1->GetRelatedSiteInstance(GURL("http://b.com")));
2547 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2548 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2550 scoped_ptr<TestWebContents> contents1(
2551 TestWebContents::Create(browser_context(), instance1));
2552 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2553 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2555 scoped_ptr<TestWebContents> contents2(
2556 TestWebContents::Create(browser_context(), instance1));
2557 EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount());
2558 EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount());
2560 contents1.reset();
2561 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount());
2562 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount());
2564 contents2.reset();
2565 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount());
2566 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount());
2569 // Tests that GetRelatedActiveContentsCount is preserved correctly across
2570 // same-site and cross-site navigations.
2571 TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) {
2572 scoped_refptr<SiteInstance> instance(
2573 SiteInstance::Create(browser_context()));
2575 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2577 scoped_ptr<TestWebContents> contents(
2578 TestWebContents::Create(browser_context(), instance));
2579 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2581 // Navigate to a URL.
2582 contents->GetController().LoadURL(
2583 GURL("http://a.com/1"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2584 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2585 contents->CommitPendingNavigation();
2586 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2588 // Navigate to a URL in the same site.
2589 contents->GetController().LoadURL(
2590 GURL("http://a.com/2"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2591 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2592 contents->CommitPendingNavigation();
2593 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2595 // Navigate to a URL in a different site.
2596 contents->GetController().LoadURL(
2597 GURL("http://b.com"), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2598 EXPECT_TRUE(contents->cross_navigation_pending());
2599 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2600 contents->CommitPendingNavigation();
2601 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2603 contents.reset();
2604 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2607 // Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes
2608 // from WebUI.
2609 TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) {
2610 scoped_refptr<SiteInstance> instance(
2611 SiteInstance::Create(browser_context()));
2613 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2615 scoped_ptr<TestWebContents> contents(
2616 TestWebContents::Create(browser_context(), instance));
2617 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2619 // Navigate to a URL.
2620 contents->NavigateAndCommit(GURL("http://a.com"));
2621 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2623 // Navigate to a URL with WebUI. This will change BrowsingInstances.
2624 contents->GetController().LoadURL(
2625 GURL(kTestWebUIUrl), Referrer(), PAGE_TRANSITION_TYPED, std::string());
2626 EXPECT_TRUE(contents->cross_navigation_pending());
2627 scoped_refptr<SiteInstance> instance_webui(
2628 contents->GetPendingRenderViewHost()->GetSiteInstance());
2629 EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get()));
2631 // At this point, contents still counts for the old BrowsingInstance.
2632 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount());
2633 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2635 // Commit and contents counts for the new one.
2636 contents->CommitPendingNavigation();
2637 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2638 EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount());
2640 contents.reset();
2641 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount());
2642 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount());
2645 } // namespace content