web_contents_impl_unittest.cc revision 6d86b77056ed63eb6871182f42a9fd5f07550f90
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. 4 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" 36 37namespace content { 38namespace { 39 40const char kTestWebUIUrl[] = "chrome://blah"; 41 42class 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); 50 } 51 52 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context, 53 const GURL& url) const OVERRIDE { 54 return WebUI::kNoWebUI; 55 } 56 57 virtual bool UseWebUIForURL(BrowserContext* browser_context, 58 const GURL& url) const OVERRIDE { 59 return UseWebUI(url); 60 } 61 62 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context, 63 const GURL& url) const OVERRIDE { 64 return UseWebUI(url); 65 } 66 67 private: 68 bool UseWebUI(const GURL& url) const { 69 return url == GURL(kTestWebUIUrl); 70 } 71}; 72 73class TestInterstitialPage; 74 75class 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_; 85}; 86 87class 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. 94 }; 95 96 class Delegate { 97 public: 98 virtual void TestInterstitialPageDeleted( 99 TestInterstitialPage* interstitial) = 0; 100 101 protected: 102 virtual ~Delegate() {} 103 }; 104 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; 129 } 130 131 virtual ~TestInterstitialPage() { 132 if (deleted_) 133 *deleted_ = true; 134 if (delegate_) 135 delegate_->TestInterstitialPageDeleted(this); 136 } 137 138 void OnDontProceed() { 139 if (state_) 140 *state_ = CANCELED; 141 } 142 void OnProceed() { 143 if (state_) 144 *state_ = OKED; 145 } 146 147 int command_received_count() const { 148 return command_received_count_; 149 } 150 151 void TestDomOperationResponse(const std::string& json_string) { 152 if (enabled()) 153 CommandReceived(); 154 } 155 156 void TestDidNavigate(int page_id, const GURL& url) { 157 FrameHostMsg_DidCommitProvisionalLoad_Params params; 158 InitNavigateParams(¶ms, page_id, url, PAGE_TRANSITION_TYPED); 159 DidNavigate(GetRenderViewHostForTesting(), params); 160 } 161 162 void TestRenderViewTerminated(base::TerminationStatus status, 163 int error_code) { 164 RenderViewTerminated(GetRenderViewHostForTesting(), status, error_code); 165 } 166 167 bool is_showing() const { 168 return static_cast<TestRenderWidgetHostView*>( 169 GetRenderViewHostForTesting()->GetView())->is_showing(); 170 } 171 172 void ClearStates() { 173 state_ = NULL; 174 deleted_ = NULL; 175 delegate_ = NULL; 176 } 177 178 void CommandReceived() { 179 command_received_count_++; 180 } 181 182 void set_delegate(Delegate* delegate) { 183 delegate_ = delegate; 184 } 185 186 protected: 187 virtual WebContentsView* CreateWebContentsView() OVERRIDE { 188 return NULL; 189 } 190 191 private: 192 InterstitialState* state_; 193 bool* deleted_; 194 int command_received_count_; 195 Delegate* delegate_; 196}; 197 198void TestInterstitialPageDelegate::CommandReceived(const std::string& command) { 199 interstitial_page_->CommandReceived(); 200} 201 202void TestInterstitialPageDelegate::OnDontProceed() { 203 interstitial_page_->OnDontProceed(); 204} 205 206void TestInterstitialPageDelegate::OnProceed() { 207 interstitial_page_->OnProceed(); 208} 209 210class 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); 217 } 218 virtual ~TestInterstitialPageStateGuard() { 219 if (interstitial_page_) 220 interstitial_page_->ClearStates(); 221 } 222 223 virtual void TestInterstitialPageDeleted( 224 TestInterstitialPage* interstitial) OVERRIDE { 225 DCHECK(interstitial_page_ == interstitial); 226 interstitial_page_ = NULL; 227 } 228 229 private: 230 TestInterstitialPage* interstitial_page_; 231}; 232 233class WebContentsImplTestBrowserClient : public TestContentBrowserClient { 234 public: 235 WebContentsImplTestBrowserClient() 236 : assign_site_for_url_(false) {} 237 238 virtual ~WebContentsImplTestBrowserClient() {} 239 240 virtual bool ShouldAssignSiteForURL(const GURL& url) OVERRIDE { 241 return assign_site_for_url_; 242 } 243 244 void set_assign_site_for_url(bool assign) { 245 assign_site_for_url_ = assign; 246 } 247 248 private: 249 bool assign_site_for_url_; 250}; 251 252class WebContentsImplTest : public RenderViewHostImplTestHarness { 253 public: 254 virtual void SetUp() { 255 RenderViewHostImplTestHarness::SetUp(); 256 WebUIControllerFactory::RegisterFactory(&factory_); 257 } 258 259 virtual void TearDown() { 260 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_); 261 RenderViewHostImplTestHarness::TearDown(); 262 } 263 264 private: 265 WebContentsImplTestWebUIControllerFactory factory_; 266}; 267 268class TestWebContentsObserver : public WebContentsObserver { 269 public: 270 explicit TestWebContentsObserver(WebContents* contents) 271 : WebContentsObserver(contents) { 272 } 273 virtual ~TestWebContentsObserver() {} 274 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; 280 } 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; 288 } 289 290 const GURL& last_url() const { return last_url_; } 291 292 private: 293 GURL last_url_; 294 295 DISALLOW_COPY_AND_ASSIGN(TestWebContentsObserver); 296}; 297 298// Pretends to be a normal browser that receives toggles and transitions to/from 299// a fullscreened state. 300class FakeFullscreenDelegate : public WebContentsDelegate { 301 public: 302 FakeFullscreenDelegate() : fullscreened_contents_(NULL) {} 303 virtual ~FakeFullscreenDelegate() {} 304 305 virtual void ToggleFullscreenModeForTab(WebContents* web_contents, 306 bool enter_fullscreen) OVERRIDE { 307 fullscreened_contents_ = enter_fullscreen ? web_contents : NULL; 308 } 309 310 virtual bool IsFullscreenForTabOrPending(const WebContents* web_contents) 311 const OVERRIDE { 312 return fullscreened_contents_ && web_contents == fullscreened_contents_; 313 } 314 315 private: 316 WebContents* fullscreened_contents_; 317 318 DISALLOW_COPY_AND_ASSIGN(FakeFullscreenDelegate); 319}; 320 321} // namespace 322 323// Test to make sure that title updates get stripped of whitespace. 324TEST_F(WebContentsImplTest, UpdateTitle) { 325 NavigationControllerImpl& cont = 326 static_cast<NavigationControllerImpl&>(controller()); 327 FrameHostMsg_DidCommitProvisionalLoad_Params params; 328 InitNavigateParams( 329 ¶ms, 0, GURL(url::kAboutBlankURL), PAGE_TRANSITION_TYPED); 330 331 LoadCommittedDetails details; 332 cont.RendererDidNavigate(main_test_rfh(), params, &details); 333 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()); 338} 339 340TEST_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()); 345} 346 347TEST_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()); 352 353 NavigationEntry* entry = controller().GetVisibleEntry(); 354 ASSERT_EQ(kGURL, entry->GetURL()); 355 entry->SetTitle(title); 356 357 EXPECT_EQ(title, contents()->GetTitle()); 358} 359 360// Test view source mode for a webui page. 361TEST_F(WebContentsImplTest, NTPViewSource) { 362 NavigationControllerImpl& cont = 363 static_cast<NavigationControllerImpl&>(controller()); 364 const char kUrl[] = "view-source:chrome://blah"; 365 const GURL kGURL(kUrl); 366 367 process()->sink().ClearMessages(); 368 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)); 375 376 FrameHostMsg_DidCommitProvisionalLoad_Params params; 377 InitNavigateParams(¶ms, 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()); 382} 383 384// Test to ensure UpdateMaxPageID is working properly. 385TEST_F(WebContentsImplTest, UpdateMaxPageID) { 386 SiteInstance* instance1 = contents()->GetSiteInstance(); 387 scoped_refptr<SiteInstance> instance2(SiteInstance::Create(NULL)); 388 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())); 393 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())); 400 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())); 405} 406 407// Test simple same-SiteInstance navigation. 408TEST_F(WebContentsImplTest, SimpleNavigation) { 409 TestRenderViewHost* orig_rvh = test_rvh(); 410 SiteInstance* instance1 = contents()->GetSiteInstance(); 411 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL); 412 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); 424 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()); 436} 437 438// Test that we reject NavigateToEntry if the url is over kMaxURLChars. 439TEST_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')); 443 444 controller().LoadURL( 445 url, Referrer(), PAGE_TRANSITION_GENERATED, std::string()); 446 EXPECT_TRUE(controller().GetVisibleEntry() == NULL); 447} 448 449// Test that navigating across a site boundary creates a new RenderViewHost 450// with a new SiteInstance. Going back should do the same. 451TEST_F(WebContentsImplTest, CrossSiteBoundaries) { 452 TestRenderViewHost* orig_rvh = test_rvh(); 453 RenderFrameHostImpl* orig_rfh = 454 contents()->GetFrameTree()->root()->current_frame_host(); 455 int orig_rvh_delete_count = 0; 456 orig_rvh->set_delete_counter(&orig_rvh_delete_count); 457 SiteInstance* instance1 = contents()->GetSiteInstance(); 458 459 // Navigate to URL. First URL should use first RenderViewHost. 460 const GURL url("http://www.google.com"); 461 controller().LoadURL( 462 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 463 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 464 465 // Keep the number of active views in orig_rvh's SiteInstance 466 // non-zero so that orig_rvh doesn't get deleted when it gets 467 // swapped out. 468 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())-> 469 increment_active_view_count(); 470 471 EXPECT_FALSE(contents()->cross_navigation_pending()); 472 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 473 EXPECT_EQ(url, contents()->GetLastCommittedURL()); 474 EXPECT_EQ(url, contents()->GetVisibleURL()); 475 476 // Navigate to new site 477 const GURL url2("http://www.yahoo.com"); 478 controller().LoadURL( 479 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 480 EXPECT_TRUE(contents()->cross_navigation_pending()); 481 EXPECT_EQ(url, contents()->GetLastCommittedURL()); 482 EXPECT_EQ(url2, contents()->GetVisibleURL()); 483 TestRenderViewHost* pending_rvh = 484 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost()); 485 int pending_rvh_delete_count = 0; 486 pending_rvh->set_delete_counter(&pending_rvh_delete_count); 487 RenderFrameHostImpl* pending_rfh = contents()->GetFrameTree()->root()-> 488 render_manager()->pending_frame_host(); 489 490 // Navigations should be suspended in pending_rvh until BeforeUnloadACK. 491 EXPECT_TRUE(pending_rvh->are_navigations_suspended()); 492 orig_rvh->SendBeforeUnloadACK(true); 493 EXPECT_FALSE(pending_rvh->are_navigations_suspended()); 494 495 // DidNavigate from the pending page 496 contents()->TestDidNavigate( 497 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED); 498 SiteInstance* instance2 = contents()->GetSiteInstance(); 499 500 // Keep the number of active views in pending_rvh's SiteInstance 501 // non-zero so that orig_rvh doesn't get deleted when it gets 502 // swapped out. 503 static_cast<SiteInstanceImpl*>(pending_rvh->GetSiteInstance())-> 504 increment_active_view_count(); 505 506 EXPECT_FALSE(contents()->cross_navigation_pending()); 507 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost()); 508 EXPECT_EQ(url2, contents()->GetLastCommittedURL()); 509 EXPECT_EQ(url2, contents()->GetVisibleURL()); 510 EXPECT_NE(instance1, instance2); 511 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL); 512 // We keep the original RFH around, swapped out. 513 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList( 514 orig_rfh)); 515 EXPECT_EQ(orig_rvh_delete_count, 0); 516 517 // Going back should switch SiteInstances again. The first SiteInstance is 518 // stored in the NavigationEntry, so it should be the same as at the start. 519 // We should use the same RVH as before, swapping it back in. 520 controller().GoBack(); 521 TestRenderViewHost* goback_rvh = 522 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost()); 523 EXPECT_EQ(orig_rvh, goback_rvh); 524 EXPECT_TRUE(contents()->cross_navigation_pending()); 525 526 // Navigations should be suspended in goback_rvh until BeforeUnloadACK. 527 EXPECT_TRUE(goback_rvh->are_navigations_suspended()); 528 pending_rvh->SendBeforeUnloadACK(true); 529 EXPECT_FALSE(goback_rvh->are_navigations_suspended()); 530 531 // DidNavigate from the back action 532 contents()->TestDidNavigate( 533 goback_rvh, 1, url2, PAGE_TRANSITION_TYPED); 534 EXPECT_FALSE(contents()->cross_navigation_pending()); 535 EXPECT_EQ(goback_rvh, contents()->GetRenderViewHost()); 536 EXPECT_EQ(instance1, contents()->GetSiteInstance()); 537 // The pending RFH should now be swapped out, not deleted. 538 EXPECT_TRUE(contents()->GetRenderManagerForTesting()-> 539 IsOnSwappedOutList(pending_rfh)); 540 EXPECT_EQ(pending_rvh_delete_count, 0); 541 pending_rvh->OnSwappedOut(false); 542 543 // Close contents and ensure RVHs are deleted. 544 DeleteContents(); 545 EXPECT_EQ(orig_rvh_delete_count, 1); 546 EXPECT_EQ(pending_rvh_delete_count, 1); 547} 548 549// Test that navigating across a site boundary after a crash creates a new 550// RVH without requiring a cross-site transition (i.e., PENDING state). 551TEST_F(WebContentsImplTest, CrossSiteBoundariesAfterCrash) { 552 TestRenderViewHost* orig_rvh = test_rvh(); 553 int orig_rvh_delete_count = 0; 554 orig_rvh->set_delete_counter(&orig_rvh_delete_count); 555 SiteInstance* instance1 = contents()->GetSiteInstance(); 556 557 // Navigate to URL. First URL should use first RenderViewHost. 558 const GURL url("http://www.google.com"); 559 controller().LoadURL( 560 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 561 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 562 563 EXPECT_FALSE(contents()->cross_navigation_pending()); 564 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 565 566 // Crash the renderer. 567 orig_rvh->set_render_view_created(false); 568 569 // Navigate to new site. We should not go into PENDING. 570 const GURL url2("http://www.yahoo.com"); 571 controller().LoadURL( 572 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 573 RenderViewHost* new_rvh = rvh(); 574 EXPECT_FALSE(contents()->cross_navigation_pending()); 575 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL); 576 EXPECT_NE(orig_rvh, new_rvh); 577 EXPECT_EQ(orig_rvh_delete_count, 1); 578 579 // DidNavigate from the new page 580 contents()->TestDidNavigate(new_rvh, 1, url2, PAGE_TRANSITION_TYPED); 581 SiteInstance* instance2 = contents()->GetSiteInstance(); 582 583 EXPECT_FALSE(contents()->cross_navigation_pending()); 584 EXPECT_EQ(new_rvh, rvh()); 585 EXPECT_NE(instance1, instance2); 586 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL); 587 588 // Close contents and ensure RVHs are deleted. 589 DeleteContents(); 590 EXPECT_EQ(orig_rvh_delete_count, 1); 591} 592 593// Test that opening a new contents in the same SiteInstance and then navigating 594// both contentses to a new site will place both contentses in a single 595// SiteInstance. 596TEST_F(WebContentsImplTest, NavigateTwoTabsCrossSite) { 597 TestRenderViewHost* orig_rvh = test_rvh(); 598 SiteInstance* instance1 = contents()->GetSiteInstance(); 599 600 // Navigate to URL. First URL should use first RenderViewHost. 601 const GURL url("http://www.google.com"); 602 controller().LoadURL( 603 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 604 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 605 606 // Open a new contents with the same SiteInstance, navigated to the same site. 607 scoped_ptr<TestWebContents> contents2( 608 TestWebContents::Create(browser_context(), instance1)); 609 contents2->GetController().LoadURL(url, Referrer(), 610 PAGE_TRANSITION_TYPED, 611 std::string()); 612 // Need this page id to be 2 since the site instance is the same (which is the 613 // scope of page IDs) and we want to consider this a new page. 614 contents2->TestDidNavigate( 615 contents2->GetRenderViewHost(), 2, url, PAGE_TRANSITION_TYPED); 616 617 // Navigate first contents to a new site. 618 const GURL url2a("http://www.yahoo.com"); 619 controller().LoadURL( 620 url2a, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 621 orig_rvh->SendBeforeUnloadACK(true); 622 TestRenderViewHost* pending_rvh_a = 623 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost()); 624 contents()->TestDidNavigate( 625 pending_rvh_a, 1, url2a, PAGE_TRANSITION_TYPED); 626 SiteInstance* instance2a = contents()->GetSiteInstance(); 627 EXPECT_NE(instance1, instance2a); 628 629 // Navigate second contents to the same site as the first tab. 630 const GURL url2b("http://mail.yahoo.com"); 631 contents2->GetController().LoadURL(url2b, Referrer(), 632 PAGE_TRANSITION_TYPED, 633 std::string()); 634 TestRenderViewHost* rvh2 = 635 static_cast<TestRenderViewHost*>(contents2->GetRenderViewHost()); 636 rvh2->SendBeforeUnloadACK(true); 637 TestRenderViewHost* pending_rvh_b = 638 static_cast<TestRenderViewHost*>(contents2->GetPendingRenderViewHost()); 639 EXPECT_TRUE(pending_rvh_b != NULL); 640 EXPECT_TRUE(contents2->cross_navigation_pending()); 641 642 // NOTE(creis): We used to be in danger of showing a crash page here if the 643 // second contents hadn't navigated somewhere first (bug 1145430). That case 644 // is now covered by the CrossSiteBoundariesAfterCrash test. 645 contents2->TestDidNavigate( 646 pending_rvh_b, 2, url2b, PAGE_TRANSITION_TYPED); 647 SiteInstance* instance2b = contents2->GetSiteInstance(); 648 EXPECT_NE(instance1, instance2b); 649 650 // Both contentses should now be in the same SiteInstance. 651 EXPECT_EQ(instance2a, instance2b); 652} 653 654TEST_F(WebContentsImplTest, NavigateDoesNotUseUpSiteInstance) { 655 WebContentsImplTestBrowserClient browser_client; 656 SetBrowserClientForTesting(&browser_client); 657 658 TestRenderViewHost* orig_rvh = test_rvh(); 659 RenderFrameHostImpl* orig_rfh = 660 contents()->GetFrameTree()->root()->current_frame_host(); 661 int orig_rvh_delete_count = 0; 662 orig_rvh->set_delete_counter(&orig_rvh_delete_count); 663 SiteInstanceImpl* orig_instance = 664 static_cast<SiteInstanceImpl*>(contents()->GetSiteInstance()); 665 666 browser_client.set_assign_site_for_url(false); 667 // Navigate to an URL that will not assign a new SiteInstance. 668 const GURL native_url("non-site-url://stuffandthings"); 669 controller().LoadURL( 670 native_url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 671 contents()->TestDidNavigate(orig_rvh, 1, native_url, PAGE_TRANSITION_TYPED); 672 673 EXPECT_FALSE(contents()->cross_navigation_pending()); 674 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 675 EXPECT_EQ(native_url, contents()->GetLastCommittedURL()); 676 EXPECT_EQ(native_url, contents()->GetVisibleURL()); 677 EXPECT_EQ(orig_instance, contents()->GetSiteInstance()); 678 EXPECT_EQ(GURL(), contents()->GetSiteInstance()->GetSiteURL()); 679 EXPECT_FALSE(orig_instance->HasSite()); 680 681 browser_client.set_assign_site_for_url(true); 682 // Navigate to new site (should keep same site instance). 683 const GURL url("http://www.google.com"); 684 controller().LoadURL( 685 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 686 EXPECT_FALSE(contents()->cross_navigation_pending()); 687 EXPECT_EQ(native_url, contents()->GetLastCommittedURL()); 688 EXPECT_EQ(url, contents()->GetVisibleURL()); 689 EXPECT_FALSE(contents()->GetPendingRenderViewHost()); 690 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 691 692 // Keep the number of active views in orig_rvh's SiteInstance 693 // non-zero so that orig_rvh doesn't get deleted when it gets 694 // swapped out. 695 static_cast<SiteInstanceImpl*>(orig_rvh->GetSiteInstance())-> 696 increment_active_view_count(); 697 698 EXPECT_EQ(orig_instance, contents()->GetSiteInstance()); 699 EXPECT_TRUE( 700 contents()->GetSiteInstance()->GetSiteURL().DomainIs("google.com")); 701 EXPECT_EQ(url, contents()->GetLastCommittedURL()); 702 703 // Navigate to another new site (should create a new site instance). 704 const GURL url2("http://www.yahoo.com"); 705 controller().LoadURL( 706 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 707 EXPECT_TRUE(contents()->cross_navigation_pending()); 708 EXPECT_EQ(url, contents()->GetLastCommittedURL()); 709 EXPECT_EQ(url2, contents()->GetVisibleURL()); 710 TestRenderViewHost* pending_rvh = 711 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost()); 712 int pending_rvh_delete_count = 0; 713 pending_rvh->set_delete_counter(&pending_rvh_delete_count); 714 715 // Navigations should be suspended in pending_rvh until BeforeUnloadACK. 716 EXPECT_TRUE(pending_rvh->are_navigations_suspended()); 717 orig_rvh->SendBeforeUnloadACK(true); 718 EXPECT_FALSE(pending_rvh->are_navigations_suspended()); 719 720 // DidNavigate from the pending page. 721 contents()->TestDidNavigate( 722 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED); 723 SiteInstance* new_instance = contents()->GetSiteInstance(); 724 725 EXPECT_FALSE(contents()->cross_navigation_pending()); 726 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost()); 727 EXPECT_EQ(url2, contents()->GetLastCommittedURL()); 728 EXPECT_EQ(url2, contents()->GetVisibleURL()); 729 EXPECT_NE(new_instance, orig_instance); 730 EXPECT_FALSE(contents()->GetPendingRenderViewHost()); 731 // We keep the original RFH around, swapped out. 732 EXPECT_TRUE(contents()->GetRenderManagerForTesting()->IsOnSwappedOutList( 733 orig_rfh)); 734 EXPECT_EQ(orig_rvh_delete_count, 0); 735 orig_rvh->OnSwappedOut(false); 736 737 // Close contents and ensure RVHs are deleted. 738 DeleteContents(); 739 EXPECT_EQ(orig_rvh_delete_count, 1); 740 EXPECT_EQ(pending_rvh_delete_count, 1); 741} 742 743// Test that we can find an opener RVH even if it's pending. 744// http://crbug.com/176252. 745TEST_F(WebContentsImplTest, FindOpenerRVHWhenPending) { 746 TestRenderViewHost* orig_rvh = test_rvh(); 747 748 // Navigate to a URL. 749 const GURL url("http://www.google.com"); 750 controller().LoadURL( 751 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 752 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 753 754 // Start to navigate first tab to a new site, so that it has a pending RVH. 755 const GURL url2("http://www.yahoo.com"); 756 controller().LoadURL( 757 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 758 orig_rvh->SendBeforeUnloadACK(true); 759 TestRenderViewHost* pending_rvh = 760 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost()); 761 762 // While it is still pending, simulate opening a new tab with the first tab 763 // as its opener. This will call WebContentsImpl::CreateOpenerRenderViews 764 // on the opener to ensure that an RVH exists. 765 int opener_routing_id = contents()->CreateOpenerRenderViews( 766 pending_rvh->GetSiteInstance()); 767 768 // We should find the pending RVH and not create a new one. 769 EXPECT_EQ(pending_rvh->GetRoutingID(), opener_routing_id); 770} 771 772// Tests that WebContentsImpl uses the current URL, not the SiteInstance's site, 773// to determine whether a navigation is cross-site. 774TEST_F(WebContentsImplTest, CrossSiteComparesAgainstCurrentPage) { 775 RenderViewHost* orig_rvh = rvh(); 776 SiteInstance* instance1 = contents()->GetSiteInstance(); 777 778 // Navigate to URL. 779 const GURL url("http://www.google.com"); 780 controller().LoadURL( 781 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 782 contents()->TestDidNavigate( 783 orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 784 785 // Open a related contents to a second site. 786 scoped_ptr<TestWebContents> contents2( 787 TestWebContents::Create(browser_context(), instance1)); 788 const GURL url2("http://www.yahoo.com"); 789 contents2->GetController().LoadURL(url2, Referrer(), 790 PAGE_TRANSITION_TYPED, 791 std::string()); 792 // The first RVH in contents2 isn't live yet, so we shortcut the cross site 793 // pending. 794 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>( 795 contents2->GetRenderViewHost()); 796 EXPECT_FALSE(contents2->cross_navigation_pending()); 797 contents2->TestDidNavigate(rvh2, 2, url2, PAGE_TRANSITION_TYPED); 798 SiteInstance* instance2 = contents2->GetSiteInstance(); 799 EXPECT_NE(instance1, instance2); 800 EXPECT_FALSE(contents2->cross_navigation_pending()); 801 802 // Simulate a link click in first contents to second site. Doesn't switch 803 // SiteInstances, because we don't intercept WebKit navigations. 804 contents()->TestDidNavigate( 805 orig_rvh, 2, url2, PAGE_TRANSITION_TYPED); 806 SiteInstance* instance3 = contents()->GetSiteInstance(); 807 EXPECT_EQ(instance1, instance3); 808 EXPECT_FALSE(contents()->cross_navigation_pending()); 809 810 // Navigate to the new site. Doesn't switch SiteInstancees, because we 811 // compare against the current URL, not the SiteInstance's site. 812 const GURL url3("http://mail.yahoo.com"); 813 controller().LoadURL( 814 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 815 EXPECT_FALSE(contents()->cross_navigation_pending()); 816 contents()->TestDidNavigate( 817 orig_rvh, 3, url3, PAGE_TRANSITION_TYPED); 818 SiteInstance* instance4 = contents()->GetSiteInstance(); 819 EXPECT_EQ(instance1, instance4); 820} 821 822// Test that the onbeforeunload and onunload handlers run when navigating 823// across site boundaries. 824TEST_F(WebContentsImplTest, CrossSiteUnloadHandlers) { 825 TestRenderViewHost* orig_rvh = test_rvh(); 826 SiteInstance* instance1 = contents()->GetSiteInstance(); 827 828 // Navigate to URL. First URL should use first RenderViewHost. 829 const GURL url("http://www.google.com"); 830 controller().LoadURL( 831 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 832 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 833 EXPECT_FALSE(contents()->cross_navigation_pending()); 834 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 835 836 // Navigate to new site, but simulate an onbeforeunload denial. 837 const GURL url2("http://www.yahoo.com"); 838 controller().LoadURL( 839 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 840 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 841 base::TimeTicks now = base::TimeTicks::Now(); 842 orig_rvh->GetMainFrame()->OnMessageReceived( 843 FrameHostMsg_BeforeUnload_ACK(0, false, now, now)); 844 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 845 EXPECT_FALSE(contents()->cross_navigation_pending()); 846 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 847 848 // Navigate again, but simulate an onbeforeunload approval. 849 controller().LoadURL( 850 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 851 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 852 now = base::TimeTicks::Now(); 853 orig_rvh->GetMainFrame()->OnMessageReceived( 854 FrameHostMsg_BeforeUnload_ACK(0, true, now, now)); 855 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 856 EXPECT_TRUE(contents()->cross_navigation_pending()); 857 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>( 858 contents()->GetPendingRenderViewHost()); 859 860 // We won't hear DidNavigate until the onunload handler has finished running. 861 862 // DidNavigate from the pending page. 863 contents()->TestDidNavigate( 864 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED); 865 SiteInstance* instance2 = contents()->GetSiteInstance(); 866 EXPECT_FALSE(contents()->cross_navigation_pending()); 867 EXPECT_EQ(pending_rvh, rvh()); 868 EXPECT_NE(instance1, instance2); 869 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL); 870} 871 872// Test that during a slow cross-site navigation, the original renderer can 873// navigate to a different URL and have it displayed, canceling the slow 874// navigation. 875TEST_F(WebContentsImplTest, CrossSiteNavigationPreempted) { 876 TestRenderViewHost* orig_rvh = test_rvh(); 877 SiteInstance* instance1 = contents()->GetSiteInstance(); 878 879 // Navigate to URL. First URL should use first RenderViewHost. 880 const GURL url("http://www.google.com"); 881 controller().LoadURL( 882 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 883 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 884 EXPECT_FALSE(contents()->cross_navigation_pending()); 885 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 886 887 // Navigate to new site, simulating an onbeforeunload approval. 888 const GURL url2("http://www.yahoo.com"); 889 controller().LoadURL( 890 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 891 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 892 base::TimeTicks now = base::TimeTicks::Now(); 893 orig_rvh->GetMainFrame()->OnMessageReceived( 894 FrameHostMsg_BeforeUnload_ACK(0, true, now, now)); 895 EXPECT_TRUE(contents()->cross_navigation_pending()); 896 897 // Suppose the original renderer navigates before the new one is ready. 898 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo")); 899 900 // Verify that the pending navigation is cancelled. 901 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 902 SiteInstance* instance2 = contents()->GetSiteInstance(); 903 EXPECT_FALSE(contents()->cross_navigation_pending()); 904 EXPECT_EQ(orig_rvh, rvh()); 905 EXPECT_EQ(instance1, instance2); 906 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL); 907} 908 909TEST_F(WebContentsImplTest, CrossSiteNavigationBackPreempted) { 910 // Start with a web ui page, which gets a new RVH with WebUI bindings. 911 const GURL url1("chrome://blah"); 912 controller().LoadURL( 913 url1, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 914 TestRenderViewHost* ntp_rvh = test_rvh(); 915 contents()->TestDidNavigate(ntp_rvh, 1, url1, PAGE_TRANSITION_TYPED); 916 NavigationEntry* entry1 = controller().GetLastCommittedEntry(); 917 SiteInstance* instance1 = contents()->GetSiteInstance(); 918 919 EXPECT_FALSE(contents()->cross_navigation_pending()); 920 EXPECT_EQ(ntp_rvh, contents()->GetRenderViewHost()); 921 EXPECT_EQ(url1, entry1->GetURL()); 922 EXPECT_EQ(instance1, 923 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance()); 924 EXPECT_TRUE(ntp_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI); 925 926 // Navigate to new site. 927 const GURL url2("http://www.google.com"); 928 controller().LoadURL( 929 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 930 EXPECT_TRUE(contents()->cross_navigation_pending()); 931 TestRenderViewHost* google_rvh = 932 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost()); 933 934 // Simulate beforeunload approval. 935 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack()); 936 base::TimeTicks now = base::TimeTicks::Now(); 937 ntp_rvh->GetMainFrame()->OnMessageReceived( 938 FrameHostMsg_BeforeUnload_ACK(0, true, now, now)); 939 940 // DidNavigate from the pending page. 941 contents()->TestDidNavigate( 942 google_rvh, 1, url2, PAGE_TRANSITION_TYPED); 943 NavigationEntry* entry2 = controller().GetLastCommittedEntry(); 944 SiteInstance* instance2 = contents()->GetSiteInstance(); 945 946 EXPECT_FALSE(contents()->cross_navigation_pending()); 947 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost()); 948 EXPECT_NE(instance1, instance2); 949 EXPECT_FALSE(contents()->GetPendingRenderViewHost()); 950 EXPECT_EQ(url2, entry2->GetURL()); 951 EXPECT_EQ(instance2, 952 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance()); 953 EXPECT_FALSE(google_rvh->GetEnabledBindings() & BINDINGS_POLICY_WEB_UI); 954 955 // Navigate to third page on same site. 956 const GURL url3("http://news.google.com"); 957 controller().LoadURL( 958 url3, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 959 EXPECT_FALSE(contents()->cross_navigation_pending()); 960 contents()->TestDidNavigate( 961 google_rvh, 2, url3, PAGE_TRANSITION_TYPED); 962 NavigationEntry* entry3 = controller().GetLastCommittedEntry(); 963 SiteInstance* instance3 = contents()->GetSiteInstance(); 964 965 EXPECT_FALSE(contents()->cross_navigation_pending()); 966 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost()); 967 EXPECT_EQ(instance2, instance3); 968 EXPECT_FALSE(contents()->GetPendingRenderViewHost()); 969 EXPECT_EQ(url3, entry3->GetURL()); 970 EXPECT_EQ(instance3, 971 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance()); 972 973 // Go back within the site. 974 controller().GoBack(); 975 EXPECT_FALSE(contents()->cross_navigation_pending()); 976 EXPECT_EQ(entry2, controller().GetPendingEntry()); 977 978 // Before that commits, go back again. 979 controller().GoBack(); 980 EXPECT_TRUE(contents()->cross_navigation_pending()); 981 EXPECT_TRUE(contents()->GetPendingRenderViewHost()); 982 EXPECT_EQ(entry1, controller().GetPendingEntry()); 983 984 // Simulate beforeunload approval. 985 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack()); 986 now = base::TimeTicks::Now(); 987 google_rvh->GetMainFrame()->OnMessageReceived( 988 FrameHostMsg_BeforeUnload_ACK(0, true, now, now)); 989 990 // DidNavigate from the first back. This aborts the second back's pending RVH. 991 contents()->TestDidNavigate(google_rvh, 1, url2, PAGE_TRANSITION_TYPED); 992 993 // We should commit this page and forget about the second back. 994 EXPECT_FALSE(contents()->cross_navigation_pending()); 995 EXPECT_FALSE(controller().GetPendingEntry()); 996 EXPECT_EQ(google_rvh, contents()->GetRenderViewHost()); 997 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->GetURL()); 998 999 // We should not have corrupted the NTP entry. 1000 EXPECT_EQ(instance3, 1001 NavigationEntryImpl::FromNavigationEntry(entry3)->site_instance()); 1002 EXPECT_EQ(instance2, 1003 NavigationEntryImpl::FromNavigationEntry(entry2)->site_instance()); 1004 EXPECT_EQ(instance1, 1005 NavigationEntryImpl::FromNavigationEntry(entry1)->site_instance()); 1006 EXPECT_EQ(url1, entry1->GetURL()); 1007} 1008 1009// Test that during a slow cross-site navigation, a sub-frame navigation in the 1010// original renderer will not cancel the slow navigation (bug 42029). 1011TEST_F(WebContentsImplTest, CrossSiteNavigationNotPreemptedByFrame) { 1012 TestRenderViewHost* orig_rvh = test_rvh(); 1013 1014 // Navigate to URL. First URL should use first RenderViewHost. 1015 const GURL url("http://www.google.com"); 1016 controller().LoadURL( 1017 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1018 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 1019 EXPECT_FALSE(contents()->cross_navigation_pending()); 1020 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 1021 1022 // Start navigating to new site. 1023 const GURL url2("http://www.yahoo.com"); 1024 controller().LoadURL( 1025 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1026 1027 // Simulate a sub-frame navigation arriving and ensure the RVH is still 1028 // waiting for a before unload response. 1029 orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"), 1030 PAGE_TRANSITION_AUTO_SUBFRAME); 1031 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 1032 1033 // Now simulate the onbeforeunload approval and verify the navigation is 1034 // not canceled. 1035 base::TimeTicks now = base::TimeTicks::Now(); 1036 orig_rvh->GetMainFrame()->OnMessageReceived( 1037 FrameHostMsg_BeforeUnload_ACK(0, true, now, now)); 1038 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 1039 EXPECT_TRUE(contents()->cross_navigation_pending()); 1040} 1041 1042// Test that a cross-site navigation is not preempted if the previous 1043// renderer sends a FrameNavigate message just before being told to stop. 1044// We should only preempt the cross-site navigation if the previous renderer 1045// has started a new navigation. See http://crbug.com/79176. 1046TEST_F(WebContentsImplTest, CrossSiteNotPreemptedDuringBeforeUnload) { 1047 // Navigate to NTP URL. 1048 const GURL url("chrome://blah"); 1049 controller().LoadURL( 1050 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1051 TestRenderViewHost* orig_rvh = test_rvh(); 1052 EXPECT_FALSE(contents()->cross_navigation_pending()); 1053 1054 // Navigate to new site, with the beforeunload request in flight. 1055 const GURL url2("http://www.yahoo.com"); 1056 controller().LoadURL( 1057 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1058 TestRenderViewHost* pending_rvh = 1059 static_cast<TestRenderViewHost*>(contents()->GetPendingRenderViewHost()); 1060 EXPECT_TRUE(contents()->cross_navigation_pending()); 1061 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 1062 1063 // Suppose the first navigation tries to commit now, with a 1064 // ViewMsg_Stop in flight. This should not cancel the pending navigation, 1065 // but it should act as if the beforeunload ack arrived. 1066 orig_rvh->SendNavigate(1, GURL("chrome://blah")); 1067 EXPECT_TRUE(contents()->cross_navigation_pending()); 1068 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 1069 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 1070 1071 // The pending navigation should be able to commit successfully. 1072 contents()->TestDidNavigate(pending_rvh, 1, url2, PAGE_TRANSITION_TYPED); 1073 EXPECT_FALSE(contents()->cross_navigation_pending()); 1074 EXPECT_EQ(pending_rvh, contents()->GetRenderViewHost()); 1075} 1076 1077// Test that the original renderer cannot preempt a cross-site navigation once 1078// the unload request has been made. At this point, the cross-site navigation 1079// is almost ready to be displayed, and the original renderer is only given a 1080// short chance to run an unload handler. Prevents regression of bug 23942. 1081TEST_F(WebContentsImplTest, CrossSiteCantPreemptAfterUnload) { 1082 TestRenderViewHost* orig_rvh = test_rvh(); 1083 SiteInstance* instance1 = contents()->GetSiteInstance(); 1084 1085 // Navigate to URL. First URL should use first RenderViewHost. 1086 const GURL url("http://www.google.com"); 1087 controller().LoadURL( 1088 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1089 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 1090 EXPECT_FALSE(contents()->cross_navigation_pending()); 1091 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 1092 1093 // Navigate to new site, simulating an onbeforeunload approval. 1094 const GURL url2("http://www.yahoo.com"); 1095 controller().LoadURL( 1096 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1097 base::TimeTicks now = base::TimeTicks::Now(); 1098 orig_rvh->GetMainFrame()->OnMessageReceived( 1099 FrameHostMsg_BeforeUnload_ACK(0, true, now, now)); 1100 EXPECT_TRUE(contents()->cross_navigation_pending()); 1101 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>( 1102 contents()->GetPendingRenderViewHost()); 1103 1104 // Simulate the pending renderer's response, which leads to an unload request 1105 // being sent to orig_rvh. 1106 std::vector<GURL> url_chain; 1107 url_chain.push_back(GURL()); 1108 contents()->GetRenderManagerForTesting()->OnCrossSiteResponse( 1109 contents()->GetRenderManagerForTesting()->pending_frame_host(), 1110 GlobalRequestID(0, 0), scoped_ptr<CrossSiteTransferringRequest>(), 1111 url_chain, Referrer(), PAGE_TRANSITION_TYPED, false); 1112 1113 // Suppose the original renderer navigates now, while the unload request is in 1114 // flight. We should ignore it, wait for the unload ack, and let the pending 1115 // request continue. Otherwise, the contents may close spontaneously or stop 1116 // responding to navigation requests. (See bug 23942.) 1117 FrameHostMsg_DidCommitProvisionalLoad_Params params1a; 1118 InitNavigateParams(¶ms1a, 2, GURL("http://www.google.com/foo"), 1119 PAGE_TRANSITION_TYPED); 1120 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo")); 1121 1122 // Verify that the pending navigation is still in progress. 1123 EXPECT_TRUE(contents()->cross_navigation_pending()); 1124 EXPECT_TRUE(contents()->GetPendingRenderViewHost() != NULL); 1125 1126 // DidNavigate from the pending page should commit it. 1127 contents()->TestDidNavigate( 1128 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED); 1129 SiteInstance* instance2 = contents()->GetSiteInstance(); 1130 EXPECT_FALSE(contents()->cross_navigation_pending()); 1131 EXPECT_EQ(pending_rvh, rvh()); 1132 EXPECT_NE(instance1, instance2); 1133 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL); 1134} 1135 1136// Test that a cross-site navigation that doesn't commit after the unload 1137// handler doesn't leave the contents in a stuck state. http://crbug.com/88562 1138TEST_F(WebContentsImplTest, CrossSiteNavigationCanceled) { 1139 TestRenderViewHost* orig_rvh = test_rvh(); 1140 SiteInstance* instance1 = contents()->GetSiteInstance(); 1141 1142 // Navigate to URL. First URL should use first RenderViewHost. 1143 const GURL url("http://www.google.com"); 1144 controller().LoadURL( 1145 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1146 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 1147 EXPECT_FALSE(contents()->cross_navigation_pending()); 1148 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 1149 1150 // Navigate to new site, simulating an onbeforeunload approval. 1151 const GURL url2("http://www.yahoo.com"); 1152 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1153 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 1154 base::TimeTicks now = base::TimeTicks::Now(); 1155 orig_rvh->GetMainFrame()->OnMessageReceived( 1156 FrameHostMsg_BeforeUnload_ACK(0, true, now, now)); 1157 EXPECT_TRUE(contents()->cross_navigation_pending()); 1158 1159 // Simulate swap out message when the response arrives. 1160 orig_rvh->OnSwappedOut(false); 1161 1162 // Suppose the navigation doesn't get a chance to commit, and the user 1163 // navigates in the current RVH's SiteInstance. 1164 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1165 1166 // Verify that the pending navigation is cancelled and the renderer is no 1167 // longer swapped out. 1168 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 1169 SiteInstance* instance2 = contents()->GetSiteInstance(); 1170 EXPECT_FALSE(contents()->cross_navigation_pending()); 1171 EXPECT_EQ(orig_rvh, rvh()); 1172 EXPECT_EQ(RenderViewHostImpl::STATE_DEFAULT, orig_rvh->rvh_state()); 1173 EXPECT_EQ(instance1, instance2); 1174 EXPECT_TRUE(contents()->GetPendingRenderViewHost() == NULL); 1175} 1176 1177// Test that NavigationEntries have the correct page state after going 1178// forward and back. Prevents regression for bug 1116137. 1179TEST_F(WebContentsImplTest, NavigationEntryContentState) { 1180 TestRenderViewHost* orig_rvh = test_rvh(); 1181 1182 // Navigate to URL. There should be no committed entry yet. 1183 const GURL url("http://www.google.com"); 1184 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1185 NavigationEntry* entry = controller().GetLastCommittedEntry(); 1186 EXPECT_TRUE(entry == NULL); 1187 1188 // Committed entry should have page state after DidNavigate. 1189 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 1190 entry = controller().GetLastCommittedEntry(); 1191 EXPECT_TRUE(entry->GetPageState().IsValid()); 1192 1193 // Navigate to same site. 1194 const GURL url2("http://images.google.com"); 1195 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1196 entry = controller().GetLastCommittedEntry(); 1197 EXPECT_TRUE(entry->GetPageState().IsValid()); 1198 1199 // Committed entry should have page state after DidNavigate. 1200 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED); 1201 entry = controller().GetLastCommittedEntry(); 1202 EXPECT_TRUE(entry->GetPageState().IsValid()); 1203 1204 // Now go back. Committed entry should still have page state. 1205 controller().GoBack(); 1206 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 1207 entry = controller().GetLastCommittedEntry(); 1208 EXPECT_TRUE(entry->GetPageState().IsValid()); 1209} 1210 1211// Test that NavigationEntries have the correct page state and SiteInstance 1212// state after opening a new window to about:blank. Prevents regression for 1213// bugs b/1116137 and http://crbug.com/111975. 1214TEST_F(WebContentsImplTest, NavigationEntryContentStateNewWindow) { 1215 TestRenderViewHost* orig_rvh = test_rvh(); 1216 1217 // When opening a new window, it is navigated to about:blank internally. 1218 // Currently, this results in two DidNavigate events. 1219 const GURL url(url::kAboutBlankURL); 1220 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 1221 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 1222 1223 // Should have a page state here. 1224 NavigationEntry* entry = controller().GetLastCommittedEntry(); 1225 EXPECT_TRUE(entry->GetPageState().IsValid()); 1226 1227 // The SiteInstance should be available for other navigations to use. 1228 NavigationEntryImpl* entry_impl = 1229 NavigationEntryImpl::FromNavigationEntry(entry); 1230 EXPECT_FALSE(entry_impl->site_instance()->HasSite()); 1231 int32 site_instance_id = entry_impl->site_instance()->GetId(); 1232 1233 // Navigating to a normal page should not cause a process swap. 1234 const GURL new_url("http://www.google.com"); 1235 controller().LoadURL(new_url, Referrer(), 1236 PAGE_TRANSITION_TYPED, std::string()); 1237 EXPECT_FALSE(contents()->cross_navigation_pending()); 1238 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 1239 contents()->TestDidNavigate(orig_rvh, 1, new_url, PAGE_TRANSITION_TYPED); 1240 NavigationEntryImpl* entry_impl2 = NavigationEntryImpl::FromNavigationEntry( 1241 controller().GetLastCommittedEntry()); 1242 EXPECT_EQ(site_instance_id, entry_impl2->site_instance()->GetId()); 1243 EXPECT_TRUE(entry_impl2->site_instance()->HasSite()); 1244} 1245 1246// Tests that fullscreen is exited throughout the object hierarchy when 1247// navigating to a new page. 1248TEST_F(WebContentsImplTest, NavigationExitsFullscreen) { 1249 FakeFullscreenDelegate fake_delegate; 1250 contents()->SetDelegate(&fake_delegate); 1251 TestRenderViewHost* orig_rvh = test_rvh(); 1252 1253 // Navigate to a site. 1254 const GURL url("http://www.google.com"); 1255 controller().LoadURL( 1256 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1257 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 1258 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 1259 1260 // Toggle fullscreen mode on (as if initiated via IPC from renderer). 1261 EXPECT_FALSE(orig_rvh->IsFullscreen()); 1262 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); 1263 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); 1264 orig_rvh->OnMessageReceived( 1265 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true)); 1266 EXPECT_TRUE(orig_rvh->IsFullscreen()); 1267 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab()); 1268 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents())); 1269 1270 // Navigate to a new site. 1271 const GURL url2("http://www.yahoo.com"); 1272 controller().LoadURL( 1273 url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1274 RenderViewHost* const pending_rvh = contents()->GetPendingRenderViewHost(); 1275 contents()->TestDidNavigate( 1276 pending_rvh, 1, url2, PAGE_TRANSITION_TYPED); 1277 1278 // Confirm fullscreen has exited. 1279 EXPECT_FALSE(orig_rvh->IsFullscreen()); 1280 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); 1281 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); 1282 1283 contents()->SetDelegate(NULL); 1284} 1285 1286// Tests that fullscreen is exited throughout the object hierarchy when 1287// instructing NavigationController to GoBack() or GoForward(). 1288TEST_F(WebContentsImplTest, HistoryNavigationExitsFullscreen) { 1289 FakeFullscreenDelegate fake_delegate; 1290 contents()->SetDelegate(&fake_delegate); 1291 TestRenderViewHost* const orig_rvh = test_rvh(); 1292 1293 // Navigate to a site. 1294 const GURL url("http://www.google.com"); 1295 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1296 contents()->TestDidNavigate(orig_rvh, 1, url, PAGE_TRANSITION_TYPED); 1297 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 1298 1299 // Now, navigate to another page on the same site. 1300 const GURL url2("http://www.google.com/search?q=kittens"); 1301 controller().LoadURL(url2, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1302 EXPECT_FALSE(contents()->cross_navigation_pending()); 1303 contents()->TestDidNavigate(orig_rvh, 2, url2, PAGE_TRANSITION_TYPED); 1304 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 1305 1306 // Sanity-check: Confirm we're not starting out in fullscreen mode. 1307 EXPECT_FALSE(orig_rvh->IsFullscreen()); 1308 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); 1309 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); 1310 1311 for (int i = 0; i < 2; ++i) { 1312 // Toggle fullscreen mode on (as if initiated via IPC from renderer). 1313 orig_rvh->OnMessageReceived( 1314 ViewHostMsg_ToggleFullscreen(orig_rvh->GetRoutingID(), true)); 1315 EXPECT_TRUE(orig_rvh->IsFullscreen()); 1316 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab()); 1317 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents())); 1318 1319 // Navigate backward (or forward). 1320 if (i == 0) 1321 controller().GoBack(); 1322 else 1323 controller().GoForward(); 1324 EXPECT_FALSE(contents()->cross_navigation_pending()); 1325 EXPECT_EQ(orig_rvh, contents()->GetRenderViewHost()); 1326 contents()->TestDidNavigate( 1327 orig_rvh, i + 1, url, PAGE_TRANSITION_FORWARD_BACK); 1328 1329 // Confirm fullscreen has exited. 1330 EXPECT_FALSE(orig_rvh->IsFullscreen()); 1331 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); 1332 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); 1333 } 1334 1335 contents()->SetDelegate(NULL); 1336} 1337 1338// Tests that fullscreen is exited throughout the object hierarchy on a renderer 1339// crash. 1340TEST_F(WebContentsImplTest, CrashExitsFullscreen) { 1341 FakeFullscreenDelegate fake_delegate; 1342 contents()->SetDelegate(&fake_delegate); 1343 1344 // Navigate to a site. 1345 const GURL url("http://www.google.com"); 1346 controller().LoadURL( 1347 url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 1348 contents()->TestDidNavigate(test_rvh(), 1, url, PAGE_TRANSITION_TYPED); 1349 EXPECT_EQ(test_rvh(), contents()->GetRenderViewHost()); 1350 1351 // Toggle fullscreen mode on (as if initiated via IPC from renderer). 1352 EXPECT_FALSE(test_rvh()->IsFullscreen()); 1353 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); 1354 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); 1355 test_rvh()->OnMessageReceived( 1356 ViewHostMsg_ToggleFullscreen(test_rvh()->GetRoutingID(), true)); 1357 EXPECT_TRUE(test_rvh()->IsFullscreen()); 1358 EXPECT_TRUE(contents()->IsFullscreenForCurrentTab()); 1359 EXPECT_TRUE(fake_delegate.IsFullscreenForTabOrPending(contents())); 1360 1361 // Crash the renderer. 1362 test_rvh()->OnMessageReceived( 1363 ViewHostMsg_RenderProcessGone( 1364 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1)); 1365 1366 // Confirm fullscreen has exited. 1367 EXPECT_FALSE(test_rvh()->IsFullscreen()); 1368 EXPECT_FALSE(contents()->IsFullscreenForCurrentTab()); 1369 EXPECT_FALSE(fake_delegate.IsFullscreenForTabOrPending(contents())); 1370 1371 contents()->SetDelegate(NULL); 1372} 1373 1374//////////////////////////////////////////////////////////////////////////////// 1375// Interstitial Tests 1376//////////////////////////////////////////////////////////////////////////////// 1377 1378// Test navigating to a page (with the navigation initiated from the browser, 1379// as when a URL is typed in the location bar) that shows an interstitial and 1380// creates a new navigation entry, then hiding it without proceeding. 1381TEST_F(WebContentsImplTest, 1382 ShowInterstitialFromBrowserWithNewNavigationDontProceed) { 1383 // Navigate to a page. 1384 GURL url1("http://www.google.com"); 1385 test_rvh()->SendNavigate(1, url1); 1386 EXPECT_EQ(1, controller().GetEntryCount()); 1387 1388 // Initiate a browser navigation that will trigger the interstitial 1389 controller().LoadURL(GURL("http://www.evil.com"), Referrer(), 1390 PAGE_TRANSITION_TYPED, std::string()); 1391 1392 // Show an interstitial. 1393 TestInterstitialPage::InterstitialState state = 1394 TestInterstitialPage::INVALID; 1395 bool deleted = false; 1396 GURL url2("http://interstitial"); 1397 TestInterstitialPage* interstitial = 1398 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 1399 TestInterstitialPageStateGuard state_guard(interstitial); 1400 interstitial->Show(); 1401 // The interstitial should not show until its navigation has committed. 1402 EXPECT_FALSE(interstitial->is_showing()); 1403 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1404 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1405 // Let's commit the interstitial navigation. 1406 interstitial->TestDidNavigate(1, url2); 1407 EXPECT_TRUE(interstitial->is_showing()); 1408 EXPECT_TRUE(contents()->ShowingInterstitialPage()); 1409 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial); 1410 NavigationEntry* entry = controller().GetVisibleEntry(); 1411 ASSERT_TRUE(entry != NULL); 1412 EXPECT_TRUE(entry->GetURL() == url2); 1413 1414 // Now don't proceed. 1415 interstitial->DontProceed(); 1416 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1417 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1418 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1419 entry = controller().GetVisibleEntry(); 1420 ASSERT_TRUE(entry != NULL); 1421 EXPECT_TRUE(entry->GetURL() == url1); 1422 EXPECT_EQ(1, controller().GetEntryCount()); 1423 1424 RunAllPendingInMessageLoop(); 1425 EXPECT_TRUE(deleted); 1426} 1427 1428// Test navigating to a page (with the navigation initiated from the renderer, 1429// as when clicking on a link in the page) that shows an interstitial and 1430// creates a new navigation entry, then hiding it without proceeding. 1431TEST_F(WebContentsImplTest, 1432 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) { 1433 // Navigate to a page. 1434 GURL url1("http://www.google.com"); 1435 test_rvh()->SendNavigate(1, url1); 1436 EXPECT_EQ(1, controller().GetEntryCount()); 1437 1438 // Show an interstitial (no pending entry, the interstitial would have been 1439 // triggered by clicking on a link). 1440 TestInterstitialPage::InterstitialState state = 1441 TestInterstitialPage::INVALID; 1442 bool deleted = false; 1443 GURL url2("http://interstitial"); 1444 TestInterstitialPage* interstitial = 1445 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 1446 TestInterstitialPageStateGuard state_guard(interstitial); 1447 interstitial->Show(); 1448 // The interstitial should not show until its navigation has committed. 1449 EXPECT_FALSE(interstitial->is_showing()); 1450 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1451 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1452 // Let's commit the interstitial navigation. 1453 interstitial->TestDidNavigate(1, url2); 1454 EXPECT_TRUE(interstitial->is_showing()); 1455 EXPECT_TRUE(contents()->ShowingInterstitialPage()); 1456 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial); 1457 NavigationEntry* entry = controller().GetVisibleEntry(); 1458 ASSERT_TRUE(entry != NULL); 1459 EXPECT_TRUE(entry->GetURL() == url2); 1460 1461 // Now don't proceed. 1462 interstitial->DontProceed(); 1463 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1464 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1465 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1466 entry = controller().GetVisibleEntry(); 1467 ASSERT_TRUE(entry != NULL); 1468 EXPECT_TRUE(entry->GetURL() == url1); 1469 EXPECT_EQ(1, controller().GetEntryCount()); 1470 1471 RunAllPendingInMessageLoop(); 1472 EXPECT_TRUE(deleted); 1473} 1474 1475// Test navigating to a page that shows an interstitial without creating a new 1476// navigation entry (this happens when the interstitial is triggered by a 1477// sub-resource in the page), then hiding it without proceeding. 1478TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationDontProceed) { 1479 // Navigate to a page. 1480 GURL url1("http://www.google.com"); 1481 test_rvh()->SendNavigate(1, url1); 1482 EXPECT_EQ(1, controller().GetEntryCount()); 1483 1484 // Show an interstitial. 1485 TestInterstitialPage::InterstitialState state = 1486 TestInterstitialPage::INVALID; 1487 bool deleted = false; 1488 GURL url2("http://interstitial"); 1489 TestInterstitialPage* interstitial = 1490 new TestInterstitialPage(contents(), false, url2, &state, &deleted); 1491 TestInterstitialPageStateGuard state_guard(interstitial); 1492 interstitial->Show(); 1493 // The interstitial should not show until its navigation has committed. 1494 EXPECT_FALSE(interstitial->is_showing()); 1495 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1496 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1497 // Let's commit the interstitial navigation. 1498 interstitial->TestDidNavigate(1, url2); 1499 EXPECT_TRUE(interstitial->is_showing()); 1500 EXPECT_TRUE(contents()->ShowingInterstitialPage()); 1501 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial); 1502 NavigationEntry* entry = controller().GetVisibleEntry(); 1503 ASSERT_TRUE(entry != NULL); 1504 // The URL specified to the interstitial should have been ignored. 1505 EXPECT_TRUE(entry->GetURL() == url1); 1506 1507 // Now don't proceed. 1508 interstitial->DontProceed(); 1509 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1510 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1511 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1512 entry = controller().GetVisibleEntry(); 1513 ASSERT_TRUE(entry != NULL); 1514 EXPECT_TRUE(entry->GetURL() == url1); 1515 EXPECT_EQ(1, controller().GetEntryCount()); 1516 1517 RunAllPendingInMessageLoop(); 1518 EXPECT_TRUE(deleted); 1519} 1520 1521// Test navigating to a page (with the navigation initiated from the browser, 1522// as when a URL is typed in the location bar) that shows an interstitial and 1523// creates a new navigation entry, then proceeding. 1524TEST_F(WebContentsImplTest, 1525 ShowInterstitialFromBrowserNewNavigationProceed) { 1526 // Navigate to a page. 1527 GURL url1("http://www.google.com"); 1528 test_rvh()->SendNavigate(1, url1); 1529 EXPECT_EQ(1, controller().GetEntryCount()); 1530 1531 // Initiate a browser navigation that will trigger the interstitial 1532 controller().LoadURL(GURL("http://www.evil.com"), Referrer(), 1533 PAGE_TRANSITION_TYPED, std::string()); 1534 1535 // Show an interstitial. 1536 TestInterstitialPage::InterstitialState state = 1537 TestInterstitialPage::INVALID; 1538 bool deleted = false; 1539 GURL url2("http://interstitial"); 1540 TestInterstitialPage* interstitial = 1541 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 1542 TestInterstitialPageStateGuard state_guard(interstitial); 1543 interstitial->Show(); 1544 // The interstitial should not show until its navigation has committed. 1545 EXPECT_FALSE(interstitial->is_showing()); 1546 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1547 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1548 // Let's commit the interstitial navigation. 1549 interstitial->TestDidNavigate(1, url2); 1550 EXPECT_TRUE(interstitial->is_showing()); 1551 EXPECT_TRUE(contents()->ShowingInterstitialPage()); 1552 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial); 1553 NavigationEntry* entry = controller().GetVisibleEntry(); 1554 ASSERT_TRUE(entry != NULL); 1555 EXPECT_TRUE(entry->GetURL() == url2); 1556 1557 // Then proceed. 1558 interstitial->Proceed(); 1559 // The interstitial should show until the new navigation commits. 1560 RunAllPendingInMessageLoop(); 1561 ASSERT_FALSE(deleted); 1562 EXPECT_EQ(TestInterstitialPage::OKED, state); 1563 EXPECT_TRUE(contents()->ShowingInterstitialPage()); 1564 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial); 1565 1566 // Simulate the navigation to the page, that's when the interstitial gets 1567 // hidden. 1568 GURL url3("http://www.thepage.com"); 1569 test_rvh()->SendNavigate(2, url3); 1570 1571 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1572 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1573 entry = controller().GetVisibleEntry(); 1574 ASSERT_TRUE(entry != NULL); 1575 EXPECT_TRUE(entry->GetURL() == url3); 1576 1577 EXPECT_EQ(2, controller().GetEntryCount()); 1578 1579 RunAllPendingInMessageLoop(); 1580 EXPECT_TRUE(deleted); 1581} 1582 1583// Test navigating to a page (with the navigation initiated from the renderer, 1584// as when clicking on a link in the page) that shows an interstitial and 1585// creates a new navigation entry, then proceeding. 1586TEST_F(WebContentsImplTest, 1587 ShowInterstitialFromRendererNewNavigationProceed) { 1588 // Navigate to a page. 1589 GURL url1("http://www.google.com"); 1590 test_rvh()->SendNavigate(1, url1); 1591 EXPECT_EQ(1, controller().GetEntryCount()); 1592 1593 // Show an interstitial. 1594 TestInterstitialPage::InterstitialState state = 1595 TestInterstitialPage::INVALID; 1596 bool deleted = false; 1597 GURL url2("http://interstitial"); 1598 TestInterstitialPage* interstitial = 1599 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 1600 TestInterstitialPageStateGuard state_guard(interstitial); 1601 interstitial->Show(); 1602 // The interstitial should not show until its navigation has committed. 1603 EXPECT_FALSE(interstitial->is_showing()); 1604 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1605 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1606 // Let's commit the interstitial navigation. 1607 interstitial->TestDidNavigate(1, url2); 1608 EXPECT_TRUE(interstitial->is_showing()); 1609 EXPECT_TRUE(contents()->ShowingInterstitialPage()); 1610 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial); 1611 NavigationEntry* entry = controller().GetVisibleEntry(); 1612 ASSERT_TRUE(entry != NULL); 1613 EXPECT_TRUE(entry->GetURL() == url2); 1614 1615 // Then proceed. 1616 interstitial->Proceed(); 1617 // The interstitial should show until the new navigation commits. 1618 RunAllPendingInMessageLoop(); 1619 ASSERT_FALSE(deleted); 1620 EXPECT_EQ(TestInterstitialPage::OKED, state); 1621 EXPECT_TRUE(contents()->ShowingInterstitialPage()); 1622 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial); 1623 1624 // Simulate the navigation to the page, that's when the interstitial gets 1625 // hidden. 1626 GURL url3("http://www.thepage.com"); 1627 test_rvh()->SendNavigate(2, url3); 1628 1629 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1630 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1631 entry = controller().GetVisibleEntry(); 1632 ASSERT_TRUE(entry != NULL); 1633 EXPECT_TRUE(entry->GetURL() == url3); 1634 1635 EXPECT_EQ(2, controller().GetEntryCount()); 1636 1637 RunAllPendingInMessageLoop(); 1638 EXPECT_TRUE(deleted); 1639} 1640 1641// Test navigating to a page that shows an interstitial without creating a new 1642// navigation entry (this happens when the interstitial is triggered by a 1643// sub-resource in the page), then proceeding. 1644TEST_F(WebContentsImplTest, ShowInterstitialNoNewNavigationProceed) { 1645 // Navigate to a page so we have a navigation entry in the controller. 1646 GURL url1("http://www.google.com"); 1647 test_rvh()->SendNavigate(1, url1); 1648 EXPECT_EQ(1, controller().GetEntryCount()); 1649 1650 // Show an interstitial. 1651 TestInterstitialPage::InterstitialState state = 1652 TestInterstitialPage::INVALID; 1653 bool deleted = false; 1654 GURL url2("http://interstitial"); 1655 TestInterstitialPage* interstitial = 1656 new TestInterstitialPage(contents(), false, url2, &state, &deleted); 1657 TestInterstitialPageStateGuard state_guard(interstitial); 1658 interstitial->Show(); 1659 // The interstitial should not show until its navigation has committed. 1660 EXPECT_FALSE(interstitial->is_showing()); 1661 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1662 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1663 // Let's commit the interstitial navigation. 1664 interstitial->TestDidNavigate(1, url2); 1665 EXPECT_TRUE(interstitial->is_showing()); 1666 EXPECT_TRUE(contents()->ShowingInterstitialPage()); 1667 EXPECT_TRUE(contents()->GetInterstitialPage() == interstitial); 1668 NavigationEntry* entry = controller().GetVisibleEntry(); 1669 ASSERT_TRUE(entry != NULL); 1670 // The URL specified to the interstitial should have been ignored. 1671 EXPECT_TRUE(entry->GetURL() == url1); 1672 1673 // Then proceed. 1674 interstitial->Proceed(); 1675 // Since this is not a new navigation, the previous page is dismissed right 1676 // away and shows the original page. 1677 EXPECT_EQ(TestInterstitialPage::OKED, state); 1678 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1679 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1680 entry = controller().GetVisibleEntry(); 1681 ASSERT_TRUE(entry != NULL); 1682 EXPECT_TRUE(entry->GetURL() == url1); 1683 1684 EXPECT_EQ(1, controller().GetEntryCount()); 1685 1686 RunAllPendingInMessageLoop(); 1687 EXPECT_TRUE(deleted); 1688} 1689 1690// Test navigating to a page that shows an interstitial, then navigating away. 1691TEST_F(WebContentsImplTest, ShowInterstitialThenNavigate) { 1692 // Show interstitial. 1693 TestInterstitialPage::InterstitialState state = 1694 TestInterstitialPage::INVALID; 1695 bool deleted = false; 1696 GURL url("http://interstitial"); 1697 TestInterstitialPage* interstitial = 1698 new TestInterstitialPage(contents(), true, url, &state, &deleted); 1699 TestInterstitialPageStateGuard state_guard(interstitial); 1700 interstitial->Show(); 1701 interstitial->TestDidNavigate(1, url); 1702 1703 // While interstitial showing, navigate to a new URL. 1704 const GURL url2("http://www.yahoo.com"); 1705 test_rvh()->SendNavigate(1, url2); 1706 1707 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1708 1709 RunAllPendingInMessageLoop(); 1710 EXPECT_TRUE(deleted); 1711} 1712 1713// Test navigating to a page that shows an interstitial, then going back. 1714TEST_F(WebContentsImplTest, ShowInterstitialThenGoBack) { 1715 // Navigate to a page so we have a navigation entry in the controller. 1716 GURL url1("http://www.google.com"); 1717 test_rvh()->SendNavigate(1, url1); 1718 EXPECT_EQ(1, controller().GetEntryCount()); 1719 1720 // Show interstitial. 1721 TestInterstitialPage::InterstitialState state = 1722 TestInterstitialPage::INVALID; 1723 bool deleted = false; 1724 GURL interstitial_url("http://interstitial"); 1725 TestInterstitialPage* interstitial = 1726 new TestInterstitialPage(contents(), true, interstitial_url, 1727 &state, &deleted); 1728 TestInterstitialPageStateGuard state_guard(interstitial); 1729 interstitial->Show(); 1730 interstitial->TestDidNavigate(2, interstitial_url); 1731 1732 // While the interstitial is showing, go back. 1733 controller().GoBack(); 1734 test_rvh()->SendNavigate(1, url1); 1735 1736 // Make sure we are back to the original page and that the interstitial is 1737 // gone. 1738 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1739 NavigationEntry* entry = controller().GetVisibleEntry(); 1740 ASSERT_TRUE(entry); 1741 EXPECT_EQ(url1.spec(), entry->GetURL().spec()); 1742 1743 RunAllPendingInMessageLoop(); 1744 EXPECT_TRUE(deleted); 1745} 1746 1747// Test navigating to a page that shows an interstitial, has a renderer crash, 1748// and then goes back. 1749TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenGoBack) { 1750 // Navigate to a page so we have a navigation entry in the controller. 1751 GURL url1("http://www.google.com"); 1752 test_rvh()->SendNavigate(1, url1); 1753 EXPECT_EQ(1, controller().GetEntryCount()); 1754 1755 // Show interstitial. 1756 TestInterstitialPage::InterstitialState state = 1757 TestInterstitialPage::INVALID; 1758 bool deleted = false; 1759 GURL interstitial_url("http://interstitial"); 1760 TestInterstitialPage* interstitial = 1761 new TestInterstitialPage(contents(), true, interstitial_url, 1762 &state, &deleted); 1763 TestInterstitialPageStateGuard state_guard(interstitial); 1764 interstitial->Show(); 1765 interstitial->TestDidNavigate(2, interstitial_url); 1766 1767 // Crash the renderer 1768 test_rvh()->OnMessageReceived( 1769 ViewHostMsg_RenderProcessGone( 1770 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1)); 1771 1772 // While the interstitial is showing, go back. 1773 controller().GoBack(); 1774 test_rvh()->SendNavigate(1, url1); 1775 1776 // Make sure we are back to the original page and that the interstitial is 1777 // gone. 1778 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1779 NavigationEntry* entry = controller().GetVisibleEntry(); 1780 ASSERT_TRUE(entry); 1781 EXPECT_EQ(url1.spec(), entry->GetURL().spec()); 1782 1783 RunAllPendingInMessageLoop(); 1784 EXPECT_TRUE(deleted); 1785} 1786 1787// Test navigating to a page that shows an interstitial, has the renderer crash, 1788// and then navigates to the interstitial. 1789TEST_F(WebContentsImplTest, ShowInterstitialCrashRendererThenNavigate) { 1790 // Navigate to a page so we have a navigation entry in the controller. 1791 GURL url1("http://www.google.com"); 1792 test_rvh()->SendNavigate(1, url1); 1793 EXPECT_EQ(1, controller().GetEntryCount()); 1794 1795 // Show interstitial. 1796 TestInterstitialPage::InterstitialState state = 1797 TestInterstitialPage::INVALID; 1798 bool deleted = false; 1799 GURL interstitial_url("http://interstitial"); 1800 TestInterstitialPage* interstitial = 1801 new TestInterstitialPage(contents(), true, interstitial_url, 1802 &state, &deleted); 1803 TestInterstitialPageStateGuard state_guard(interstitial); 1804 interstitial->Show(); 1805 1806 // Crash the renderer 1807 test_rvh()->OnMessageReceived( 1808 ViewHostMsg_RenderProcessGone( 1809 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1)); 1810 1811 interstitial->TestDidNavigate(2, interstitial_url); 1812} 1813 1814// Test navigating to a page that shows an interstitial, then close the 1815// contents. 1816TEST_F(WebContentsImplTest, ShowInterstitialThenCloseTab) { 1817 // Show interstitial. 1818 TestInterstitialPage::InterstitialState state = 1819 TestInterstitialPage::INVALID; 1820 bool deleted = false; 1821 GURL url("http://interstitial"); 1822 TestInterstitialPage* interstitial = 1823 new TestInterstitialPage(contents(), true, url, &state, &deleted); 1824 TestInterstitialPageStateGuard state_guard(interstitial); 1825 interstitial->Show(); 1826 interstitial->TestDidNavigate(1, url); 1827 1828 // Now close the contents. 1829 DeleteContents(); 1830 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1831 1832 RunAllPendingInMessageLoop(); 1833 EXPECT_TRUE(deleted); 1834} 1835 1836// Test navigating to a page that shows an interstitial, then close the 1837// contents. 1838TEST_F(WebContentsImplTest, ShowInterstitialThenCloseAndShutdown) { 1839 // Show interstitial. 1840 TestInterstitialPage::InterstitialState state = 1841 TestInterstitialPage::INVALID; 1842 bool deleted = false; 1843 GURL url("http://interstitial"); 1844 TestInterstitialPage* interstitial = 1845 new TestInterstitialPage(contents(), true, url, &state, &deleted); 1846 TestInterstitialPageStateGuard state_guard(interstitial); 1847 interstitial->Show(); 1848 interstitial->TestDidNavigate(1, url); 1849 RenderViewHostImpl* rvh = static_cast<RenderViewHostImpl*>( 1850 interstitial->GetRenderViewHostForTesting()); 1851 1852 // Now close the contents. 1853 DeleteContents(); 1854 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1855 1856 // Before the interstitial has a chance to process its shutdown task, 1857 // simulate quitting the browser. This goes through all processes and 1858 // tells them to destruct. 1859 rvh->OnMessageReceived( 1860 ViewHostMsg_RenderProcessGone(0, 0, 0)); 1861 1862 RunAllPendingInMessageLoop(); 1863 EXPECT_TRUE(deleted); 1864} 1865 1866// Test that after Proceed is called and an interstitial is still shown, no more 1867// commands get executed. 1868TEST_F(WebContentsImplTest, ShowInterstitialProceedMultipleCommands) { 1869 // Navigate to a page so we have a navigation entry in the controller. 1870 GURL url1("http://www.google.com"); 1871 test_rvh()->SendNavigate(1, url1); 1872 EXPECT_EQ(1, controller().GetEntryCount()); 1873 1874 // Show an interstitial. 1875 TestInterstitialPage::InterstitialState state = 1876 TestInterstitialPage::INVALID; 1877 bool deleted = false; 1878 GURL url2("http://interstitial"); 1879 TestInterstitialPage* interstitial = 1880 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 1881 TestInterstitialPageStateGuard state_guard(interstitial); 1882 interstitial->Show(); 1883 interstitial->TestDidNavigate(1, url2); 1884 1885 // Run a command. 1886 EXPECT_EQ(0, interstitial->command_received_count()); 1887 interstitial->TestDomOperationResponse("toto"); 1888 EXPECT_EQ(1, interstitial->command_received_count()); 1889 1890 // Then proceed. 1891 interstitial->Proceed(); 1892 RunAllPendingInMessageLoop(); 1893 ASSERT_FALSE(deleted); 1894 1895 // While the navigation to the new page is pending, send other commands, they 1896 // should be ignored. 1897 interstitial->TestDomOperationResponse("hello"); 1898 interstitial->TestDomOperationResponse("hi"); 1899 EXPECT_EQ(1, interstitial->command_received_count()); 1900} 1901 1902// Test showing an interstitial while another interstitial is already showing. 1903TEST_F(WebContentsImplTest, ShowInterstitialOnInterstitial) { 1904 // Navigate to a page so we have a navigation entry in the controller. 1905 GURL start_url("http://www.google.com"); 1906 test_rvh()->SendNavigate(1, start_url); 1907 EXPECT_EQ(1, controller().GetEntryCount()); 1908 1909 // Show an interstitial. 1910 TestInterstitialPage::InterstitialState state1 = 1911 TestInterstitialPage::INVALID; 1912 bool deleted1 = false; 1913 GURL url1("http://interstitial1"); 1914 TestInterstitialPage* interstitial1 = 1915 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1); 1916 TestInterstitialPageStateGuard state_guard1(interstitial1); 1917 interstitial1->Show(); 1918 interstitial1->TestDidNavigate(1, url1); 1919 1920 // Now show another interstitial. 1921 TestInterstitialPage::InterstitialState state2 = 1922 TestInterstitialPage::INVALID; 1923 bool deleted2 = false; 1924 GURL url2("http://interstitial2"); 1925 TestInterstitialPage* interstitial2 = 1926 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2); 1927 TestInterstitialPageStateGuard state_guard2(interstitial2); 1928 interstitial2->Show(); 1929 interstitial2->TestDidNavigate(1, url2); 1930 1931 // Showing interstitial2 should have caused interstitial1 to go away. 1932 EXPECT_EQ(TestInterstitialPage::CANCELED, state1); 1933 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2); 1934 1935 RunAllPendingInMessageLoop(); 1936 EXPECT_TRUE(deleted1); 1937 ASSERT_FALSE(deleted2); 1938 1939 // Let's make sure interstitial2 is working as intended. 1940 interstitial2->Proceed(); 1941 GURL landing_url("http://www.thepage.com"); 1942 test_rvh()->SendNavigate(2, landing_url); 1943 1944 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 1945 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 1946 NavigationEntry* entry = controller().GetVisibleEntry(); 1947 ASSERT_TRUE(entry != NULL); 1948 EXPECT_TRUE(entry->GetURL() == landing_url); 1949 EXPECT_EQ(2, controller().GetEntryCount()); 1950 RunAllPendingInMessageLoop(); 1951 EXPECT_TRUE(deleted2); 1952} 1953 1954// Test showing an interstitial, proceeding and then navigating to another 1955// interstitial. 1956TEST_F(WebContentsImplTest, ShowInterstitialProceedShowInterstitial) { 1957 // Navigate to a page so we have a navigation entry in the controller. 1958 GURL start_url("http://www.google.com"); 1959 test_rvh()->SendNavigate(1, start_url); 1960 EXPECT_EQ(1, controller().GetEntryCount()); 1961 1962 // Show an interstitial. 1963 TestInterstitialPage::InterstitialState state1 = 1964 TestInterstitialPage::INVALID; 1965 bool deleted1 = false; 1966 GURL url1("http://interstitial1"); 1967 TestInterstitialPage* interstitial1 = 1968 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1); 1969 TestInterstitialPageStateGuard state_guard1(interstitial1); 1970 interstitial1->Show(); 1971 interstitial1->TestDidNavigate(1, url1); 1972 1973 // Take action. The interstitial won't be hidden until the navigation is 1974 // committed. 1975 interstitial1->Proceed(); 1976 EXPECT_EQ(TestInterstitialPage::OKED, state1); 1977 1978 // Now show another interstitial (simulating the navigation causing another 1979 // interstitial). 1980 TestInterstitialPage::InterstitialState state2 = 1981 TestInterstitialPage::INVALID; 1982 bool deleted2 = false; 1983 GURL url2("http://interstitial2"); 1984 TestInterstitialPage* interstitial2 = 1985 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2); 1986 TestInterstitialPageStateGuard state_guard2(interstitial2); 1987 interstitial2->Show(); 1988 interstitial2->TestDidNavigate(1, url2); 1989 1990 // Showing interstitial2 should have caused interstitial1 to go away. 1991 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2); 1992 RunAllPendingInMessageLoop(); 1993 EXPECT_TRUE(deleted1); 1994 ASSERT_FALSE(deleted2); 1995 1996 // Let's make sure interstitial2 is working as intended. 1997 interstitial2->Proceed(); 1998 GURL landing_url("http://www.thepage.com"); 1999 test_rvh()->SendNavigate(2, landing_url); 2000 2001 RunAllPendingInMessageLoop(); 2002 EXPECT_TRUE(deleted2); 2003 EXPECT_FALSE(contents()->ShowingInterstitialPage()); 2004 EXPECT_TRUE(contents()->GetInterstitialPage() == NULL); 2005 NavigationEntry* entry = controller().GetVisibleEntry(); 2006 ASSERT_TRUE(entry != NULL); 2007 EXPECT_TRUE(entry->GetURL() == landing_url); 2008 EXPECT_EQ(2, controller().GetEntryCount()); 2009} 2010 2011// Test that navigating away from an interstitial while it's loading cause it 2012// not to show. 2013TEST_F(WebContentsImplTest, NavigateBeforeInterstitialShows) { 2014 // Show an interstitial. 2015 TestInterstitialPage::InterstitialState state = 2016 TestInterstitialPage::INVALID; 2017 bool deleted = false; 2018 GURL interstitial_url("http://interstitial"); 2019 TestInterstitialPage* interstitial = 2020 new TestInterstitialPage(contents(), true, interstitial_url, 2021 &state, &deleted); 2022 TestInterstitialPageStateGuard state_guard(interstitial); 2023 interstitial->Show(); 2024 2025 // Let's simulate a navigation initiated from the browser before the 2026 // interstitial finishes loading. 2027 const GURL url("http://www.google.com"); 2028 controller().LoadURL(url, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 2029 EXPECT_FALSE(interstitial->is_showing()); 2030 RunAllPendingInMessageLoop(); 2031 ASSERT_FALSE(deleted); 2032 2033 // Now let's make the interstitial navigation commit. 2034 interstitial->TestDidNavigate(1, interstitial_url); 2035 2036 // After it loaded the interstitial should be gone. 2037 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 2038 2039 RunAllPendingInMessageLoop(); 2040 EXPECT_TRUE(deleted); 2041} 2042 2043// Test that a new request to show an interstitial while an interstitial is 2044// pending does not cause problems. htp://crbug/29655 and htp://crbug/9442. 2045TEST_F(WebContentsImplTest, TwoQuickInterstitials) { 2046 GURL interstitial_url("http://interstitial"); 2047 2048 // Show a first interstitial. 2049 TestInterstitialPage::InterstitialState state1 = 2050 TestInterstitialPage::INVALID; 2051 bool deleted1 = false; 2052 TestInterstitialPage* interstitial1 = 2053 new TestInterstitialPage(contents(), true, interstitial_url, 2054 &state1, &deleted1); 2055 TestInterstitialPageStateGuard state_guard1(interstitial1); 2056 interstitial1->Show(); 2057 2058 // Show another interstitial on that same contents before the first one had 2059 // time to load. 2060 TestInterstitialPage::InterstitialState state2 = 2061 TestInterstitialPage::INVALID; 2062 bool deleted2 = false; 2063 TestInterstitialPage* interstitial2 = 2064 new TestInterstitialPage(contents(), true, interstitial_url, 2065 &state2, &deleted2); 2066 TestInterstitialPageStateGuard state_guard2(interstitial2); 2067 interstitial2->Show(); 2068 2069 // The first interstitial should have been closed and deleted. 2070 EXPECT_EQ(TestInterstitialPage::CANCELED, state1); 2071 // The 2nd one should still be OK. 2072 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2); 2073 2074 RunAllPendingInMessageLoop(); 2075 EXPECT_TRUE(deleted1); 2076 ASSERT_FALSE(deleted2); 2077 2078 // Make the interstitial navigation commit it should be showing. 2079 interstitial2->TestDidNavigate(1, interstitial_url); 2080 EXPECT_EQ(interstitial2, contents()->GetInterstitialPage()); 2081} 2082 2083// Test showing an interstitial and have its renderer crash. 2084TEST_F(WebContentsImplTest, InterstitialCrasher) { 2085 // Show an interstitial. 2086 TestInterstitialPage::InterstitialState state = 2087 TestInterstitialPage::INVALID; 2088 bool deleted = false; 2089 GURL url("http://interstitial"); 2090 TestInterstitialPage* interstitial = 2091 new TestInterstitialPage(contents(), true, url, &state, &deleted); 2092 TestInterstitialPageStateGuard state_guard(interstitial); 2093 interstitial->Show(); 2094 // Simulate a renderer crash before the interstitial is shown. 2095 interstitial->TestRenderViewTerminated( 2096 base::TERMINATION_STATUS_PROCESS_CRASHED, -1); 2097 // The interstitial should have been dismissed. 2098 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 2099 RunAllPendingInMessageLoop(); 2100 EXPECT_TRUE(deleted); 2101 2102 // Now try again but this time crash the intersitial after it was shown. 2103 interstitial = 2104 new TestInterstitialPage(contents(), true, url, &state, &deleted); 2105 interstitial->Show(); 2106 interstitial->TestDidNavigate(1, url); 2107 // Simulate a renderer crash. 2108 interstitial->TestRenderViewTerminated( 2109 base::TERMINATION_STATUS_PROCESS_CRASHED, -1); 2110 // The interstitial should have been dismissed. 2111 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 2112 RunAllPendingInMessageLoop(); 2113 EXPECT_TRUE(deleted); 2114} 2115 2116// Tests that showing an interstitial as a result of a browser initiated 2117// navigation while an interstitial is showing does not remove the pending 2118// entry (see http://crbug.com/9791). 2119TEST_F(WebContentsImplTest, NewInterstitialDoesNotCancelPendingEntry) { 2120 const char kUrl[] = "http://www.badguys.com/"; 2121 const GURL kGURL(kUrl); 2122 2123 // Start a navigation to a page 2124 contents()->GetController().LoadURL( 2125 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 2126 2127 // Simulate that navigation triggering an interstitial. 2128 TestInterstitialPage::InterstitialState state = 2129 TestInterstitialPage::INVALID; 2130 bool deleted = false; 2131 TestInterstitialPage* interstitial = 2132 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted); 2133 TestInterstitialPageStateGuard state_guard(interstitial); 2134 interstitial->Show(); 2135 interstitial->TestDidNavigate(1, kGURL); 2136 2137 // Initiate a new navigation from the browser that also triggers an 2138 // interstitial. 2139 contents()->GetController().LoadURL( 2140 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 2141 TestInterstitialPage::InterstitialState state2 = 2142 TestInterstitialPage::INVALID; 2143 bool deleted2 = false; 2144 TestInterstitialPage* interstitial2 = 2145 new TestInterstitialPage(contents(), true, kGURL, &state2, &deleted2); 2146 TestInterstitialPageStateGuard state_guard2(interstitial2); 2147 interstitial2->Show(); 2148 interstitial2->TestDidNavigate(1, kGURL); 2149 2150 // Make sure we still have an entry. 2151 NavigationEntry* entry = contents()->GetController().GetPendingEntry(); 2152 ASSERT_TRUE(entry); 2153 EXPECT_EQ(kUrl, entry->GetURL().spec()); 2154 2155 // And that the first interstitial is gone, but not the second. 2156 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 2157 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2); 2158 RunAllPendingInMessageLoop(); 2159 EXPECT_TRUE(deleted); 2160 EXPECT_FALSE(deleted2); 2161} 2162 2163// Tests that Javascript messages are not shown while an interstitial is 2164// showing. 2165TEST_F(WebContentsImplTest, NoJSMessageOnInterstitials) { 2166 const char kUrl[] = "http://www.badguys.com/"; 2167 const GURL kGURL(kUrl); 2168 2169 // Start a navigation to a page 2170 contents()->GetController().LoadURL( 2171 kGURL, Referrer(), PAGE_TRANSITION_TYPED, std::string()); 2172 // DidNavigate from the page 2173 contents()->TestDidNavigate(rvh(), 1, kGURL, PAGE_TRANSITION_TYPED); 2174 2175 // Simulate showing an interstitial while the page is showing. 2176 TestInterstitialPage::InterstitialState state = 2177 TestInterstitialPage::INVALID; 2178 bool deleted = false; 2179 TestInterstitialPage* interstitial = 2180 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted); 2181 TestInterstitialPageStateGuard state_guard(interstitial); 2182 interstitial->Show(); 2183 interstitial->TestDidNavigate(1, kGURL); 2184 2185 // While the interstitial is showing, let's simulate the hidden page 2186 // attempting to show a JS message. 2187 IPC::Message* dummy_message = new IPC::Message; 2188 contents()->RunJavaScriptMessage(contents()->GetMainFrame(), 2189 base::ASCIIToUTF16("This is an informative message"), 2190 base::ASCIIToUTF16("OK"), 2191 kGURL, JAVASCRIPT_MESSAGE_TYPE_ALERT, dummy_message); 2192 EXPECT_TRUE(contents()->last_dialog_suppressed_); 2193} 2194 2195// Makes sure that if the source passed to CopyStateFromAndPrune has an 2196// interstitial it isn't copied over to the destination. 2197TEST_F(WebContentsImplTest, CopyStateFromAndPruneSourceInterstitial) { 2198 // Navigate to a page. 2199 GURL url1("http://www.google.com"); 2200 test_rvh()->SendNavigate(1, url1); 2201 EXPECT_EQ(1, controller().GetEntryCount()); 2202 2203 // Initiate a browser navigation that will trigger the interstitial 2204 controller().LoadURL(GURL("http://www.evil.com"), Referrer(), 2205 PAGE_TRANSITION_TYPED, std::string()); 2206 2207 // Show an interstitial. 2208 TestInterstitialPage::InterstitialState state = 2209 TestInterstitialPage::INVALID; 2210 bool deleted = false; 2211 GURL url2("http://interstitial"); 2212 TestInterstitialPage* interstitial = 2213 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 2214 TestInterstitialPageStateGuard state_guard(interstitial); 2215 interstitial->Show(); 2216 interstitial->TestDidNavigate(1, url2); 2217 EXPECT_TRUE(interstitial->is_showing()); 2218 EXPECT_EQ(2, controller().GetEntryCount()); 2219 2220 // Create another NavigationController. 2221 GURL url3("http://foo2"); 2222 scoped_ptr<TestWebContents> other_contents( 2223 static_cast<TestWebContents*>(CreateTestWebContents())); 2224 NavigationControllerImpl& other_controller = other_contents->GetController(); 2225 other_contents->NavigateAndCommit(url3); 2226 other_contents->ExpectSetHistoryLengthAndPrune( 2227 NavigationEntryImpl::FromNavigationEntry( 2228 other_controller.GetEntryAtIndex(0))->site_instance(), 1, 2229 other_controller.GetEntryAtIndex(0)->GetPageID()); 2230 other_controller.CopyStateFromAndPrune(&controller(), false); 2231 2232 // The merged controller should only have two entries: url1 and url2. 2233 ASSERT_EQ(2, other_controller.GetEntryCount()); 2234 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex()); 2235 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->GetURL()); 2236 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->GetURL()); 2237 2238 // And the merged controller shouldn't be showing an interstitial. 2239 EXPECT_FALSE(other_contents->ShowingInterstitialPage()); 2240} 2241 2242// Makes sure that CopyStateFromAndPrune cannot be called if the target is 2243// showing an interstitial. 2244TEST_F(WebContentsImplTest, CopyStateFromAndPruneTargetInterstitial) { 2245 // Navigate to a page. 2246 GURL url1("http://www.google.com"); 2247 contents()->NavigateAndCommit(url1); 2248 2249 // Create another NavigationController. 2250 scoped_ptr<TestWebContents> other_contents( 2251 static_cast<TestWebContents*>(CreateTestWebContents())); 2252 NavigationControllerImpl& other_controller = other_contents->GetController(); 2253 2254 // Navigate it to url2. 2255 GURL url2("http://foo2"); 2256 other_contents->NavigateAndCommit(url2); 2257 2258 // Show an interstitial. 2259 TestInterstitialPage::InterstitialState state = 2260 TestInterstitialPage::INVALID; 2261 bool deleted = false; 2262 GURL url3("http://interstitial"); 2263 TestInterstitialPage* interstitial = 2264 new TestInterstitialPage(other_contents.get(), true, url3, &state, 2265 &deleted); 2266 TestInterstitialPageStateGuard state_guard(interstitial); 2267 interstitial->Show(); 2268 interstitial->TestDidNavigate(1, url3); 2269 EXPECT_TRUE(interstitial->is_showing()); 2270 EXPECT_EQ(2, other_controller.GetEntryCount()); 2271 2272 // Ensure that we do not allow calling CopyStateFromAndPrune when an 2273 // interstitial is showing in the target. 2274 EXPECT_FALSE(other_controller.CanPruneAllButLastCommitted()); 2275} 2276 2277// Regression test for http://crbug.com/168611 - the URLs passed by the 2278// DidFinishLoad and DidFailLoadWithError IPCs should get filtered. 2279TEST_F(WebContentsImplTest, FilterURLs) { 2280 TestWebContentsObserver observer(contents()); 2281 2282 // A navigation to about:whatever should always look like a navigation to 2283 // about:blank 2284 GURL url_normalized(url::kAboutBlankURL); 2285 GURL url_from_ipc("about:whatever"); 2286 2287 // We navigate the test WebContents to about:blank, since NavigateAndCommit 2288 // will use the given URL to create the NavigationEntry as well, and that 2289 // entry should contain the filtered URL. 2290 contents()->NavigateAndCommit(url_normalized); 2291 2292 // Check that an IPC with about:whatever is correctly normalized. 2293 contents()->TestDidFinishLoad(url_from_ipc); 2294 2295 EXPECT_EQ(url_normalized, observer.last_url()); 2296 2297 // Create and navigate another WebContents. 2298 scoped_ptr<TestWebContents> other_contents( 2299 static_cast<TestWebContents*>(CreateTestWebContents())); 2300 TestWebContentsObserver other_observer(other_contents.get()); 2301 other_contents->NavigateAndCommit(url_normalized); 2302 2303 // Check that an IPC with about:whatever is correctly normalized. 2304 other_contents->TestDidFailLoadWithError( 2305 url_from_ipc, 1, base::string16()); 2306 EXPECT_EQ(url_normalized, other_observer.last_url()); 2307} 2308 2309// Test that if a pending contents is deleted before it is shown, we don't 2310// crash. 2311TEST_F(WebContentsImplTest, PendingContents) { 2312 scoped_ptr<TestWebContents> other_contents( 2313 static_cast<TestWebContents*>(CreateTestWebContents())); 2314 contents()->AddPendingContents(other_contents.get()); 2315 int route_id = other_contents->GetRenderViewHost()->GetRoutingID(); 2316 other_contents.reset(); 2317 EXPECT_EQ(NULL, contents()->GetCreatedWindow(route_id)); 2318} 2319 2320TEST_F(WebContentsImplTest, CapturerOverridesPreferredSize) { 2321 const gfx::Size original_preferred_size(1024, 768); 2322 contents()->UpdatePreferredSize(original_preferred_size); 2323 2324 // With no capturers, expect the preferred size to be the one propagated into 2325 // WebContentsImpl via the RenderViewHostDelegate interface. 2326 EXPECT_EQ(contents()->GetCapturerCount(), 0); 2327 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize()); 2328 2329 // Increment capturer count, but without specifying a capture size. Expect 2330 // a "not set" preferred size. 2331 contents()->IncrementCapturerCount(gfx::Size()); 2332 EXPECT_EQ(1, contents()->GetCapturerCount()); 2333 EXPECT_EQ(gfx::Size(), contents()->GetPreferredSize()); 2334 2335 // Increment capturer count again, but with an overriding capture size. 2336 // Expect preferred size to now be overridden to the capture size. 2337 const gfx::Size capture_size(1280, 720); 2338 contents()->IncrementCapturerCount(capture_size); 2339 EXPECT_EQ(2, contents()->GetCapturerCount()); 2340 EXPECT_EQ(capture_size, contents()->GetPreferredSize()); 2341 2342 // Increment capturer count a third time, but the expect that the preferred 2343 // size is still the first capture size. 2344 const gfx::Size another_capture_size(720, 480); 2345 contents()->IncrementCapturerCount(another_capture_size); 2346 EXPECT_EQ(3, contents()->GetCapturerCount()); 2347 EXPECT_EQ(capture_size, contents()->GetPreferredSize()); 2348 2349 // Decrement capturer count twice, but expect the preferred size to still be 2350 // overridden. 2351 contents()->DecrementCapturerCount(); 2352 contents()->DecrementCapturerCount(); 2353 EXPECT_EQ(1, contents()->GetCapturerCount()); 2354 EXPECT_EQ(capture_size, contents()->GetPreferredSize()); 2355 2356 // Decrement capturer count, and since the count has dropped to zero, the 2357 // original preferred size should be restored. 2358 contents()->DecrementCapturerCount(); 2359 EXPECT_EQ(0, contents()->GetCapturerCount()); 2360 EXPECT_EQ(original_preferred_size, contents()->GetPreferredSize()); 2361} 2362 2363// Tests that GetLastActiveTime starts with a real, non-zero time and updates 2364// on activity. 2365TEST_F(WebContentsImplTest, GetLastActiveTime) { 2366 // The WebContents starts with a valid creation time. 2367 EXPECT_FALSE(contents()->GetLastActiveTime().is_null()); 2368 2369 // Reset the last active time to a known-bad value. 2370 contents()->last_active_time_ = base::TimeTicks(); 2371 ASSERT_TRUE(contents()->GetLastActiveTime().is_null()); 2372 2373 // Simulate activating the WebContents. The active time should update. 2374 contents()->WasShown(); 2375 EXPECT_FALSE(contents()->GetLastActiveTime().is_null()); 2376} 2377 2378class ContentsZoomChangedDelegate : public WebContentsDelegate { 2379 public: 2380 ContentsZoomChangedDelegate() : 2381 contents_zoom_changed_call_count_(0), 2382 last_zoom_in_(false) { 2383 } 2384 2385 int GetAndResetContentsZoomChangedCallCount() { 2386 int count = contents_zoom_changed_call_count_; 2387 contents_zoom_changed_call_count_ = 0; 2388 return count; 2389 } 2390 2391 bool last_zoom_in() const { 2392 return last_zoom_in_; 2393 } 2394 2395 // WebContentsDelegate: 2396 virtual void ContentsZoomChange(bool zoom_in) OVERRIDE { 2397 contents_zoom_changed_call_count_++; 2398 last_zoom_in_ = zoom_in; 2399 } 2400 2401 private: 2402 int contents_zoom_changed_call_count_; 2403 bool last_zoom_in_; 2404 2405 DISALLOW_COPY_AND_ASSIGN(ContentsZoomChangedDelegate); 2406}; 2407 2408// Tests that some mouseehweel events get turned into browser zoom requests. 2409TEST_F(WebContentsImplTest, HandleWheelEvent) { 2410 using blink::WebInputEvent; 2411 2412 scoped_ptr<ContentsZoomChangedDelegate> delegate( 2413 new ContentsZoomChangedDelegate()); 2414 contents()->SetDelegate(delegate.get()); 2415 2416 int modifiers = 0; 2417 // Verify that normal mouse wheel events do nothing to change the zoom level. 2418 blink::WebMouseWheelEvent event = 2419 SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false); 2420 EXPECT_FALSE(contents()->HandleWheelEvent(event)); 2421 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount()); 2422 2423 modifiers = WebInputEvent::ShiftKey | WebInputEvent::AltKey; 2424 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false); 2425 EXPECT_FALSE(contents()->HandleWheelEvent(event)); 2426 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount()); 2427 2428 // But whenever the ctrl modifier is applied, they can increase/decrease zoom. 2429 // Except on MacOS where we never want to adjust zoom with mousewheel. 2430 modifiers = WebInputEvent::ControlKey; 2431 event = SyntheticWebMouseWheelEventBuilder::Build(0, 1, modifiers, false); 2432 bool handled = contents()->HandleWheelEvent(event); 2433#if defined(OS_MACOSX) 2434 EXPECT_FALSE(handled); 2435 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount()); 2436#else 2437 EXPECT_TRUE(handled); 2438 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount()); 2439 EXPECT_TRUE(delegate->last_zoom_in()); 2440#endif 2441 2442 modifiers = WebInputEvent::ControlKey | WebInputEvent::ShiftKey | 2443 WebInputEvent::AltKey; 2444 event = SyntheticWebMouseWheelEventBuilder::Build(2, -5, modifiers, false); 2445 handled = contents()->HandleWheelEvent(event); 2446#if defined(OS_MACOSX) 2447 EXPECT_FALSE(handled); 2448 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount()); 2449#else 2450 EXPECT_TRUE(handled); 2451 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount()); 2452 EXPECT_FALSE(delegate->last_zoom_in()); 2453#endif 2454 2455 // Unless there is no vertical movement. 2456 event = SyntheticWebMouseWheelEventBuilder::Build(2, 0, modifiers, false); 2457 EXPECT_FALSE(contents()->HandleWheelEvent(event)); 2458 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount()); 2459 2460 // Events containing precise scrolling deltas also shouldn't result in the 2461 // zoom being adjusted, to avoid accidental adjustments caused by 2462 // two-finger-scrolling on a touchpad. 2463 modifiers = WebInputEvent::ControlKey; 2464 event = SyntheticWebMouseWheelEventBuilder::Build(0, 5, modifiers, true); 2465 EXPECT_FALSE(contents()->HandleWheelEvent(event)); 2466 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount()); 2467 2468 // Ensure pointers to the delegate aren't kept beyond its lifetime. 2469 contents()->SetDelegate(NULL); 2470} 2471 2472// Tests that trackpad GesturePinchUpdate events get turned into browser zoom. 2473TEST_F(WebContentsImplTest, HandleGestureEvent) { 2474 using blink::WebGestureEvent; 2475 using blink::WebInputEvent; 2476 2477 scoped_ptr<ContentsZoomChangedDelegate> delegate( 2478 new ContentsZoomChangedDelegate()); 2479 contents()->SetDelegate(delegate.get()); 2480 2481 const float kZoomStepValue = 0.6f; 2482 blink::WebGestureEvent event = SyntheticWebGestureEventBuilder::Build( 2483 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchpad); 2484 2485 // A pinch less than the step value doesn't change the zoom level. 2486 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 0.8f; 2487 EXPECT_TRUE(contents()->HandleGestureEvent(event)); 2488 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount()); 2489 2490 // But repeating the event so the combined scale is greater does. 2491 EXPECT_TRUE(contents()->HandleGestureEvent(event)); 2492 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount()); 2493 EXPECT_TRUE(delegate->last_zoom_in()); 2494 2495 // Pinching back out one step goes back to 100%. 2496 event.data.pinchUpdate.scale = 1.0f - kZoomStepValue; 2497 EXPECT_TRUE(contents()->HandleGestureEvent(event)); 2498 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount()); 2499 EXPECT_FALSE(delegate->last_zoom_in()); 2500 2501 // Pinching out again doesn't zoom (step is twice as large around 100%). 2502 EXPECT_TRUE(contents()->HandleGestureEvent(event)); 2503 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount()); 2504 2505 // And again now it zooms once per step. 2506 EXPECT_TRUE(contents()->HandleGestureEvent(event)); 2507 EXPECT_EQ(1, delegate->GetAndResetContentsZoomChangedCallCount()); 2508 EXPECT_FALSE(delegate->last_zoom_in()); 2509 2510 // No other type of gesture event is handled by WebContentsImpl (for example 2511 // a touchscreen pinch gesture). 2512 event = SyntheticWebGestureEventBuilder::Build( 2513 WebInputEvent::GesturePinchUpdate, blink::WebGestureDeviceTouchscreen); 2514 event.data.pinchUpdate.scale = 1.0f + kZoomStepValue * 3; 2515 EXPECT_FALSE(contents()->HandleGestureEvent(event)); 2516 EXPECT_EQ(0, delegate->GetAndResetContentsZoomChangedCallCount()); 2517 2518 // Ensure pointers to the delegate aren't kept beyond it's lifetime. 2519 contents()->SetDelegate(NULL); 2520} 2521 2522// Tests that GetRelatedActiveContentsCount is shared between related 2523// SiteInstances and includes WebContents that have not navigated yet. 2524TEST_F(WebContentsImplTest, ActiveContentsCountBasic) { 2525 scoped_refptr<SiteInstance> instance1( 2526 SiteInstance::CreateForURL(browser_context(), GURL("http://a.com"))); 2527 scoped_refptr<SiteInstance> instance2( 2528 instance1->GetRelatedSiteInstance(GURL("http://b.com"))); 2529 2530 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount()); 2531 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount()); 2532 2533 scoped_ptr<TestWebContents> contents1( 2534 TestWebContents::Create(browser_context(), instance1)); 2535 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount()); 2536 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount()); 2537 2538 scoped_ptr<TestWebContents> contents2( 2539 TestWebContents::Create(browser_context(), instance1)); 2540 EXPECT_EQ(2u, instance1->GetRelatedActiveContentsCount()); 2541 EXPECT_EQ(2u, instance2->GetRelatedActiveContentsCount()); 2542 2543 contents1.reset(); 2544 EXPECT_EQ(1u, instance1->GetRelatedActiveContentsCount()); 2545 EXPECT_EQ(1u, instance2->GetRelatedActiveContentsCount()); 2546 2547 contents2.reset(); 2548 EXPECT_EQ(0u, instance1->GetRelatedActiveContentsCount()); 2549 EXPECT_EQ(0u, instance2->GetRelatedActiveContentsCount()); 2550} 2551 2552// Tests that GetRelatedActiveContentsCount is preserved correctly across 2553// same-site and cross-site navigations. 2554TEST_F(WebContentsImplTest, ActiveContentsCountNavigate) { 2555 scoped_refptr<SiteInstance> instance( 2556 SiteInstance::Create(browser_context())); 2557 2558 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount()); 2559 2560 scoped_ptr<TestWebContents> contents( 2561 TestWebContents::Create(browser_context(), instance)); 2562 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2563 2564 // Navigate to a URL. 2565 contents->GetController().LoadURL( 2566 GURL("http://a.com/1"), Referrer(), PAGE_TRANSITION_TYPED, std::string()); 2567 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2568 contents->CommitPendingNavigation(); 2569 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2570 2571 // Navigate to a URL in the same site. 2572 contents->GetController().LoadURL( 2573 GURL("http://a.com/2"), Referrer(), PAGE_TRANSITION_TYPED, std::string()); 2574 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2575 contents->CommitPendingNavigation(); 2576 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2577 2578 // Navigate to a URL in a different site. 2579 contents->GetController().LoadURL( 2580 GURL("http://b.com"), Referrer(), PAGE_TRANSITION_TYPED, std::string()); 2581 EXPECT_TRUE(contents->cross_navigation_pending()); 2582 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2583 contents->CommitPendingNavigation(); 2584 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2585 2586 contents.reset(); 2587 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount()); 2588} 2589 2590// Tests that GetRelatedActiveContentsCount tracks BrowsingInstance changes 2591// from WebUI. 2592TEST_F(WebContentsImplTest, ActiveContentsCountChangeBrowsingInstance) { 2593 scoped_refptr<SiteInstance> instance( 2594 SiteInstance::Create(browser_context())); 2595 2596 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount()); 2597 2598 scoped_ptr<TestWebContents> contents( 2599 TestWebContents::Create(browser_context(), instance)); 2600 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2601 2602 // Navigate to a URL. 2603 contents->NavigateAndCommit(GURL("http://a.com")); 2604 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2605 2606 // Navigate to a URL with WebUI. This will change BrowsingInstances. 2607 contents->GetController().LoadURL( 2608 GURL(kTestWebUIUrl), Referrer(), PAGE_TRANSITION_TYPED, std::string()); 2609 EXPECT_TRUE(contents->cross_navigation_pending()); 2610 scoped_refptr<SiteInstance> instance_webui( 2611 contents->GetPendingRenderViewHost()->GetSiteInstance()); 2612 EXPECT_FALSE(instance->IsRelatedSiteInstance(instance_webui.get())); 2613 2614 // At this point, contents still counts for the old BrowsingInstance. 2615 EXPECT_EQ(1u, instance->GetRelatedActiveContentsCount()); 2616 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount()); 2617 2618 // Commit and contents counts for the new one. 2619 contents->CommitPendingNavigation(); 2620 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount()); 2621 EXPECT_EQ(1u, instance_webui->GetRelatedActiveContentsCount()); 2622 2623 contents.reset(); 2624 EXPECT_EQ(0u, instance->GetRelatedActiveContentsCount()); 2625 EXPECT_EQ(0u, instance_webui->GetRelatedActiveContentsCount()); 2626} 2627 2628} // namespace content 2629