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