session_history_browsertest.cc revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
1// Copyright (c) 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "base/string_util.h" 6#include "base/utf_string_conversions.h" 7#include "content/public/browser/navigation_controller.h" 8#include "content/public/browser/notification_service.h" 9#include "content/public/browser/notification_types.h" 10#include "content/public/browser/web_contents.h" 11#include "content/public/common/url_constants.h" 12#include "content/public/test/browser_test_utils.h" 13#include "content/public/test/test_utils.h" 14#include "content/shell/shell.h" 15#include "content/test/content_browser_test.h" 16#include "content/test/content_browser_test_utils.h" 17#include "net/test/spawned_test_server.h" 18#include "testing/gtest/include/gtest/gtest.h" 19 20namespace content { 21 22class SessionHistoryTest : public ContentBrowserTest { 23 protected: 24 SessionHistoryTest() {} 25 26 virtual void SetUpOnMainThread() OVERRIDE { 27 ASSERT_TRUE(test_server()->Start()); 28 NavigateToURL(shell(), GURL(chrome::kAboutBlankURL)); 29 } 30 31 // Simulate clicking a link. Only works on the frames.html testserver page. 32 void ClickLink(std::string node_id) { 33 GURL url("javascript:clickLink('" + node_id + "')"); 34 NavigateToURL(shell(), url); 35 } 36 37 // Simulate filling in form data. Only works on the frames.html page with 38 // subframe = form.html, and on form.html itself. 39 void FillForm(std::string node_id, std::string value) { 40 GURL url("javascript:fillForm('" + node_id + "', '" + value + "')"); 41 // This will return immediately, but since the JS executes synchronously 42 // on the renderer, it will complete before the next navigate message is 43 // processed. 44 NavigateToURL(shell(), url); 45 } 46 47 // Simulate submitting a form. Only works on the frames.html page with 48 // subframe = form.html, and on form.html itself. 49 void SubmitForm(std::string node_id) { 50 GURL url("javascript:submitForm('" + node_id + "')"); 51 NavigateToURL(shell(), url); 52 } 53 54 // Navigate session history using history.go(distance). 55 void JavascriptGo(std::string distance) { 56 GURL url("javascript:history.go('" + distance + "')"); 57 NavigateToURL(shell(), url); 58 } 59 60 std::string GetTabTitle() { 61 return UTF16ToASCII(shell()->web_contents()->GetTitle()); 62 } 63 64 GURL GetTabURL() { 65 return shell()->web_contents()->GetURL(); 66 } 67 68 GURL GetURL(const std::string file) { 69 return test_server()->GetURL(std::string("files/session_history/") + file); 70 } 71 72 void NavigateAndCheckTitle(const char* filename, 73 const std::string& expected_title) { 74 string16 expected_title16(ASCIIToUTF16(expected_title)); 75 TitleWatcher title_watcher(shell()->web_contents(), expected_title16); 76 NavigateToURL(shell(), GetURL(filename)); 77 ASSERT_EQ(expected_title16, title_watcher.WaitAndGetTitle()); 78 } 79 80 bool CanGoBack() { 81 return shell()->web_contents()->GetController().CanGoBack(); 82 } 83 84 bool CanGoForward() { 85 return shell()->web_contents()->GetController().CanGoForward(); 86 } 87 88 void GoBack() { 89 WindowedNotificationObserver load_stop_observer( 90 NOTIFICATION_LOAD_STOP, 91 NotificationService::AllSources()); 92 shell()->web_contents()->GetController().GoBack(); 93 load_stop_observer.Wait(); 94 } 95 96 void GoForward() { 97 WindowedNotificationObserver load_stop_observer( 98 NOTIFICATION_LOAD_STOP, 99 NotificationService::AllSources()); 100 shell()->web_contents()->GetController().GoForward(); 101 load_stop_observer.Wait(); 102 } 103}; 104 105// If this flakes, use http://crbug.com/61619 on windows and 106// http://crbug.com/102094 on mac. 107IN_PROC_BROWSER_TEST_F(SessionHistoryTest, BasicBackForward) { 108 ASSERT_FALSE(CanGoBack()); 109 110 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot1.html", "bot1")); 111 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot2.html", "bot2")); 112 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot3.html", "bot3")); 113 114 // history is [blank, bot1, bot2, *bot3] 115 116 GoBack(); 117 EXPECT_EQ("bot2", GetTabTitle()); 118 119 GoBack(); 120 EXPECT_EQ("bot1", GetTabTitle()); 121 122 GoForward(); 123 EXPECT_EQ("bot2", GetTabTitle()); 124 125 GoBack(); 126 EXPECT_EQ("bot1", GetTabTitle()); 127 128 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot3.html", "bot3")); 129 130 // history is [blank, bot1, *bot3] 131 132 ASSERT_FALSE(CanGoForward()); 133 EXPECT_EQ("bot3", GetTabTitle()); 134 135 GoBack(); 136 EXPECT_EQ("bot1", GetTabTitle()); 137 138 GoBack(); 139 EXPECT_EQ("about:blank", GetTabTitle()); 140 141 ASSERT_FALSE(CanGoBack()); 142 EXPECT_EQ("about:blank", GetTabTitle()); 143 144 GoForward(); 145 EXPECT_EQ("bot1", GetTabTitle()); 146 147 GoForward(); 148 EXPECT_EQ("bot3", GetTabTitle()); 149} 150 151// Test that back/forward works when navigating in subframes. 152// If this flakes, use http://crbug.com/48833 153IN_PROC_BROWSER_TEST_F(SessionHistoryTest, FrameBackForward) { 154 ASSERT_FALSE(CanGoBack()); 155 156 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("frames.html", "bot1")); 157 158 ClickLink("abot2"); 159 EXPECT_EQ("bot2", GetTabTitle()); 160 GURL frames(GetURL("frames.html")); 161 EXPECT_EQ(frames, GetTabURL()); 162 163 ClickLink("abot3"); 164 EXPECT_EQ("bot3", GetTabTitle()); 165 EXPECT_EQ(frames, GetTabURL()); 166 167 // history is [blank, bot1, bot2, *bot3] 168 169 GoBack(); 170 EXPECT_EQ("bot2", GetTabTitle()); 171 EXPECT_EQ(frames, GetTabURL()); 172 173 GoBack(); 174 EXPECT_EQ("bot1", GetTabTitle()); 175 EXPECT_EQ(frames, GetTabURL()); 176 177 GoBack(); 178 EXPECT_EQ("about:blank", GetTabTitle()); 179 EXPECT_EQ(GURL(chrome::kAboutBlankURL), GetTabURL()); 180 181 GoForward(); 182 EXPECT_EQ("bot1", GetTabTitle()); 183 EXPECT_EQ(frames, GetTabURL()); 184 185 GoForward(); 186 EXPECT_EQ("bot2", GetTabTitle()); 187 EXPECT_EQ(frames, GetTabURL()); 188 189 ClickLink("abot1"); 190 EXPECT_EQ("bot1", GetTabTitle()); 191 EXPECT_EQ(frames, GetTabURL()); 192 193 // history is [blank, bot1, bot2, *bot1] 194 195 ASSERT_FALSE(CanGoForward()); 196 EXPECT_EQ("bot1", GetTabTitle()); 197 EXPECT_EQ(frames, GetTabURL()); 198 199 GoBack(); 200 EXPECT_EQ("bot2", GetTabTitle()); 201 EXPECT_EQ(frames, GetTabURL()); 202 203 GoBack(); 204 EXPECT_EQ("bot1", GetTabTitle()); 205 EXPECT_EQ(frames, GetTabURL()); 206} 207 208// Test that back/forward preserves POST data and document state in subframes. 209// If this flakes use http://crbug.com/61619 210IN_PROC_BROWSER_TEST_F(SessionHistoryTest, FrameFormBackForward) { 211 ASSERT_FALSE(CanGoBack()); 212 213 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("frames.html", "bot1")); 214 215 ClickLink("aform"); 216 EXPECT_EQ("form", GetTabTitle()); 217 GURL frames(GetURL("frames.html")); 218 EXPECT_EQ(frames, GetTabURL()); 219 220 SubmitForm("isubmit"); 221 EXPECT_EQ("text=&select=a", GetTabTitle()); 222 EXPECT_EQ(frames, GetTabURL()); 223 224 GoBack(); 225 EXPECT_EQ("form", GetTabTitle()); 226 EXPECT_EQ(frames, GetTabURL()); 227 228 // history is [blank, bot1, *form, post] 229 230 ClickLink("abot2"); 231 EXPECT_EQ("bot2", GetTabTitle()); 232 EXPECT_EQ(frames, GetTabURL()); 233 234 // history is [blank, bot1, form, *bot2] 235 236 GoBack(); 237 EXPECT_EQ("form", GetTabTitle()); 238 EXPECT_EQ(frames, GetTabURL()); 239 240 SubmitForm("isubmit"); 241 EXPECT_EQ("text=&select=a", GetTabTitle()); 242 EXPECT_EQ(frames, GetTabURL()); 243 244 // history is [blank, bot1, form, *post] 245 246 // TODO(mpcomplete): reenable this when WebKit bug 10199 is fixed: 247 // "returning to a POST result within a frame does a GET instead of a POST" 248 ClickLink("abot2"); 249 EXPECT_EQ("bot2", GetTabTitle()); 250 EXPECT_EQ(frames, GetTabURL()); 251 252 GoBack(); 253 EXPECT_EQ("text=&select=a", GetTabTitle()); 254 EXPECT_EQ(frames, GetTabURL()); 255} 256 257// TODO(mpcomplete): enable this when Bug 734372 is fixed: 258// "Doing a session history navigation does not restore newly-created subframe 259// document state" 260// Test that back/forward preserves POST data and document state when navigating 261// across frames (ie, from frame -> nonframe). 262// Hangs, see http://crbug.com/45058. 263IN_PROC_BROWSER_TEST_F(SessionHistoryTest, CrossFrameFormBackForward) { 264 ASSERT_FALSE(CanGoBack()); 265 266 GURL frames(GetURL("frames.html")); 267 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("frames.html", "bot1")); 268 269 ClickLink("aform"); 270 EXPECT_EQ("form", GetTabTitle()); 271 EXPECT_EQ(frames, GetTabURL()); 272 273 SubmitForm("isubmit"); 274 EXPECT_EQ("text=&select=a", GetTabTitle()); 275 EXPECT_EQ(frames, GetTabURL()); 276 277 GoBack(); 278 EXPECT_EQ("form", GetTabTitle()); 279 EXPECT_EQ(frames, GetTabURL()); 280 281 // history is [blank, bot1, *form, post] 282 283 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot2.html", "bot2")); 284 285 // history is [blank, bot1, form, *bot2] 286 287 GoBack(); 288 EXPECT_EQ("bot1", GetTabTitle()); 289 EXPECT_EQ(frames, GetTabURL()); 290 291 SubmitForm("isubmit"); 292 EXPECT_EQ("text=&select=a", GetTabTitle()); 293 EXPECT_EQ(frames, GetTabURL()); 294} 295 296// Test that back/forward entries are created for reference fragment 297// navigations. Bug 730379. 298// If this flakes use http://crbug.com/61619. 299IN_PROC_BROWSER_TEST_F(SessionHistoryTest, FragmentBackForward) { 300 ASSERT_FALSE(CanGoBack()); 301 302 GURL fragment(GetURL("fragment.html")); 303 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("fragment.html", "fragment")); 304 305 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("fragment.html#a", "fragment")); 306 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("fragment.html#b", "fragment")); 307 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("fragment.html#c", "fragment")); 308 309 // history is [blank, fragment, fragment#a, fragment#b, *fragment#c] 310 311 GoBack(); 312 EXPECT_EQ(GetURL("fragment.html#b"), GetTabURL()); 313 314 GoBack(); 315 EXPECT_EQ(GetURL("fragment.html#a"), GetTabURL()); 316 317 GoBack(); 318 EXPECT_EQ(GetURL("fragment.html"), GetTabURL()); 319 320 GoForward(); 321 EXPECT_EQ(GetURL("fragment.html#a"), GetTabURL()); 322 323 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot3.html", "bot3")); 324 325 // history is [blank, fragment, fragment#a, bot3] 326 327 ASSERT_FALSE(CanGoForward()); 328 EXPECT_EQ(GetURL("bot3.html"), GetTabURL()); 329 330 GoBack(); 331 EXPECT_EQ(GetURL("fragment.html#a"), GetTabURL()); 332 333 GoBack(); 334 EXPECT_EQ(GetURL("fragment.html"), GetTabURL()); 335} 336 337// Test that the javascript window.history object works. 338// NOTE: history.go(N) does not do anything if N is outside the bounds of the 339// back/forward list (such as trigger our start/stop loading events). This 340// means the test will hang if it attempts to navigate too far forward or back, 341// since we'll be waiting forever for a load stop event. 342// 343// TODO(brettw) bug 50648: fix flakyness. This test seems like it was failing 344// about 1/4 of the time on Vista by failing to execute JavascriptGo (see bug). 345IN_PROC_BROWSER_TEST_F(SessionHistoryTest, JavascriptHistory) { 346 ASSERT_FALSE(CanGoBack()); 347 348 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot1.html", "bot1")); 349 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot2.html", "bot2")); 350 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot3.html", "bot3")); 351 352 // history is [blank, bot1, bot2, *bot3] 353 354 JavascriptGo("-1"); 355 EXPECT_EQ("bot2", GetTabTitle()); 356 357 JavascriptGo("-1"); 358 EXPECT_EQ("bot1", GetTabTitle()); 359 360 JavascriptGo("1"); 361 EXPECT_EQ("bot2", GetTabTitle()); 362 363 JavascriptGo("-1"); 364 EXPECT_EQ("bot1", GetTabTitle()); 365 366 JavascriptGo("2"); 367 EXPECT_EQ("bot3", GetTabTitle()); 368 369 // history is [blank, bot1, bot2, *bot3] 370 371 JavascriptGo("-3"); 372 EXPECT_EQ("about:blank", GetTabTitle()); 373 374 ASSERT_FALSE(CanGoBack()); 375 EXPECT_EQ("about:blank", GetTabTitle()); 376 377 JavascriptGo("1"); 378 EXPECT_EQ("bot1", GetTabTitle()); 379 380 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle("bot3.html", "bot3")); 381 382 // history is [blank, bot1, *bot3] 383 384 ASSERT_FALSE(CanGoForward()); 385 EXPECT_EQ("bot3", GetTabTitle()); 386 387 JavascriptGo("-1"); 388 EXPECT_EQ("bot1", GetTabTitle()); 389 390 JavascriptGo("-1"); 391 EXPECT_EQ("about:blank", GetTabTitle()); 392 393 ASSERT_FALSE(CanGoBack()); 394 EXPECT_EQ("about:blank", GetTabTitle()); 395 396 JavascriptGo("1"); 397 EXPECT_EQ("bot1", GetTabTitle()); 398 399 JavascriptGo("1"); 400 EXPECT_EQ("bot3", GetTabTitle()); 401 402 // TODO(creis): Test that JavaScript history navigations work across tab 403 // types. For example, load about:network in a tab, then a real page, then 404 // try to go back and forward with JavaScript. Bug 1136715. 405 // (Hard to test right now, because pages like about:network cause the 406 // TabProxy to hang. This is because they do not appear to use the 407 // NotificationService.) 408} 409 410// This test is failing consistently. See http://crbug.com/22560 411IN_PROC_BROWSER_TEST_F(SessionHistoryTest, LocationReplace) { 412 // Test that using location.replace doesn't leave the title of the old page 413 // visible. 414 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle( 415 "replace.html?bot1.html", "bot1")); 416} 417 418IN_PROC_BROWSER_TEST_F(SessionHistoryTest, LocationChangeInSubframe) { 419 ASSERT_NO_FATAL_FAILURE(NavigateAndCheckTitle( 420 "location_redirect.html", "Default Title")); 421 422 NavigateToURL(shell(), GURL("javascript:void(frames[0].navigate())")); 423 EXPECT_EQ("foo", GetTabTitle()); 424 425 GoBack(); 426 EXPECT_EQ("Default Title", GetTabTitle()); 427} 428 429// http://code.google.com/p/chromium/issues/detail?id=56267 430IN_PROC_BROWSER_TEST_F(SessionHistoryTest, HistoryLength) { 431 int length; 432 ASSERT_TRUE(ExecuteScriptAndExtractInt( 433 shell()->web_contents(), 434 "domAutomationController.send(history.length)", 435 &length)); 436 EXPECT_EQ(1, length); 437 438 NavigateToURL(shell(), GetURL("title1.html")); 439 440 ASSERT_TRUE(ExecuteScriptAndExtractInt( 441 shell()->web_contents(), 442 "domAutomationController.send(history.length)", 443 &length)); 444 EXPECT_EQ(2, length); 445 446 // Now test that history.length is updated when the navigation is committed. 447 NavigateToURL(shell(), GetURL("record_length.html")); 448 449 ASSERT_TRUE(ExecuteScriptAndExtractInt( 450 shell()->web_contents(), 451 "domAutomationController.send(history.length)", 452 &length)); 453 EXPECT_EQ(3, length); 454 455 GoBack(); 456 GoBack(); 457 458 // Ensure history.length is properly truncated. 459 NavigateToURL(shell(), GetURL("title2.html")); 460 461 ASSERT_TRUE(ExecuteScriptAndExtractInt( 462 shell()->web_contents(), 463 "domAutomationController.send(history.length)", 464 &length)); 465 EXPECT_EQ(2, length); 466} 467 468} // namespace content 469