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