1 // Copyright (c) 2011 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 <vector> 6 7 #include "base/logging.h" 8 #include "base/utf_string_conversions.h" 9 #include "chrome/browser/prefs/pref_service.h" 10 #include "chrome/browser/prefs/pref_value_store.h" 11 #include "chrome/common/chrome_paths.h" 12 #include "chrome/common/pref_names.h" 13 #include "chrome/common/render_messages.h" 14 #include "chrome/common/url_constants.h" 15 #include "chrome/test/testing_pref_service.h" 16 #include "chrome/test/testing_profile.h" 17 #include "content/browser/browser_thread.h" 18 #include "content/browser/renderer_host/render_view_host.h" 19 #include "content/browser/renderer_host/render_widget_host_view.h" 20 #include "content/browser/renderer_host/test_render_view_host.h" 21 #include "content/browser/site_instance.h" 22 #include "content/browser/tab_contents/constrained_window.h" 23 #include "content/browser/tab_contents/interstitial_page.h" 24 #include "content/browser/tab_contents/navigation_controller.h" 25 #include "content/browser/tab_contents/navigation_entry.h" 26 #include "content/browser/tab_contents/test_tab_contents.h" 27 #include "content/common/bindings_policy.h" 28 #include "content/common/view_messages.h" 29 #include "ipc/ipc_channel.h" 30 #include "testing/gtest/include/gtest/gtest.h" 31 #include "ui/base/message_box_flags.h" 32 #include "webkit/glue/webkit_glue.h" 33 34 using webkit_glue::PasswordForm; 35 36 static void InitNavigateParams(ViewHostMsg_FrameNavigate_Params* params, 37 int page_id, 38 const GURL& url) { 39 params->page_id = page_id; 40 params->url = url; 41 params->referrer = GURL(); 42 params->transition = PageTransition::TYPED; 43 params->redirects = std::vector<GURL>(); 44 params->should_update_history = false; 45 params->searchable_form_url = GURL(); 46 params->searchable_form_encoding = std::string(); 47 params->password_form = PasswordForm(); 48 params->security_info = std::string(); 49 params->gesture = NavigationGestureUser; 50 params->was_within_same_page = false; 51 params->is_post = false; 52 params->content_state = webkit_glue::CreateHistoryStateForURL(GURL(url)); 53 } 54 55 class TestInterstitialPage : public InterstitialPage { 56 public: 57 enum InterstitialState { 58 UNDECIDED = 0, // No decision taken yet. 59 OKED, // Proceed was called. 60 CANCELED // DontProceed was called. 61 }; 62 63 class Delegate { 64 public: 65 virtual void TestInterstitialPageDeleted( 66 TestInterstitialPage* interstitial) = 0; 67 68 protected: 69 virtual ~Delegate() {} 70 }; 71 72 // IMPORTANT NOTE: if you pass stack allocated values for |state| and 73 // |deleted| (like all interstitial related tests do at this point), make sure 74 // to create an instance of the TestInterstitialPageStateGuard class on the 75 // stack in your test. This will ensure that the TestInterstitialPage states 76 // are cleared when the test finishes. 77 // Not doing so will cause stack trashing if your test does not hide the 78 // interstitial, as in such a case it will be destroyed in the test TearDown 79 // method and will dereference the |deleted| local variable which by then is 80 // out of scope. 81 TestInterstitialPage(TabContents* tab, 82 bool new_navigation, 83 const GURL& url, 84 InterstitialState* state, 85 bool* deleted) 86 : InterstitialPage(tab, new_navigation, url), 87 state_(state), 88 deleted_(deleted), 89 command_received_count_(0), 90 delegate_(NULL) { 91 *state_ = UNDECIDED; 92 *deleted_ = false; 93 } 94 95 virtual ~TestInterstitialPage() { 96 if (deleted_) 97 *deleted_ = true; 98 if (delegate_) 99 delegate_->TestInterstitialPageDeleted(this); 100 } 101 102 virtual void DontProceed() { 103 if (state_) 104 *state_ = CANCELED; 105 InterstitialPage::DontProceed(); 106 } 107 virtual void Proceed() { 108 if (state_) 109 *state_ = OKED; 110 InterstitialPage::Proceed(); 111 } 112 113 int command_received_count() const { 114 return command_received_count_; 115 } 116 117 void TestDomOperationResponse(const std::string& json_string) { 118 DomOperationResponse(json_string, 1); 119 } 120 121 void TestDidNavigate(int page_id, const GURL& url) { 122 ViewHostMsg_FrameNavigate_Params params; 123 InitNavigateParams(¶ms, page_id, url); 124 DidNavigate(render_view_host(), params); 125 } 126 127 void TestRenderViewGone(base::TerminationStatus status, int error_code) { 128 RenderViewGone(render_view_host(), status, error_code); 129 } 130 131 bool is_showing() const { 132 return static_cast<TestRenderWidgetHostView*>(render_view_host()->view())-> 133 is_showing(); 134 } 135 136 void ClearStates() { 137 state_ = NULL; 138 deleted_ = NULL; 139 delegate_ = NULL; 140 } 141 142 void set_delegate(Delegate* delegate) { 143 delegate_ = delegate; 144 } 145 146 protected: 147 virtual RenderViewHost* CreateRenderViewHost() { 148 return new TestRenderViewHost( 149 SiteInstance::CreateSiteInstance(tab()->profile()), 150 this, MSG_ROUTING_NONE); 151 } 152 153 virtual TabContentsView* CreateTabContentsView() { return NULL; } 154 155 156 virtual void CommandReceived(const std::string& command) { 157 command_received_count_++; 158 } 159 160 private: 161 InterstitialState* state_; 162 bool* deleted_; 163 int command_received_count_; 164 Delegate* delegate_; 165 }; 166 167 class TestInterstitialPageStateGuard : public TestInterstitialPage::Delegate { 168 public: 169 explicit TestInterstitialPageStateGuard( 170 TestInterstitialPage* interstitial_page) 171 : interstitial_page_(interstitial_page) { 172 DCHECK(interstitial_page_); 173 interstitial_page_->set_delegate(this); 174 } 175 ~TestInterstitialPageStateGuard() { 176 if (interstitial_page_) 177 interstitial_page_->ClearStates(); 178 } 179 180 virtual void TestInterstitialPageDeleted(TestInterstitialPage* interstitial) { 181 DCHECK(interstitial_page_ == interstitial); 182 interstitial_page_ = NULL; 183 } 184 185 private: 186 TestInterstitialPage* interstitial_page_; 187 }; 188 189 class TabContentsTest : public RenderViewHostTestHarness { 190 public: 191 TabContentsTest() 192 : RenderViewHostTestHarness(), 193 ui_thread_(BrowserThread::UI, &message_loop_) { 194 } 195 196 private: 197 // Supply our own profile so we use the correct profile data. The test harness 198 // is not supposed to overwrite a profile if it's already created. 199 virtual void SetUp() { 200 TestingProfile* profile = new TestingProfile(); 201 profile_.reset(profile); 202 203 // Set some (WebKit) user preferences. 204 TestingPrefService* pref_services = profile->GetTestingPrefService(); 205 #if defined(TOOLKIT_USES_GTK) 206 pref_services->SetUserPref(prefs::kUsesSystemTheme, 207 Value::CreateBooleanValue(false)); 208 #endif 209 pref_services->SetUserPref(prefs::kDefaultCharset, 210 Value::CreateStringValue("utf8")); 211 pref_services->SetUserPref(prefs::kWebKitDefaultFontSize, 212 Value::CreateIntegerValue(20)); 213 pref_services->SetUserPref(prefs::kWebKitTextAreasAreResizable, 214 Value::CreateBooleanValue(false)); 215 pref_services->SetUserPref(prefs::kWebKitUsesUniversalDetector, 216 Value::CreateBooleanValue(true)); 217 pref_services->SetUserPref("webkit.webprefs.foo", 218 Value::CreateStringValue("bar")); 219 220 RenderViewHostTestHarness::SetUp(); 221 } 222 223 virtual void TearDown() { 224 RenderViewHostTestHarness::TearDown(); 225 226 profile_.reset(NULL); 227 } 228 229 BrowserThread ui_thread_; 230 }; 231 232 // Test to make sure that title updates get stripped of whitespace. 233 TEST_F(TabContentsTest, UpdateTitle) { 234 ViewHostMsg_FrameNavigate_Params params; 235 InitNavigateParams(¶ms, 0, GURL(chrome::kAboutBlankURL)); 236 237 NavigationController::LoadCommittedDetails details; 238 controller().RendererDidNavigate(params, 0, &details); 239 240 contents()->UpdateTitle(rvh(), 0, L" Lots O' Whitespace\n"); 241 EXPECT_EQ(ASCIIToUTF16("Lots O' Whitespace"), contents()->GetTitle()); 242 } 243 244 // Test view source mode for the new tabs page. 245 TEST_F(TabContentsTest, NTPViewSource) { 246 const char kUrl[] = "view-source:chrome://newtab"; 247 const GURL kGURL(kUrl); 248 249 process()->sink().ClearMessages(); 250 251 controller().LoadURL(kGURL, GURL(), PageTransition::TYPED); 252 rvh()->delegate()->RenderViewCreated(rvh()); 253 // Did we get the expected message? 254 EXPECT_TRUE(process()->sink().GetFirstMessageMatching( 255 ViewMsg_EnableViewSourceMode::ID)); 256 257 ViewHostMsg_FrameNavigate_Params params; 258 InitNavigateParams(¶ms, 0, kGURL); 259 NavigationController::LoadCommittedDetails details; 260 controller().RendererDidNavigate(params, 0, &details); 261 // Also check title and url. 262 EXPECT_EQ(ASCIIToUTF16(kUrl), contents()->GetTitle()); 263 EXPECT_TRUE(contents()->ShouldDisplayURL()); 264 } 265 266 // Test simple same-SiteInstance navigation. 267 TEST_F(TabContentsTest, SimpleNavigation) { 268 TestRenderViewHost* orig_rvh = rvh(); 269 SiteInstance* instance1 = contents()->GetSiteInstance(); 270 EXPECT_TRUE(contents()->pending_rvh() == NULL); 271 272 // Navigate to URL 273 const GURL url("http://www.google.com"); 274 controller().LoadURL(url, GURL(), PageTransition::TYPED); 275 EXPECT_FALSE(contents()->cross_navigation_pending()); 276 EXPECT_EQ(instance1, orig_rvh->site_instance()); 277 // Controller's pending entry will have a NULL site instance until we assign 278 // it in DidNavigate. 279 EXPECT_TRUE(controller().GetActiveEntry()->site_instance() == NULL); 280 281 // DidNavigate from the page 282 ViewHostMsg_FrameNavigate_Params params; 283 InitNavigateParams(¶ms, 1, url); 284 contents()->TestDidNavigate(orig_rvh, params); 285 EXPECT_FALSE(contents()->cross_navigation_pending()); 286 EXPECT_EQ(orig_rvh, contents()->render_view_host()); 287 EXPECT_EQ(instance1, orig_rvh->site_instance()); 288 // Controller's entry should now have the SiteInstance, or else we won't be 289 // able to find it later. 290 EXPECT_EQ(instance1, controller().GetActiveEntry()->site_instance()); 291 } 292 293 // Test that navigating across a site boundary creates a new RenderViewHost 294 // with a new SiteInstance. Going back should do the same. 295 TEST_F(TabContentsTest, CrossSiteBoundaries) { 296 contents()->transition_cross_site = true; 297 TestRenderViewHost* orig_rvh = rvh(); 298 int orig_rvh_delete_count = 0; 299 orig_rvh->set_delete_counter(&orig_rvh_delete_count); 300 SiteInstance* instance1 = contents()->GetSiteInstance(); 301 302 // Navigate to URL. First URL should use first RenderViewHost. 303 const GURL url("http://www.google.com"); 304 controller().LoadURL(url, GURL(), PageTransition::TYPED); 305 ViewHostMsg_FrameNavigate_Params params1; 306 InitNavigateParams(¶ms1, 1, url); 307 contents()->TestDidNavigate(orig_rvh, params1); 308 309 EXPECT_FALSE(contents()->cross_navigation_pending()); 310 EXPECT_EQ(orig_rvh, contents()->render_view_host()); 311 312 // Navigate to new site 313 const GURL url2("http://www.yahoo.com"); 314 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 315 EXPECT_TRUE(contents()->cross_navigation_pending()); 316 TestRenderViewHost* pending_rvh = contents()->pending_rvh(); 317 int pending_rvh_delete_count = 0; 318 pending_rvh->set_delete_counter(&pending_rvh_delete_count); 319 320 // DidNavigate from the pending page 321 ViewHostMsg_FrameNavigate_Params params2; 322 InitNavigateParams(¶ms2, 1, url2); 323 contents()->TestDidNavigate(pending_rvh, params2); 324 SiteInstance* instance2 = contents()->GetSiteInstance(); 325 326 EXPECT_FALSE(contents()->cross_navigation_pending()); 327 EXPECT_EQ(pending_rvh, contents()->render_view_host()); 328 EXPECT_NE(instance1, instance2); 329 EXPECT_TRUE(contents()->pending_rvh() == NULL); 330 EXPECT_EQ(orig_rvh_delete_count, 1); 331 332 // Going back should switch SiteInstances again. The first SiteInstance is 333 // stored in the NavigationEntry, so it should be the same as at the start. 334 controller().GoBack(); 335 TestRenderViewHost* goback_rvh = contents()->pending_rvh(); 336 EXPECT_TRUE(contents()->cross_navigation_pending()); 337 338 // DidNavigate from the back action 339 contents()->TestDidNavigate(goback_rvh, params1); 340 EXPECT_FALSE(contents()->cross_navigation_pending()); 341 EXPECT_EQ(goback_rvh, contents()->render_view_host()); 342 EXPECT_EQ(pending_rvh_delete_count, 1); 343 EXPECT_EQ(instance1, contents()->GetSiteInstance()); 344 } 345 346 // Test that navigating across a site boundary after a crash creates a new 347 // RVH without requiring a cross-site transition (i.e., PENDING state). 348 TEST_F(TabContentsTest, CrossSiteBoundariesAfterCrash) { 349 contents()->transition_cross_site = true; 350 TestRenderViewHost* orig_rvh = rvh(); 351 int orig_rvh_delete_count = 0; 352 orig_rvh->set_delete_counter(&orig_rvh_delete_count); 353 SiteInstance* instance1 = contents()->GetSiteInstance(); 354 355 // Navigate to URL. First URL should use first RenderViewHost. 356 const GURL url("http://www.google.com"); 357 controller().LoadURL(url, GURL(), PageTransition::TYPED); 358 ViewHostMsg_FrameNavigate_Params params1; 359 InitNavigateParams(¶ms1, 1, url); 360 contents()->TestDidNavigate(orig_rvh, params1); 361 362 EXPECT_FALSE(contents()->cross_navigation_pending()); 363 EXPECT_EQ(orig_rvh, contents()->render_view_host()); 364 365 // Crash the renderer. 366 orig_rvh->set_render_view_created(false); 367 368 // Navigate to new site. We should not go into PENDING. 369 const GURL url2("http://www.yahoo.com"); 370 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 371 TestRenderViewHost* new_rvh = rvh(); 372 EXPECT_FALSE(contents()->cross_navigation_pending()); 373 EXPECT_TRUE(contents()->pending_rvh() == NULL); 374 EXPECT_NE(orig_rvh, new_rvh); 375 EXPECT_EQ(orig_rvh_delete_count, 1); 376 377 // DidNavigate from the new page 378 ViewHostMsg_FrameNavigate_Params params2; 379 InitNavigateParams(¶ms2, 1, url2); 380 contents()->TestDidNavigate(new_rvh, params2); 381 SiteInstance* instance2 = contents()->GetSiteInstance(); 382 383 EXPECT_FALSE(contents()->cross_navigation_pending()); 384 EXPECT_EQ(new_rvh, rvh()); 385 EXPECT_NE(instance1, instance2); 386 EXPECT_TRUE(contents()->pending_rvh() == NULL); 387 } 388 389 // Test that opening a new tab in the same SiteInstance and then navigating 390 // both tabs to a new site will place both tabs in a single SiteInstance. 391 TEST_F(TabContentsTest, NavigateTwoTabsCrossSite) { 392 contents()->transition_cross_site = true; 393 TestRenderViewHost* orig_rvh = rvh(); 394 SiteInstance* instance1 = contents()->GetSiteInstance(); 395 396 // Navigate to URL. First URL should use first RenderViewHost. 397 const GURL url("http://www.google.com"); 398 controller().LoadURL(url, GURL(), PageTransition::TYPED); 399 ViewHostMsg_FrameNavigate_Params params1; 400 InitNavigateParams(¶ms1, 1, url); 401 contents()->TestDidNavigate(orig_rvh, params1); 402 403 // Open a new tab with the same SiteInstance, navigated to the same site. 404 TestTabContents contents2(profile(), instance1); 405 params1.page_id = 2; // Need this since the site instance is the same (which 406 // is the scope of page IDs) and we want to consider 407 // this a new page. 408 contents2.transition_cross_site = true; 409 contents2.controller().LoadURL(url, GURL(), PageTransition::TYPED); 410 contents2.TestDidNavigate(contents2.render_view_host(), params1); 411 412 // Navigate first tab to a new site 413 const GURL url2a("http://www.yahoo.com"); 414 controller().LoadURL(url2a, GURL(), PageTransition::TYPED); 415 TestRenderViewHost* pending_rvh_a = contents()->pending_rvh(); 416 ViewHostMsg_FrameNavigate_Params params2a; 417 InitNavigateParams(¶ms2a, 1, url2a); 418 contents()->TestDidNavigate(pending_rvh_a, params2a); 419 SiteInstance* instance2a = contents()->GetSiteInstance(); 420 EXPECT_NE(instance1, instance2a); 421 422 // Navigate second tab to the same site as the first tab 423 const GURL url2b("http://mail.yahoo.com"); 424 contents2.controller().LoadURL(url2b, GURL(), PageTransition::TYPED); 425 TestRenderViewHost* pending_rvh_b = contents2.pending_rvh(); 426 EXPECT_TRUE(pending_rvh_b != NULL); 427 EXPECT_TRUE(contents2.cross_navigation_pending()); 428 429 // NOTE(creis): We used to be in danger of showing a sad tab page here if the 430 // second tab hadn't navigated somewhere first (bug 1145430). That case is 431 // now covered by the CrossSiteBoundariesAfterCrash test. 432 433 ViewHostMsg_FrameNavigate_Params params2b; 434 InitNavigateParams(¶ms2b, 2, url2b); 435 contents2.TestDidNavigate(pending_rvh_b, params2b); 436 SiteInstance* instance2b = contents2.GetSiteInstance(); 437 EXPECT_NE(instance1, instance2b); 438 439 // Both tabs should now be in the same SiteInstance. 440 EXPECT_EQ(instance2a, instance2b); 441 } 442 443 // Tests that TabContents uses the current URL, not the SiteInstance's site, to 444 // determine whether a navigation is cross-site. 445 TEST_F(TabContentsTest, CrossSiteComparesAgainstCurrentPage) { 446 contents()->transition_cross_site = true; 447 TestRenderViewHost* orig_rvh = rvh(); 448 SiteInstance* instance1 = contents()->GetSiteInstance(); 449 450 // Navigate to URL. 451 const GURL url("http://www.google.com"); 452 controller().LoadURL(url, GURL(), PageTransition::TYPED); 453 ViewHostMsg_FrameNavigate_Params params1; 454 InitNavigateParams(¶ms1, 1, url); 455 contents()->TestDidNavigate(orig_rvh, params1); 456 457 // Open a related tab to a second site. 458 TestTabContents contents2(profile(), instance1); 459 contents2.transition_cross_site = true; 460 const GURL url2("http://www.yahoo.com"); 461 contents2.controller().LoadURL(url2, GURL(), PageTransition::TYPED); 462 // The first RVH in contents2 isn't live yet, so we shortcut the cross site 463 // pending. 464 TestRenderViewHost* rvh2 = static_cast<TestRenderViewHost*>( 465 contents2.render_view_host()); 466 EXPECT_FALSE(contents2.cross_navigation_pending()); 467 ViewHostMsg_FrameNavigate_Params params2; 468 InitNavigateParams(¶ms2, 2, url2); 469 contents2.TestDidNavigate(rvh2, params2); 470 SiteInstance* instance2 = contents2.GetSiteInstance(); 471 EXPECT_NE(instance1, instance2); 472 EXPECT_FALSE(contents2.cross_navigation_pending()); 473 474 // Simulate a link click in first tab to second site. Doesn't switch 475 // SiteInstances, because we don't intercept WebKit navigations. 476 ViewHostMsg_FrameNavigate_Params params3; 477 InitNavigateParams(¶ms3, 2, url2); 478 contents()->TestDidNavigate(orig_rvh, params3); 479 SiteInstance* instance3 = contents()->GetSiteInstance(); 480 EXPECT_EQ(instance1, instance3); 481 EXPECT_FALSE(contents()->cross_navigation_pending()); 482 483 // Navigate to the new site. Doesn't switch SiteInstancees, because we 484 // compare against the current URL, not the SiteInstance's site. 485 const GURL url3("http://mail.yahoo.com"); 486 controller().LoadURL(url3, GURL(), PageTransition::TYPED); 487 EXPECT_FALSE(contents()->cross_navigation_pending()); 488 ViewHostMsg_FrameNavigate_Params params4; 489 InitNavigateParams(¶ms4, 3, url3); 490 contents()->TestDidNavigate(orig_rvh, params4); 491 SiteInstance* instance4 = contents()->GetSiteInstance(); 492 EXPECT_EQ(instance1, instance4); 493 } 494 495 // Test that the onbeforeunload and onunload handlers run when navigating 496 // across site boundaries. 497 TEST_F(TabContentsTest, CrossSiteUnloadHandlers) { 498 contents()->transition_cross_site = true; 499 TestRenderViewHost* orig_rvh = rvh(); 500 SiteInstance* instance1 = contents()->GetSiteInstance(); 501 502 // Navigate to URL. First URL should use first RenderViewHost. 503 const GURL url("http://www.google.com"); 504 controller().LoadURL(url, GURL(), PageTransition::TYPED); 505 ViewHostMsg_FrameNavigate_Params params1; 506 InitNavigateParams(¶ms1, 1, url); 507 contents()->TestDidNavigate(orig_rvh, params1); 508 EXPECT_FALSE(contents()->cross_navigation_pending()); 509 EXPECT_EQ(orig_rvh, contents()->render_view_host()); 510 511 // Navigate to new site, but simulate an onbeforeunload denial. 512 const GURL url2("http://www.yahoo.com"); 513 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 514 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 515 orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, false)); 516 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 517 EXPECT_FALSE(contents()->cross_navigation_pending()); 518 EXPECT_EQ(orig_rvh, contents()->render_view_host()); 519 520 // Navigate again, but simulate an onbeforeunload approval. 521 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 522 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 523 orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true)); 524 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 525 EXPECT_TRUE(contents()->cross_navigation_pending()); 526 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>( 527 contents()->pending_rvh()); 528 529 // We won't hear DidNavigate until the onunload handler has finished running. 530 // (No way to simulate that here, but it involves a call from RDH to 531 // TabContents::OnCrossSiteResponse.) 532 533 // DidNavigate from the pending page 534 ViewHostMsg_FrameNavigate_Params params2; 535 InitNavigateParams(¶ms2, 1, url2); 536 contents()->TestDidNavigate(pending_rvh, params2); 537 SiteInstance* instance2 = contents()->GetSiteInstance(); 538 EXPECT_FALSE(contents()->cross_navigation_pending()); 539 EXPECT_EQ(pending_rvh, rvh()); 540 EXPECT_NE(instance1, instance2); 541 EXPECT_TRUE(contents()->pending_rvh() == NULL); 542 } 543 544 // Test that during a slow cross-site navigation, the original renderer can 545 // navigate to a different URL and have it displayed, canceling the slow 546 // navigation. 547 TEST_F(TabContentsTest, CrossSiteNavigationPreempted) { 548 contents()->transition_cross_site = true; 549 TestRenderViewHost* orig_rvh = rvh(); 550 SiteInstance* instance1 = contents()->GetSiteInstance(); 551 552 // Navigate to URL. First URL should use first RenderViewHost. 553 const GURL url("http://www.google.com"); 554 controller().LoadURL(url, GURL(), PageTransition::TYPED); 555 ViewHostMsg_FrameNavigate_Params params1; 556 InitNavigateParams(¶ms1, 1, url); 557 contents()->TestDidNavigate(orig_rvh, params1); 558 EXPECT_FALSE(contents()->cross_navigation_pending()); 559 EXPECT_EQ(orig_rvh, contents()->render_view_host()); 560 561 // Navigate to new site, simulating an onbeforeunload approval. 562 const GURL url2("http://www.yahoo.com"); 563 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 564 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 565 orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true)); 566 EXPECT_TRUE(contents()->cross_navigation_pending()); 567 568 // Suppose the original renderer navigates before the new one is ready. 569 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo")); 570 571 // Verify that the pending navigation is cancelled. 572 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 573 SiteInstance* instance2 = contents()->GetSiteInstance(); 574 EXPECT_FALSE(contents()->cross_navigation_pending()); 575 EXPECT_EQ(orig_rvh, rvh()); 576 EXPECT_EQ(instance1, instance2); 577 EXPECT_TRUE(contents()->pending_rvh() == NULL); 578 } 579 580 TEST_F(TabContentsTest, CrossSiteNavigationBackPreempted) { 581 contents()->transition_cross_site = true; 582 583 // Start with NTP, which gets a new RVH with WebUI bindings. 584 const GURL url1("chrome://newtab"); 585 controller().LoadURL(url1, GURL(), PageTransition::TYPED); 586 TestRenderViewHost* ntp_rvh = rvh(); 587 ViewHostMsg_FrameNavigate_Params params1; 588 InitNavigateParams(¶ms1, 1, url1); 589 contents()->TestDidNavigate(ntp_rvh, params1); 590 NavigationEntry* entry1 = controller().GetLastCommittedEntry(); 591 SiteInstance* instance1 = contents()->GetSiteInstance(); 592 593 EXPECT_FALSE(contents()->cross_navigation_pending()); 594 EXPECT_EQ(ntp_rvh, contents()->render_view_host()); 595 EXPECT_EQ(url1, entry1->url()); 596 EXPECT_EQ(instance1, entry1->site_instance()); 597 EXPECT_TRUE(BindingsPolicy::is_web_ui_enabled(ntp_rvh->enabled_bindings())); 598 599 // Navigate to new site. 600 const GURL url2("http://www.google.com"); 601 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 602 EXPECT_TRUE(contents()->cross_navigation_pending()); 603 TestRenderViewHost* google_rvh = contents()->pending_rvh(); 604 605 // Simulate beforeunload approval. 606 EXPECT_TRUE(ntp_rvh->is_waiting_for_beforeunload_ack()); 607 ntp_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true)); 608 609 // DidNavigate from the pending page. 610 ViewHostMsg_FrameNavigate_Params params2; 611 InitNavigateParams(¶ms2, 1, url2); 612 contents()->TestDidNavigate(google_rvh, params2); 613 NavigationEntry* entry2 = controller().GetLastCommittedEntry(); 614 SiteInstance* instance2 = contents()->GetSiteInstance(); 615 616 EXPECT_FALSE(contents()->cross_navigation_pending()); 617 EXPECT_EQ(google_rvh, contents()->render_view_host()); 618 EXPECT_NE(instance1, instance2); 619 EXPECT_FALSE(contents()->pending_rvh()); 620 EXPECT_EQ(url2, entry2->url()); 621 EXPECT_EQ(instance2, entry2->site_instance()); 622 EXPECT_FALSE(BindingsPolicy::is_web_ui_enabled( 623 google_rvh->enabled_bindings())); 624 625 // Navigate to third page on same site. 626 const GURL url3("http://news.google.com"); 627 controller().LoadURL(url3, GURL(), PageTransition::TYPED); 628 EXPECT_FALSE(contents()->cross_navigation_pending()); 629 ViewHostMsg_FrameNavigate_Params params3; 630 InitNavigateParams(¶ms3, 2, url3); 631 contents()->TestDidNavigate(google_rvh, params3); 632 NavigationEntry* entry3 = controller().GetLastCommittedEntry(); 633 SiteInstance* instance3 = contents()->GetSiteInstance(); 634 635 EXPECT_FALSE(contents()->cross_navigation_pending()); 636 EXPECT_EQ(google_rvh, contents()->render_view_host()); 637 EXPECT_EQ(instance2, instance3); 638 EXPECT_FALSE(contents()->pending_rvh()); 639 EXPECT_EQ(url3, entry3->url()); 640 EXPECT_EQ(instance3, entry3->site_instance()); 641 642 // Go back within the site. 643 controller().GoBack(); 644 EXPECT_FALSE(contents()->cross_navigation_pending()); 645 EXPECT_EQ(entry2, controller().pending_entry()); 646 647 // Before that commits, go back again. 648 controller().GoBack(); 649 EXPECT_TRUE(contents()->cross_navigation_pending()); 650 EXPECT_TRUE(contents()->pending_rvh()); 651 EXPECT_EQ(entry1, controller().pending_entry()); 652 653 // Simulate beforeunload approval. 654 EXPECT_TRUE(google_rvh->is_waiting_for_beforeunload_ack()); 655 google_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true)); 656 657 // DidNavigate from the first back. This aborts the second back's pending RVH. 658 contents()->TestDidNavigate(google_rvh, params2); 659 660 // We should commit this page and forget about the second back. 661 EXPECT_FALSE(contents()->cross_navigation_pending()); 662 EXPECT_FALSE(controller().pending_entry()); 663 EXPECT_EQ(google_rvh, contents()->render_view_host()); 664 EXPECT_EQ(url2, controller().GetLastCommittedEntry()->url()); 665 666 // We should not have corrupted the NTP entry. 667 EXPECT_EQ(instance3, entry3->site_instance()); 668 EXPECT_EQ(instance2, entry2->site_instance()); 669 EXPECT_EQ(instance1, entry1->site_instance()); 670 EXPECT_EQ(url1, entry1->url()); 671 } 672 673 // Test that during a slow cross-site navigation, a sub-frame navigation in the 674 // original renderer will not cancel the slow navigation (bug 42029). 675 TEST_F(TabContentsTest, CrossSiteNavigationNotPreemptedByFrame) { 676 contents()->transition_cross_site = true; 677 TestRenderViewHost* orig_rvh = rvh(); 678 679 // Navigate to URL. First URL should use first RenderViewHost. 680 const GURL url("http://www.google.com"); 681 controller().LoadURL(url, GURL(), PageTransition::TYPED); 682 ViewHostMsg_FrameNavigate_Params params1; 683 InitNavigateParams(¶ms1, 1, url); 684 contents()->TestDidNavigate(orig_rvh, params1); 685 EXPECT_FALSE(contents()->cross_navigation_pending()); 686 EXPECT_EQ(orig_rvh, contents()->render_view_host()); 687 688 // Start navigating to new site. 689 const GURL url2("http://www.yahoo.com"); 690 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 691 692 // Simulate a sub-frame navigation arriving and ensure the RVH is still 693 // waiting for a before unload response. 694 orig_rvh->SendNavigateWithTransition(1, GURL("http://google.com/frame"), 695 PageTransition::AUTO_SUBFRAME); 696 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 697 698 // Now simulate the onbeforeunload approval and verify the navigation is 699 // not canceled. 700 orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true)); 701 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 702 EXPECT_TRUE(contents()->cross_navigation_pending()); 703 } 704 705 // Test that a cross-site navigation is not preempted if the previous 706 // renderer sends a FrameNavigate message just before being told to stop. 707 // We should only preempt the cross-site navigation if the previous renderer 708 // has started a new navigation. See http://crbug.com/79176. 709 TEST_F(TabContentsTest, CrossSiteNotPreemptedDuringBeforeUnload) { 710 contents()->transition_cross_site = true; 711 712 // Navigate to NTP URL. 713 const GURL url("chrome://newtab"); 714 controller().LoadURL(url, GURL(), PageTransition::TYPED); 715 TestRenderViewHost* orig_rvh = rvh(); 716 EXPECT_FALSE(contents()->cross_navigation_pending()); 717 718 // Navigate to new site, with the beforeunload request in flight. 719 const GURL url2("http://www.yahoo.com"); 720 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 721 TestRenderViewHost* pending_rvh = contents()->pending_rvh(); 722 EXPECT_TRUE(contents()->cross_navigation_pending()); 723 EXPECT_TRUE(orig_rvh->is_waiting_for_beforeunload_ack()); 724 725 // Suppose the first navigation tries to commit now, with a 726 // ViewMsg_Stop in flight. This should not cancel the pending navigation, 727 // but it should act as if the beforeunload ack arrived. 728 orig_rvh->SendNavigate(1, GURL("chrome://newtab")); 729 EXPECT_TRUE(contents()->cross_navigation_pending()); 730 EXPECT_EQ(orig_rvh, contents()->render_view_host()); 731 EXPECT_FALSE(orig_rvh->is_waiting_for_beforeunload_ack()); 732 733 // The pending navigation should be able to commit successfully. 734 ViewHostMsg_FrameNavigate_Params params2; 735 InitNavigateParams(¶ms2, 1, url2, PageTransition::TYPED); 736 contents()->TestDidNavigate(pending_rvh, params2); 737 EXPECT_FALSE(contents()->cross_navigation_pending()); 738 EXPECT_EQ(pending_rvh, contents()->render_view_host()); 739 } 740 741 // Test that the original renderer cannot preempt a cross-site navigation once 742 // the unload request has been made. At this point, the cross-site navigation 743 // is almost ready to be displayed, and the original renderer is only given a 744 // short chance to run an unload handler. Prevents regression of bug 23942. 745 TEST_F(TabContentsTest, CrossSiteCantPreemptAfterUnload) { 746 contents()->transition_cross_site = true; 747 TestRenderViewHost* orig_rvh = rvh(); 748 SiteInstance* instance1 = contents()->GetSiteInstance(); 749 750 // Navigate to URL. First URL should use first RenderViewHost. 751 const GURL url("http://www.google.com"); 752 controller().LoadURL(url, GURL(), PageTransition::TYPED); 753 ViewHostMsg_FrameNavigate_Params params1; 754 InitNavigateParams(¶ms1, 1, url); 755 contents()->TestDidNavigate(orig_rvh, params1); 756 EXPECT_FALSE(contents()->cross_navigation_pending()); 757 EXPECT_EQ(orig_rvh, contents()->render_view_host()); 758 759 // Navigate to new site, simulating an onbeforeunload approval. 760 const GURL url2("http://www.yahoo.com"); 761 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 762 orig_rvh->TestOnMessageReceived(ViewHostMsg_ShouldClose_ACK(0, true)); 763 EXPECT_TRUE(contents()->cross_navigation_pending()); 764 TestRenderViewHost* pending_rvh = static_cast<TestRenderViewHost*>( 765 contents()->pending_rvh()); 766 767 // Simulate the pending renderer's response, which leads to an unload request 768 // being sent to orig_rvh. 769 contents()->OnCrossSiteResponse(0, 0); 770 771 // Suppose the original renderer navigates now, while the unload request is in 772 // flight. We should ignore it, wait for the unload ack, and let the pending 773 // request continue. Otherwise, the tab may close spontaneously or stop 774 // responding to navigation requests. (See bug 23942.) 775 ViewHostMsg_FrameNavigate_Params params1a; 776 InitNavigateParams(¶ms1a, 2, GURL("http://www.google.com/foo")); 777 orig_rvh->SendNavigate(2, GURL("http://www.google.com/foo")); 778 779 // Verify that the pending navigation is still in progress. 780 EXPECT_TRUE(contents()->cross_navigation_pending()); 781 EXPECT_TRUE(contents()->pending_rvh() != NULL); 782 783 // DidNavigate from the pending page should commit it. 784 ViewHostMsg_FrameNavigate_Params params2; 785 InitNavigateParams(¶ms2, 1, url2); 786 contents()->TestDidNavigate(pending_rvh, params2); 787 SiteInstance* instance2 = contents()->GetSiteInstance(); 788 EXPECT_FALSE(contents()->cross_navigation_pending()); 789 EXPECT_EQ(pending_rvh, rvh()); 790 EXPECT_NE(instance1, instance2); 791 EXPECT_TRUE(contents()->pending_rvh() == NULL); 792 } 793 794 // Test that NavigationEntries have the correct content state after going 795 // forward and back. Prevents regression for bug 1116137. 796 TEST_F(TabContentsTest, NavigationEntryContentState) { 797 TestRenderViewHost* orig_rvh = rvh(); 798 799 // Navigate to URL. There should be no committed entry yet. 800 const GURL url("http://www.google.com"); 801 controller().LoadURL(url, GURL(), PageTransition::TYPED); 802 NavigationEntry* entry = controller().GetLastCommittedEntry(); 803 EXPECT_TRUE(entry == NULL); 804 805 // Committed entry should have content state after DidNavigate. 806 ViewHostMsg_FrameNavigate_Params params1; 807 InitNavigateParams(¶ms1, 1, url); 808 contents()->TestDidNavigate(orig_rvh, params1); 809 entry = controller().GetLastCommittedEntry(); 810 EXPECT_FALSE(entry->content_state().empty()); 811 812 // Navigate to same site. 813 const GURL url2("http://images.google.com"); 814 controller().LoadURL(url2, GURL(), PageTransition::TYPED); 815 entry = controller().GetLastCommittedEntry(); 816 EXPECT_FALSE(entry->content_state().empty()); 817 818 // Committed entry should have content state after DidNavigate. 819 ViewHostMsg_FrameNavigate_Params params2; 820 InitNavigateParams(¶ms2, 2, url2); 821 contents()->TestDidNavigate(orig_rvh, params2); 822 entry = controller().GetLastCommittedEntry(); 823 EXPECT_FALSE(entry->content_state().empty()); 824 825 // Now go back. Committed entry should still have content state. 826 controller().GoBack(); 827 contents()->TestDidNavigate(orig_rvh, params1); 828 entry = controller().GetLastCommittedEntry(); 829 EXPECT_FALSE(entry->content_state().empty()); 830 } 831 832 // Test that NavigationEntries have the correct content state after opening 833 // a new window to about:blank. Prevents regression for bug 1116137. 834 TEST_F(TabContentsTest, NavigationEntryContentStateNewWindow) { 835 TestRenderViewHost* orig_rvh = rvh(); 836 837 // When opening a new window, it is navigated to about:blank internally. 838 // Currently, this results in two DidNavigate events. 839 const GURL url(chrome::kAboutBlankURL); 840 ViewHostMsg_FrameNavigate_Params params1; 841 InitNavigateParams(¶ms1, 1, url); 842 contents()->TestDidNavigate(orig_rvh, params1); 843 contents()->TestDidNavigate(orig_rvh, params1); 844 845 // Should have a content state here. 846 NavigationEntry* entry = controller().GetLastCommittedEntry(); 847 EXPECT_FALSE(entry->content_state().empty()); 848 } 849 850 // Tests to see that webkit preferences are properly loaded and copied over 851 // to a WebPreferences object. 852 TEST_F(TabContentsTest, WebKitPrefs) { 853 WebPreferences webkit_prefs = contents()->TestGetWebkitPrefs(); 854 855 // These values have been overridden by the profile preferences. 856 EXPECT_EQ("UTF-8", webkit_prefs.default_encoding); 857 EXPECT_EQ(20, webkit_prefs.default_font_size); 858 EXPECT_FALSE(webkit_prefs.text_areas_are_resizable); 859 EXPECT_TRUE(webkit_prefs.uses_universal_detector); 860 861 // These should still be the default values. 862 #if defined(OS_MACOSX) 863 const char kDefaultFont[] = "Times"; 864 #elif defined(OS_CHROMEOS) 865 const char kDefaultFont[] = "Tinos"; 866 #else 867 const char kDefaultFont[] = "Times New Roman"; 868 #endif 869 EXPECT_EQ(ASCIIToUTF16(kDefaultFont), webkit_prefs.standard_font_family); 870 EXPECT_TRUE(webkit_prefs.javascript_enabled); 871 } 872 873 //////////////////////////////////////////////////////////////////////////////// 874 // Interstitial Tests 875 //////////////////////////////////////////////////////////////////////////////// 876 877 // Test navigating to a page (with the navigation initiated from the browser, 878 // as when a URL is typed in the location bar) that shows an interstitial and 879 // creates a new navigation entry, then hiding it without proceeding. 880 TEST_F(TabContentsTest, 881 ShowInterstitialFromBrowserWithNewNavigationDontProceed) { 882 // Navigate to a page. 883 GURL url1("http://www.google.com"); 884 rvh()->SendNavigate(1, url1); 885 EXPECT_EQ(1, controller().entry_count()); 886 887 // Initiate a browser navigation that will trigger the interstitial 888 controller().LoadURL(GURL("http://www.evil.com"), GURL(), 889 PageTransition::TYPED); 890 891 // Show an interstitial. 892 TestInterstitialPage::InterstitialState state = 893 TestInterstitialPage::UNDECIDED; 894 bool deleted = false; 895 GURL url2("http://interstitial"); 896 TestInterstitialPage* interstitial = 897 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 898 TestInterstitialPageStateGuard state_guard(interstitial); 899 interstitial->Show(); 900 // The interstitial should not show until its navigation has committed. 901 EXPECT_FALSE(interstitial->is_showing()); 902 EXPECT_FALSE(contents()->showing_interstitial_page()); 903 EXPECT_TRUE(contents()->interstitial_page() == NULL); 904 // Let's commit the interstitial navigation. 905 interstitial->TestDidNavigate(1, url2); 906 EXPECT_TRUE(interstitial->is_showing()); 907 EXPECT_TRUE(contents()->showing_interstitial_page()); 908 EXPECT_TRUE(contents()->interstitial_page() == interstitial); 909 NavigationEntry* entry = controller().GetActiveEntry(); 910 ASSERT_TRUE(entry != NULL); 911 EXPECT_TRUE(entry->url() == url2); 912 913 // Now don't proceed. 914 interstitial->DontProceed(); 915 EXPECT_TRUE(deleted); 916 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 917 EXPECT_FALSE(contents()->showing_interstitial_page()); 918 EXPECT_TRUE(contents()->interstitial_page() == NULL); 919 entry = controller().GetActiveEntry(); 920 ASSERT_TRUE(entry != NULL); 921 EXPECT_TRUE(entry->url() == url1); 922 EXPECT_EQ(1, controller().entry_count()); 923 } 924 925 // Test navigating to a page (with the navigation initiated from the renderer, 926 // as when clicking on a link in the page) that shows an interstitial and 927 // creates a new navigation entry, then hiding it without proceeding. 928 TEST_F(TabContentsTest, 929 ShowInterstitiaFromRendererlWithNewNavigationDontProceed) { 930 // Navigate to a page. 931 GURL url1("http://www.google.com"); 932 rvh()->SendNavigate(1, url1); 933 EXPECT_EQ(1, controller().entry_count()); 934 935 // Show an interstitial (no pending entry, the interstitial would have been 936 // triggered by clicking on a link). 937 TestInterstitialPage::InterstitialState state = 938 TestInterstitialPage::UNDECIDED; 939 bool deleted = false; 940 GURL url2("http://interstitial"); 941 TestInterstitialPage* interstitial = 942 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 943 TestInterstitialPageStateGuard state_guard(interstitial); 944 interstitial->Show(); 945 // The interstitial should not show until its navigation has committed. 946 EXPECT_FALSE(interstitial->is_showing()); 947 EXPECT_FALSE(contents()->showing_interstitial_page()); 948 EXPECT_TRUE(contents()->interstitial_page() == NULL); 949 // Let's commit the interstitial navigation. 950 interstitial->TestDidNavigate(1, url2); 951 EXPECT_TRUE(interstitial->is_showing()); 952 EXPECT_TRUE(contents()->showing_interstitial_page()); 953 EXPECT_TRUE(contents()->interstitial_page() == interstitial); 954 NavigationEntry* entry = controller().GetActiveEntry(); 955 ASSERT_TRUE(entry != NULL); 956 EXPECT_TRUE(entry->url() == url2); 957 958 // Now don't proceed. 959 interstitial->DontProceed(); 960 EXPECT_TRUE(deleted); 961 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 962 EXPECT_FALSE(contents()->showing_interstitial_page()); 963 EXPECT_TRUE(contents()->interstitial_page() == NULL); 964 entry = controller().GetActiveEntry(); 965 ASSERT_TRUE(entry != NULL); 966 EXPECT_TRUE(entry->url() == url1); 967 EXPECT_EQ(1, controller().entry_count()); 968 } 969 970 // Test navigating to a page that shows an interstitial without creating a new 971 // navigation entry (this happens when the interstitial is triggered by a 972 // sub-resource in the page), then hiding it without proceeding. 973 TEST_F(TabContentsTest, ShowInterstitialNoNewNavigationDontProceed) { 974 // Navigate to a page. 975 GURL url1("http://www.google.com"); 976 rvh()->SendNavigate(1, url1); 977 EXPECT_EQ(1, controller().entry_count()); 978 979 // Show an interstitial. 980 TestInterstitialPage::InterstitialState state = 981 TestInterstitialPage::UNDECIDED; 982 bool deleted = false; 983 GURL url2("http://interstitial"); 984 TestInterstitialPage* interstitial = 985 new TestInterstitialPage(contents(), false, url2, &state, &deleted); 986 TestInterstitialPageStateGuard state_guard(interstitial); 987 interstitial->Show(); 988 // The interstitial should not show until its navigation has committed. 989 EXPECT_FALSE(interstitial->is_showing()); 990 EXPECT_FALSE(contents()->showing_interstitial_page()); 991 EXPECT_TRUE(contents()->interstitial_page() == NULL); 992 // Let's commit the interstitial navigation. 993 interstitial->TestDidNavigate(1, url2); 994 EXPECT_TRUE(interstitial->is_showing()); 995 EXPECT_TRUE(contents()->showing_interstitial_page()); 996 EXPECT_TRUE(contents()->interstitial_page() == interstitial); 997 NavigationEntry* entry = controller().GetActiveEntry(); 998 ASSERT_TRUE(entry != NULL); 999 // The URL specified to the interstitial should have been ignored. 1000 EXPECT_TRUE(entry->url() == url1); 1001 1002 // Now don't proceed. 1003 interstitial->DontProceed(); 1004 EXPECT_TRUE(deleted); 1005 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1006 EXPECT_FALSE(contents()->showing_interstitial_page()); 1007 EXPECT_TRUE(contents()->interstitial_page() == NULL); 1008 entry = controller().GetActiveEntry(); 1009 ASSERT_TRUE(entry != NULL); 1010 EXPECT_TRUE(entry->url() == url1); 1011 EXPECT_EQ(1, controller().entry_count()); 1012 } 1013 1014 // Test navigating to a page (with the navigation initiated from the browser, 1015 // as when a URL is typed in the location bar) that shows an interstitial and 1016 // creates a new navigation entry, then proceeding. 1017 TEST_F(TabContentsTest, 1018 ShowInterstitialFromBrowserNewNavigationProceed) { 1019 // Navigate to a page. 1020 GURL url1("http://www.google.com"); 1021 rvh()->SendNavigate(1, url1); 1022 EXPECT_EQ(1, controller().entry_count()); 1023 1024 // Initiate a browser navigation that will trigger the interstitial 1025 controller().LoadURL(GURL("http://www.evil.com"), GURL(), 1026 PageTransition::TYPED); 1027 1028 // Show an interstitial. 1029 TestInterstitialPage::InterstitialState state = 1030 TestInterstitialPage::UNDECIDED; 1031 bool deleted = false; 1032 GURL url2("http://interstitial"); 1033 TestInterstitialPage* interstitial = 1034 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 1035 TestInterstitialPageStateGuard state_guard(interstitial); 1036 interstitial->Show(); 1037 // The interstitial should not show until its navigation has committed. 1038 EXPECT_FALSE(interstitial->is_showing()); 1039 EXPECT_FALSE(contents()->showing_interstitial_page()); 1040 EXPECT_TRUE(contents()->interstitial_page() == NULL); 1041 // Let's commit the interstitial navigation. 1042 interstitial->TestDidNavigate(1, url2); 1043 EXPECT_TRUE(interstitial->is_showing()); 1044 EXPECT_TRUE(contents()->showing_interstitial_page()); 1045 EXPECT_TRUE(contents()->interstitial_page() == interstitial); 1046 NavigationEntry* entry = controller().GetActiveEntry(); 1047 ASSERT_TRUE(entry != NULL); 1048 EXPECT_TRUE(entry->url() == url2); 1049 1050 // Then proceed. 1051 interstitial->Proceed(); 1052 // The interstitial should show until the new navigation commits. 1053 ASSERT_FALSE(deleted); 1054 EXPECT_EQ(TestInterstitialPage::OKED, state); 1055 EXPECT_TRUE(contents()->showing_interstitial_page()); 1056 EXPECT_TRUE(contents()->interstitial_page() == interstitial); 1057 1058 // Simulate the navigation to the page, that's when the interstitial gets 1059 // hidden. 1060 GURL url3("http://www.thepage.com"); 1061 rvh()->SendNavigate(2, url3); 1062 1063 EXPECT_TRUE(deleted); 1064 EXPECT_FALSE(contents()->showing_interstitial_page()); 1065 EXPECT_TRUE(contents()->interstitial_page() == NULL); 1066 entry = controller().GetActiveEntry(); 1067 ASSERT_TRUE(entry != NULL); 1068 EXPECT_TRUE(entry->url() == url3); 1069 1070 EXPECT_EQ(2, controller().entry_count()); 1071 } 1072 1073 // Test navigating to a page (with the navigation initiated from the renderer, 1074 // as when clicking on a link in the page) that shows an interstitial and 1075 // creates a new navigation entry, then proceeding. 1076 TEST_F(TabContentsTest, 1077 ShowInterstitialFromRendererNewNavigationProceed) { 1078 // Navigate to a page. 1079 GURL url1("http://www.google.com"); 1080 rvh()->SendNavigate(1, url1); 1081 EXPECT_EQ(1, controller().entry_count()); 1082 1083 // Show an interstitial. 1084 TestInterstitialPage::InterstitialState state = 1085 TestInterstitialPage::UNDECIDED; 1086 bool deleted = false; 1087 GURL url2("http://interstitial"); 1088 TestInterstitialPage* interstitial = 1089 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 1090 TestInterstitialPageStateGuard state_guard(interstitial); 1091 interstitial->Show(); 1092 // The interstitial should not show until its navigation has committed. 1093 EXPECT_FALSE(interstitial->is_showing()); 1094 EXPECT_FALSE(contents()->showing_interstitial_page()); 1095 EXPECT_TRUE(contents()->interstitial_page() == NULL); 1096 // Let's commit the interstitial navigation. 1097 interstitial->TestDidNavigate(1, url2); 1098 EXPECT_TRUE(interstitial->is_showing()); 1099 EXPECT_TRUE(contents()->showing_interstitial_page()); 1100 EXPECT_TRUE(contents()->interstitial_page() == interstitial); 1101 NavigationEntry* entry = controller().GetActiveEntry(); 1102 ASSERT_TRUE(entry != NULL); 1103 EXPECT_TRUE(entry->url() == url2); 1104 1105 // Then proceed. 1106 interstitial->Proceed(); 1107 // The interstitial should show until the new navigation commits. 1108 ASSERT_FALSE(deleted); 1109 EXPECT_EQ(TestInterstitialPage::OKED, state); 1110 EXPECT_TRUE(contents()->showing_interstitial_page()); 1111 EXPECT_TRUE(contents()->interstitial_page() == interstitial); 1112 1113 // Simulate the navigation to the page, that's when the interstitial gets 1114 // hidden. 1115 GURL url3("http://www.thepage.com"); 1116 rvh()->SendNavigate(2, url3); 1117 1118 EXPECT_TRUE(deleted); 1119 EXPECT_FALSE(contents()->showing_interstitial_page()); 1120 EXPECT_TRUE(contents()->interstitial_page() == NULL); 1121 entry = controller().GetActiveEntry(); 1122 ASSERT_TRUE(entry != NULL); 1123 EXPECT_TRUE(entry->url() == url3); 1124 1125 EXPECT_EQ(2, controller().entry_count()); 1126 } 1127 1128 // Test navigating to a page that shows an interstitial without creating a new 1129 // navigation entry (this happens when the interstitial is triggered by a 1130 // sub-resource in the page), then proceeding. 1131 TEST_F(TabContentsTest, ShowInterstitialNoNewNavigationProceed) { 1132 // Navigate to a page so we have a navigation entry in the controller. 1133 GURL url1("http://www.google.com"); 1134 rvh()->SendNavigate(1, url1); 1135 EXPECT_EQ(1, controller().entry_count()); 1136 1137 // Show an interstitial. 1138 TestInterstitialPage::InterstitialState state = 1139 TestInterstitialPage::UNDECIDED; 1140 bool deleted = false; 1141 GURL url2("http://interstitial"); 1142 TestInterstitialPage* interstitial = 1143 new TestInterstitialPage(contents(), false, url2, &state, &deleted); 1144 TestInterstitialPageStateGuard state_guard(interstitial); 1145 interstitial->Show(); 1146 // The interstitial should not show until its navigation has committed. 1147 EXPECT_FALSE(interstitial->is_showing()); 1148 EXPECT_FALSE(contents()->showing_interstitial_page()); 1149 EXPECT_TRUE(contents()->interstitial_page() == NULL); 1150 // Let's commit the interstitial navigation. 1151 interstitial->TestDidNavigate(1, url2); 1152 EXPECT_TRUE(interstitial->is_showing()); 1153 EXPECT_TRUE(contents()->showing_interstitial_page()); 1154 EXPECT_TRUE(contents()->interstitial_page() == interstitial); 1155 NavigationEntry* entry = controller().GetActiveEntry(); 1156 ASSERT_TRUE(entry != NULL); 1157 // The URL specified to the interstitial should have been ignored. 1158 EXPECT_TRUE(entry->url() == url1); 1159 1160 // Then proceed. 1161 interstitial->Proceed(); 1162 // Since this is not a new navigation, the previous page is dismissed right 1163 // away and shows the original page. 1164 EXPECT_TRUE(deleted); 1165 EXPECT_EQ(TestInterstitialPage::OKED, state); 1166 EXPECT_FALSE(contents()->showing_interstitial_page()); 1167 EXPECT_TRUE(contents()->interstitial_page() == NULL); 1168 entry = controller().GetActiveEntry(); 1169 ASSERT_TRUE(entry != NULL); 1170 EXPECT_TRUE(entry->url() == url1); 1171 1172 EXPECT_EQ(1, controller().entry_count()); 1173 } 1174 1175 // Test navigating to a page that shows an interstitial, then navigating away. 1176 TEST_F(TabContentsTest, ShowInterstitialThenNavigate) { 1177 // Show interstitial. 1178 TestInterstitialPage::InterstitialState state = 1179 TestInterstitialPage::UNDECIDED; 1180 bool deleted = false; 1181 GURL url("http://interstitial"); 1182 TestInterstitialPage* interstitial = 1183 new TestInterstitialPage(contents(), true, url, &state, &deleted); 1184 TestInterstitialPageStateGuard state_guard(interstitial); 1185 interstitial->Show(); 1186 interstitial->TestDidNavigate(1, url); 1187 1188 // While interstitial showing, navigate to a new URL. 1189 const GURL url2("http://www.yahoo.com"); 1190 rvh()->SendNavigate(1, url2); 1191 1192 EXPECT_TRUE(deleted); 1193 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1194 } 1195 1196 // Test navigating to a page that shows an interstitial, then going back. 1197 TEST_F(TabContentsTest, ShowInterstitialThenGoBack) { 1198 // Navigate to a page so we have a navigation entry in the controller. 1199 GURL url1("http://www.google.com"); 1200 rvh()->SendNavigate(1, url1); 1201 EXPECT_EQ(1, controller().entry_count()); 1202 1203 // Show interstitial. 1204 TestInterstitialPage::InterstitialState state = 1205 TestInterstitialPage::UNDECIDED; 1206 bool deleted = false; 1207 GURL interstitial_url("http://interstitial"); 1208 TestInterstitialPage* interstitial = 1209 new TestInterstitialPage(contents(), true, interstitial_url, 1210 &state, &deleted); 1211 TestInterstitialPageStateGuard state_guard(interstitial); 1212 interstitial->Show(); 1213 interstitial->TestDidNavigate(2, interstitial_url); 1214 1215 // While the interstitial is showing, go back. 1216 controller().GoBack(); 1217 rvh()->SendNavigate(1, url1); 1218 1219 // Make sure we are back to the original page and that the interstitial is 1220 // gone. 1221 EXPECT_TRUE(deleted); 1222 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1223 NavigationEntry* entry = controller().GetActiveEntry(); 1224 ASSERT_TRUE(entry); 1225 EXPECT_EQ(url1.spec(), entry->url().spec()); 1226 } 1227 1228 // Test navigating to a page that shows an interstitial, has a renderer crash, 1229 // and then goes back. 1230 TEST_F(TabContentsTest, ShowInterstitialCrashRendererThenGoBack) { 1231 // Navigate to a page so we have a navigation entry in the controller. 1232 GURL url1("http://www.google.com"); 1233 rvh()->SendNavigate(1, url1); 1234 EXPECT_EQ(1, controller().entry_count()); 1235 1236 // Show interstitial. 1237 TestInterstitialPage::InterstitialState state = 1238 TestInterstitialPage::UNDECIDED; 1239 bool deleted = false; 1240 GURL interstitial_url("http://interstitial"); 1241 TestInterstitialPage* interstitial = 1242 new TestInterstitialPage(contents(), true, interstitial_url, 1243 &state, &deleted); 1244 TestInterstitialPageStateGuard state_guard(interstitial); 1245 interstitial->Show(); 1246 interstitial->TestDidNavigate(2, interstitial_url); 1247 1248 // Crash the renderer 1249 rvh()->TestOnMessageReceived( 1250 ViewHostMsg_RenderViewGone( 1251 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1)); 1252 1253 // While the interstitial is showing, go back. 1254 controller().GoBack(); 1255 rvh()->SendNavigate(1, url1); 1256 1257 // Make sure we are back to the original page and that the interstitial is 1258 // gone. 1259 EXPECT_TRUE(deleted); 1260 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1261 NavigationEntry* entry = controller().GetActiveEntry(); 1262 ASSERT_TRUE(entry); 1263 EXPECT_EQ(url1.spec(), entry->url().spec()); 1264 } 1265 1266 // Test navigating to a page that shows an interstitial, has the renderer crash, 1267 // and then navigates to the interstitial. 1268 TEST_F(TabContentsTest, ShowInterstitialCrashRendererThenNavigate) { 1269 // Navigate to a page so we have a navigation entry in the controller. 1270 GURL url1("http://www.google.com"); 1271 rvh()->SendNavigate(1, url1); 1272 EXPECT_EQ(1, controller().entry_count()); 1273 1274 // Show interstitial. 1275 TestInterstitialPage::InterstitialState state = 1276 TestInterstitialPage::UNDECIDED; 1277 bool deleted = false; 1278 GURL interstitial_url("http://interstitial"); 1279 TestInterstitialPage* interstitial = 1280 new TestInterstitialPage(contents(), true, interstitial_url, 1281 &state, &deleted); 1282 TestInterstitialPageStateGuard state_guard(interstitial); 1283 interstitial->Show(); 1284 1285 // Crash the renderer 1286 rvh()->TestOnMessageReceived( 1287 ViewHostMsg_RenderViewGone( 1288 0, base::TERMINATION_STATUS_PROCESS_CRASHED, -1)); 1289 1290 interstitial->TestDidNavigate(2, interstitial_url); 1291 } 1292 1293 // Test navigating to a page that shows an interstitial, then close the tab. 1294 TEST_F(TabContentsTest, ShowInterstitialThenCloseTab) { 1295 // Show interstitial. 1296 TestInterstitialPage::InterstitialState state = 1297 TestInterstitialPage::UNDECIDED; 1298 bool deleted = false; 1299 GURL url("http://interstitial"); 1300 TestInterstitialPage* interstitial = 1301 new TestInterstitialPage(contents(), true, url, &state, &deleted); 1302 TestInterstitialPageStateGuard state_guard(interstitial); 1303 interstitial->Show(); 1304 interstitial->TestDidNavigate(1, url); 1305 1306 // Now close the tab. 1307 DeleteContents(); 1308 EXPECT_TRUE(deleted); 1309 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1310 } 1311 1312 // Test that after Proceed is called and an interstitial is still shown, no more 1313 // commands get executed. 1314 TEST_F(TabContentsTest, ShowInterstitialProceedMultipleCommands) { 1315 // Navigate to a page so we have a navigation entry in the controller. 1316 GURL url1("http://www.google.com"); 1317 rvh()->SendNavigate(1, url1); 1318 EXPECT_EQ(1, controller().entry_count()); 1319 1320 // Show an interstitial. 1321 TestInterstitialPage::InterstitialState state = 1322 TestInterstitialPage::UNDECIDED; 1323 bool deleted = false; 1324 GURL url2("http://interstitial"); 1325 TestInterstitialPage* interstitial = 1326 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 1327 TestInterstitialPageStateGuard state_guard(interstitial); 1328 interstitial->Show(); 1329 interstitial->TestDidNavigate(1, url2); 1330 1331 // Run a command. 1332 EXPECT_EQ(0, interstitial->command_received_count()); 1333 interstitial->TestDomOperationResponse("toto"); 1334 EXPECT_EQ(1, interstitial->command_received_count()); 1335 1336 // Then proceed. 1337 interstitial->Proceed(); 1338 ASSERT_FALSE(deleted); 1339 1340 // While the navigation to the new page is pending, send other commands, they 1341 // should be ignored. 1342 interstitial->TestDomOperationResponse("hello"); 1343 interstitial->TestDomOperationResponse("hi"); 1344 EXPECT_EQ(1, interstitial->command_received_count()); 1345 } 1346 1347 // Test showing an interstitial while another interstitial is already showing. 1348 TEST_F(TabContentsTest, ShowInterstitialOnInterstitial) { 1349 // Navigate to a page so we have a navigation entry in the controller. 1350 GURL start_url("http://www.google.com"); 1351 rvh()->SendNavigate(1, start_url); 1352 EXPECT_EQ(1, controller().entry_count()); 1353 1354 // Show an interstitial. 1355 TestInterstitialPage::InterstitialState state1 = 1356 TestInterstitialPage::UNDECIDED; 1357 bool deleted1 = false; 1358 GURL url1("http://interstitial1"); 1359 TestInterstitialPage* interstitial1 = 1360 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1); 1361 TestInterstitialPageStateGuard state_guard1(interstitial1); 1362 interstitial1->Show(); 1363 interstitial1->TestDidNavigate(1, url1); 1364 1365 // Now show another interstitial. 1366 TestInterstitialPage::InterstitialState state2 = 1367 TestInterstitialPage::UNDECIDED; 1368 bool deleted2 = false; 1369 GURL url2("http://interstitial2"); 1370 TestInterstitialPage* interstitial2 = 1371 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2); 1372 TestInterstitialPageStateGuard state_guard2(interstitial2); 1373 interstitial2->Show(); 1374 interstitial2->TestDidNavigate(1, url2); 1375 1376 // Showing interstitial2 should have caused interstitial1 to go away. 1377 EXPECT_TRUE(deleted1); 1378 EXPECT_EQ(TestInterstitialPage::CANCELED, state1); 1379 1380 // Let's make sure interstitial2 is working as intended. 1381 ASSERT_FALSE(deleted2); 1382 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2); 1383 interstitial2->Proceed(); 1384 GURL landing_url("http://www.thepage.com"); 1385 rvh()->SendNavigate(2, landing_url); 1386 1387 EXPECT_TRUE(deleted2); 1388 EXPECT_FALSE(contents()->showing_interstitial_page()); 1389 EXPECT_TRUE(contents()->interstitial_page() == NULL); 1390 NavigationEntry* entry = controller().GetActiveEntry(); 1391 ASSERT_TRUE(entry != NULL); 1392 EXPECT_TRUE(entry->url() == landing_url); 1393 EXPECT_EQ(2, controller().entry_count()); 1394 } 1395 1396 // Test showing an interstitial, proceeding and then navigating to another 1397 // interstitial. 1398 TEST_F(TabContentsTest, ShowInterstitialProceedShowInterstitial) { 1399 // Navigate to a page so we have a navigation entry in the controller. 1400 GURL start_url("http://www.google.com"); 1401 rvh()->SendNavigate(1, start_url); 1402 EXPECT_EQ(1, controller().entry_count()); 1403 1404 // Show an interstitial. 1405 TestInterstitialPage::InterstitialState state1 = 1406 TestInterstitialPage::UNDECIDED; 1407 bool deleted1 = false; 1408 GURL url1("http://interstitial1"); 1409 TestInterstitialPage* interstitial1 = 1410 new TestInterstitialPage(contents(), true, url1, &state1, &deleted1); 1411 TestInterstitialPageStateGuard state_guard1(interstitial1); 1412 interstitial1->Show(); 1413 interstitial1->TestDidNavigate(1, url1); 1414 1415 // Take action. The interstitial won't be hidden until the navigation is 1416 // committed. 1417 interstitial1->Proceed(); 1418 EXPECT_EQ(TestInterstitialPage::OKED, state1); 1419 1420 // Now show another interstitial (simulating the navigation causing another 1421 // interstitial). 1422 TestInterstitialPage::InterstitialState state2 = 1423 TestInterstitialPage::UNDECIDED; 1424 bool deleted2 = false; 1425 GURL url2("http://interstitial2"); 1426 TestInterstitialPage* interstitial2 = 1427 new TestInterstitialPage(contents(), true, url2, &state2, &deleted2); 1428 TestInterstitialPageStateGuard state_guard2(interstitial2); 1429 interstitial2->Show(); 1430 interstitial2->TestDidNavigate(1, url2); 1431 1432 // Showing interstitial2 should have caused interstitial1 to go away. 1433 EXPECT_TRUE(deleted1); 1434 1435 // Let's make sure interstitial2 is working as intended. 1436 ASSERT_FALSE(deleted2); 1437 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2); 1438 interstitial2->Proceed(); 1439 GURL landing_url("http://www.thepage.com"); 1440 rvh()->SendNavigate(2, landing_url); 1441 1442 EXPECT_TRUE(deleted2); 1443 EXPECT_FALSE(contents()->showing_interstitial_page()); 1444 EXPECT_TRUE(contents()->interstitial_page() == NULL); 1445 NavigationEntry* entry = controller().GetActiveEntry(); 1446 ASSERT_TRUE(entry != NULL); 1447 EXPECT_TRUE(entry->url() == landing_url); 1448 EXPECT_EQ(2, controller().entry_count()); 1449 } 1450 1451 // Test that navigating away from an interstitial while it's loading cause it 1452 // not to show. 1453 TEST_F(TabContentsTest, NavigateBeforeInterstitialShows) { 1454 // Show an interstitial. 1455 TestInterstitialPage::InterstitialState state = 1456 TestInterstitialPage::UNDECIDED; 1457 bool deleted = false; 1458 GURL interstitial_url("http://interstitial"); 1459 TestInterstitialPage* interstitial = 1460 new TestInterstitialPage(contents(), true, interstitial_url, 1461 &state, &deleted); 1462 TestInterstitialPageStateGuard state_guard(interstitial); 1463 interstitial->Show(); 1464 1465 // Let's simulate a navigation initiated from the browser before the 1466 // interstitial finishes loading. 1467 const GURL url("http://www.google.com"); 1468 controller().LoadURL(url, GURL(), PageTransition::TYPED); 1469 ASSERT_FALSE(deleted); 1470 EXPECT_FALSE(interstitial->is_showing()); 1471 1472 // Now let's make the interstitial navigation commit. 1473 interstitial->TestDidNavigate(1, interstitial_url); 1474 1475 // After it loaded the interstitial should be gone. 1476 EXPECT_TRUE(deleted); 1477 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1478 } 1479 1480 // Test that a new request to show an interstitial while an interstitial is 1481 // pending does not cause problems. htp://crbug/29655 and htp://crbug/9442. 1482 TEST_F(TabContentsTest, TwoQuickInterstitials) { 1483 GURL interstitial_url("http://interstitial"); 1484 1485 // Show a first interstitial. 1486 TestInterstitialPage::InterstitialState state1 = 1487 TestInterstitialPage::UNDECIDED; 1488 bool deleted1 = false; 1489 TestInterstitialPage* interstitial1 = 1490 new TestInterstitialPage(contents(), true, interstitial_url, 1491 &state1, &deleted1); 1492 TestInterstitialPageStateGuard state_guard1(interstitial1); 1493 interstitial1->Show(); 1494 1495 // Show another interstitial on that same tab before the first one had time 1496 // to load. 1497 TestInterstitialPage::InterstitialState state2 = 1498 TestInterstitialPage::UNDECIDED; 1499 bool deleted2 = false; 1500 TestInterstitialPage* interstitial2 = 1501 new TestInterstitialPage(contents(), true, interstitial_url, 1502 &state2, &deleted2); 1503 TestInterstitialPageStateGuard state_guard2(interstitial2); 1504 interstitial2->Show(); 1505 1506 // The first interstitial should have been closed and deleted. 1507 EXPECT_TRUE(deleted1); 1508 EXPECT_EQ(TestInterstitialPage::CANCELED, state1); 1509 1510 // The 2nd one should still be OK. 1511 ASSERT_FALSE(deleted2); 1512 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2); 1513 1514 // Make the interstitial navigation commit it should be showing. 1515 interstitial2->TestDidNavigate(1, interstitial_url); 1516 EXPECT_EQ(interstitial2, contents()->interstitial_page()); 1517 } 1518 1519 // Test showing an interstitial and have its renderer crash. 1520 TEST_F(TabContentsTest, InterstitialCrasher) { 1521 // Show an interstitial. 1522 TestInterstitialPage::InterstitialState state = 1523 TestInterstitialPage::UNDECIDED; 1524 bool deleted = false; 1525 GURL url("http://interstitial"); 1526 TestInterstitialPage* interstitial = 1527 new TestInterstitialPage(contents(), true, url, &state, &deleted); 1528 TestInterstitialPageStateGuard state_guard(interstitial); 1529 interstitial->Show(); 1530 // Simulate a renderer crash before the interstitial is shown. 1531 interstitial->TestRenderViewGone( 1532 base::TERMINATION_STATUS_PROCESS_CRASHED, -1); 1533 // The interstitial should have been dismissed. 1534 EXPECT_TRUE(deleted); 1535 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1536 1537 // Now try again but this time crash the intersitial after it was shown. 1538 interstitial = 1539 new TestInterstitialPage(contents(), true, url, &state, &deleted); 1540 interstitial->Show(); 1541 interstitial->TestDidNavigate(1, url); 1542 // Simulate a renderer crash. 1543 interstitial->TestRenderViewGone( 1544 base::TERMINATION_STATUS_PROCESS_CRASHED, -1); 1545 // The interstitial should have been dismissed. 1546 EXPECT_TRUE(deleted); 1547 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1548 } 1549 1550 // Tests that showing an interstitial as a result of a browser initiated 1551 // navigation while an interstitial is showing does not remove the pending 1552 // entry (see http://crbug.com/9791). 1553 TEST_F(TabContentsTest, NewInterstitialDoesNotCancelPendingEntry) { 1554 const char kUrl[] = "http://www.badguys.com/"; 1555 const GURL kGURL(kUrl); 1556 1557 // Start a navigation to a page 1558 contents()->controller().LoadURL(kGURL, GURL(), PageTransition::TYPED); 1559 1560 // Simulate that navigation triggering an interstitial. 1561 TestInterstitialPage::InterstitialState state = 1562 TestInterstitialPage::UNDECIDED; 1563 bool deleted = false; 1564 TestInterstitialPage* interstitial = 1565 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted); 1566 TestInterstitialPageStateGuard state_guard(interstitial); 1567 interstitial->Show(); 1568 interstitial->TestDidNavigate(1, kGURL); 1569 1570 // Initiate a new navigation from the browser that also triggers an 1571 // interstitial. 1572 contents()->controller().LoadURL(kGURL, GURL(), PageTransition::TYPED); 1573 TestInterstitialPage::InterstitialState state2 = 1574 TestInterstitialPage::UNDECIDED; 1575 bool deleted2 = false; 1576 TestInterstitialPage* interstitial2 = 1577 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted); 1578 TestInterstitialPageStateGuard state_guard2(interstitial2); 1579 interstitial2->Show(); 1580 interstitial2->TestDidNavigate(1, kGURL); 1581 1582 // Make sure we still have an entry. 1583 NavigationEntry* entry = contents()->controller().pending_entry(); 1584 ASSERT_TRUE(entry); 1585 EXPECT_EQ(kUrl, entry->url().spec()); 1586 1587 // And that the first interstitial is gone, but not the second. 1588 EXPECT_TRUE(deleted); 1589 EXPECT_EQ(TestInterstitialPage::CANCELED, state); 1590 EXPECT_FALSE(deleted2); 1591 EXPECT_EQ(TestInterstitialPage::UNDECIDED, state2); 1592 } 1593 1594 // Tests that Javascript messages are not shown while an interstitial is 1595 // showing. 1596 TEST_F(TabContentsTest, NoJSMessageOnInterstitials) { 1597 const char kUrl[] = "http://www.badguys.com/"; 1598 const GURL kGURL(kUrl); 1599 1600 // Start a navigation to a page 1601 contents()->controller().LoadURL(kGURL, GURL(), PageTransition::TYPED); 1602 // DidNavigate from the page 1603 ViewHostMsg_FrameNavigate_Params params; 1604 InitNavigateParams(¶ms, 1, kGURL); 1605 contents()->TestDidNavigate(rvh(), params); 1606 1607 // Simulate showing an interstitial while the page is showing. 1608 TestInterstitialPage::InterstitialState state = 1609 TestInterstitialPage::UNDECIDED; 1610 bool deleted = false; 1611 TestInterstitialPage* interstitial = 1612 new TestInterstitialPage(contents(), true, kGURL, &state, &deleted); 1613 TestInterstitialPageStateGuard state_guard(interstitial); 1614 interstitial->Show(); 1615 interstitial->TestDidNavigate(1, kGURL); 1616 1617 // While the interstitial is showing, let's simulate the hidden page 1618 // attempting to show a JS message. 1619 IPC::Message* dummy_message = new IPC::Message; 1620 bool did_suppress_message = false; 1621 contents()->RunJavaScriptMessage(L"This is an informative message", L"OK", 1622 kGURL, ui::MessageBoxFlags::kIsJavascriptAlert, dummy_message, 1623 &did_suppress_message); 1624 EXPECT_TRUE(did_suppress_message); 1625 } 1626 1627 // Makes sure that if the source passed to CopyStateFromAndPrune has an 1628 // interstitial it isn't copied over to the destination. 1629 TEST_F(TabContentsTest, CopyStateFromAndPruneSourceInterstitial) { 1630 // Navigate to a page. 1631 GURL url1("http://www.google.com"); 1632 rvh()->SendNavigate(1, url1); 1633 EXPECT_EQ(1, controller().entry_count()); 1634 1635 // Initiate a browser navigation that will trigger the interstitial 1636 controller().LoadURL(GURL("http://www.evil.com"), GURL(), 1637 PageTransition::TYPED); 1638 1639 // Show an interstitial. 1640 TestInterstitialPage::InterstitialState state = 1641 TestInterstitialPage::UNDECIDED; 1642 bool deleted = false; 1643 GURL url2("http://interstitial"); 1644 TestInterstitialPage* interstitial = 1645 new TestInterstitialPage(contents(), true, url2, &state, &deleted); 1646 TestInterstitialPageStateGuard state_guard(interstitial); 1647 interstitial->Show(); 1648 interstitial->TestDidNavigate(1, url2); 1649 EXPECT_TRUE(interstitial->is_showing()); 1650 EXPECT_EQ(2, controller().entry_count()); 1651 1652 // Create another NavigationController. 1653 GURL url3("http://foo2"); 1654 scoped_ptr<TestTabContents> other_contents(CreateTestTabContents()); 1655 NavigationController& other_controller = other_contents->controller(); 1656 other_contents->NavigateAndCommit(url3); 1657 other_controller.CopyStateFromAndPrune(&controller(), false); 1658 1659 // The merged controller should only have two entries: url1 and url2. 1660 ASSERT_EQ(2, other_controller.entry_count()); 1661 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex()); 1662 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url()); 1663 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->url()); 1664 1665 // And the merged controller shouldn't be showing an interstitial. 1666 EXPECT_FALSE(other_contents->showing_interstitial_page()); 1667 } 1668 1669 // Makes sure that CopyStateFromAndPrune does the right thing if the object 1670 // CopyStateFromAndPrune is invoked on is showing an interstitial. 1671 TEST_F(TabContentsTest, CopyStateFromAndPruneTargetInterstitial) { 1672 // Navigate to a page. 1673 GURL url1("http://www.google.com"); 1674 contents()->NavigateAndCommit(url1); 1675 1676 // Create another NavigationController. 1677 scoped_ptr<TestTabContents> other_contents(CreateTestTabContents()); 1678 NavigationController& other_controller = other_contents->controller(); 1679 1680 // Navigate it to url2. 1681 GURL url2("http://foo2"); 1682 other_contents->NavigateAndCommit(url2); 1683 1684 // Show an interstitial. 1685 TestInterstitialPage::InterstitialState state = 1686 TestInterstitialPage::UNDECIDED; 1687 bool deleted = false; 1688 GURL url3("http://interstitial"); 1689 TestInterstitialPage* interstitial = 1690 new TestInterstitialPage(other_contents.get(), true, url3, &state, 1691 &deleted); 1692 TestInterstitialPageStateGuard state_guard(interstitial); 1693 interstitial->Show(); 1694 interstitial->TestDidNavigate(1, url3); 1695 EXPECT_TRUE(interstitial->is_showing()); 1696 EXPECT_EQ(2, other_controller.entry_count()); 1697 1698 other_controller.CopyStateFromAndPrune(&controller(), false); 1699 1700 // The merged controller should only have two entries: url1 and url2. 1701 ASSERT_EQ(2, other_controller.entry_count()); 1702 EXPECT_EQ(1, other_controller.GetCurrentEntryIndex()); 1703 EXPECT_EQ(url1, other_controller.GetEntryAtIndex(0)->url()); 1704 EXPECT_EQ(url3, other_controller.GetEntryAtIndex(1)->url()); 1705 1706 // It should have a transient entry. 1707 EXPECT_TRUE(other_controller.GetTransientEntry()); 1708 1709 // And the interstitial should be showing. 1710 EXPECT_TRUE(other_contents->showing_interstitial_page()); 1711 1712 // And the interstitial should do a reload on don't proceed. 1713 EXPECT_TRUE(other_contents->interstitial_page()->reload_on_dont_proceed()); 1714 } 1715 1716 class ConstrainedWindowCloseTest : public ConstrainedWindow { 1717 public: 1718 explicit ConstrainedWindowCloseTest(TabContents* tab_contents) 1719 : tab_contents_(tab_contents) { 1720 } 1721 1722 virtual void ShowConstrainedWindow() {} 1723 virtual void FocusConstrainedWindow() {} 1724 virtual ~ConstrainedWindowCloseTest() {} 1725 1726 virtual void CloseConstrainedWindow() { 1727 tab_contents_->WillClose(this); 1728 close_count++; 1729 } 1730 1731 int close_count; 1732 TabContents* tab_contents_; 1733 }; 1734 1735 TEST_F(TabContentsTest, ConstrainedWindows) { 1736 TabContents* tab_contents = CreateTestTabContents(); 1737 ConstrainedWindowCloseTest window(tab_contents); 1738 window.close_count = 0; 1739 1740 const int kWindowCount = 4; 1741 for (int i = 0; i < kWindowCount; i++) { 1742 tab_contents->AddConstrainedDialog(&window); 1743 } 1744 EXPECT_EQ(window.close_count, 0); 1745 delete tab_contents; 1746 EXPECT_EQ(window.close_count, kWindowCount); 1747 } 1748