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
InitNavigateParams(ViewHostMsg_FrameNavigate_Params * params,int page_id,const GURL & url)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:
~Delegate()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.
TestInterstitialPage(TabContents * tab,bool new_navigation,const GURL & url,InterstitialState * state,bool * deleted)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
~TestInterstitialPage()95 virtual ~TestInterstitialPage() {
96 if (deleted_)
97 *deleted_ = true;
98 if (delegate_)
99 delegate_->TestInterstitialPageDeleted(this);
100 }
101
DontProceed()102 virtual void DontProceed() {
103 if (state_)
104 *state_ = CANCELED;
105 InterstitialPage::DontProceed();
106 }
Proceed()107 virtual void Proceed() {
108 if (state_)
109 *state_ = OKED;
110 InterstitialPage::Proceed();
111 }
112
command_received_count() const113 int command_received_count() const {
114 return command_received_count_;
115 }
116
TestDomOperationResponse(const std::string & json_string)117 void TestDomOperationResponse(const std::string& json_string) {
118 DomOperationResponse(json_string, 1);
119 }
120
TestDidNavigate(int page_id,const GURL & url)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
TestRenderViewGone(base::TerminationStatus status,int error_code)127 void TestRenderViewGone(base::TerminationStatus status, int error_code) {
128 RenderViewGone(render_view_host(), status, error_code);
129 }
130
is_showing() const131 bool is_showing() const {
132 return static_cast<TestRenderWidgetHostView*>(render_view_host()->view())->
133 is_showing();
134 }
135
ClearStates()136 void ClearStates() {
137 state_ = NULL;
138 deleted_ = NULL;
139 delegate_ = NULL;
140 }
141
set_delegate(Delegate * delegate)142 void set_delegate(Delegate* delegate) {
143 delegate_ = delegate;
144 }
145
146 protected:
CreateRenderViewHost()147 virtual RenderViewHost* CreateRenderViewHost() {
148 return new TestRenderViewHost(
149 SiteInstance::CreateSiteInstance(tab()->profile()),
150 this, MSG_ROUTING_NONE);
151 }
152
CreateTabContentsView()153 virtual TabContentsView* CreateTabContentsView() { return NULL; }
154
155
CommandReceived(const std::string & command)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:
TestInterstitialPageStateGuard(TestInterstitialPage * interstitial_page)169 explicit TestInterstitialPageStateGuard(
170 TestInterstitialPage* interstitial_page)
171 : interstitial_page_(interstitial_page) {
172 DCHECK(interstitial_page_);
173 interstitial_page_->set_delegate(this);
174 }
~TestInterstitialPageStateGuard()175 ~TestInterstitialPageStateGuard() {
176 if (interstitial_page_)
177 interstitial_page_->ClearStates();
178 }
179
TestInterstitialPageDeleted(TestInterstitialPage * interstitial)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:
TabContentsTest()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.
SetUp()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
TearDown()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.
TEST_F(TabContentsTest,UpdateTitle)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.
TEST_F(TabContentsTest,NTPViewSource)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.
TEST_F(TabContentsTest,SimpleNavigation)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.
TEST_F(TabContentsTest,CrossSiteBoundaries)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).
TEST_F(TabContentsTest,CrossSiteBoundariesAfterCrash)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.
TEST_F(TabContentsTest,NavigateTwoTabsCrossSite)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.
TEST_F(TabContentsTest,CrossSiteComparesAgainstCurrentPage)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.
TEST_F(TabContentsTest,CrossSiteUnloadHandlers)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.
TEST_F(TabContentsTest,CrossSiteNavigationPreempted)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
TEST_F(TabContentsTest,CrossSiteNavigationBackPreempted)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).
TEST_F(TabContentsTest,CrossSiteNavigationNotPreemptedByFrame)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.
TEST_F(TabContentsTest,CrossSiteNotPreemptedDuringBeforeUnload)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.
TEST_F(TabContentsTest,CrossSiteCantPreemptAfterUnload)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.
TEST_F(TabContentsTest,NavigationEntryContentState)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.
TEST_F(TabContentsTest,NavigationEntryContentStateNewWindow)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.
TEST_F(TabContentsTest,WebKitPrefs)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.
TEST_F(TabContentsTest,ShowInterstitialFromBrowserWithNewNavigationDontProceed)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.
TEST_F(TabContentsTest,ShowInterstitiaFromRendererlWithNewNavigationDontProceed)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.
TEST_F(TabContentsTest,ShowInterstitialNoNewNavigationDontProceed)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.
TEST_F(TabContentsTest,ShowInterstitialFromBrowserNewNavigationProceed)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.
TEST_F(TabContentsTest,ShowInterstitialFromRendererNewNavigationProceed)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.
TEST_F(TabContentsTest,ShowInterstitialNoNewNavigationProceed)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.
TEST_F(TabContentsTest,ShowInterstitialThenNavigate)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.
TEST_F(TabContentsTest,ShowInterstitialThenGoBack)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.
TEST_F(TabContentsTest,ShowInterstitialCrashRendererThenGoBack)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.
TEST_F(TabContentsTest,ShowInterstitialCrashRendererThenNavigate)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.
TEST_F(TabContentsTest,ShowInterstitialThenCloseTab)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.
TEST_F(TabContentsTest,ShowInterstitialProceedMultipleCommands)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.
TEST_F(TabContentsTest,ShowInterstitialOnInterstitial)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.
TEST_F(TabContentsTest,ShowInterstitialProceedShowInterstitial)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.
TEST_F(TabContentsTest,NavigateBeforeInterstitialShows)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.
TEST_F(TabContentsTest,TwoQuickInterstitials)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.
TEST_F(TabContentsTest,InterstitialCrasher)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).
TEST_F(TabContentsTest,NewInterstitialDoesNotCancelPendingEntry)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.
TEST_F(TabContentsTest,NoJSMessageOnInterstitials)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.
TEST_F(TabContentsTest,CopyStateFromAndPruneSourceInterstitial)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.
TEST_F(TabContentsTest,CopyStateFromAndPruneTargetInterstitial)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:
ConstrainedWindowCloseTest(TabContents * tab_contents)1718 explicit ConstrainedWindowCloseTest(TabContents* tab_contents)
1719 : tab_contents_(tab_contents) {
1720 }
1721
ShowConstrainedWindow()1722 virtual void ShowConstrainedWindow() {}
FocusConstrainedWindow()1723 virtual void FocusConstrainedWindow() {}
~ConstrainedWindowCloseTest()1724 virtual ~ConstrainedWindowCloseTest() {}
1725
CloseConstrainedWindow()1726 virtual void CloseConstrainedWindow() {
1727 tab_contents_->WillClose(this);
1728 close_count++;
1729 }
1730
1731 int close_count;
1732 TabContents* tab_contents_;
1733 };
1734
TEST_F(TabContentsTest,ConstrainedWindows)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