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