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/string_util.h"
6#include "chrome/common/url_constants.h"
7#include "chrome/test/automation/tab_proxy.h"
8#include "chrome/test/automation/browser_proxy.h"
9#include "chrome/test/ui/ui_test.h"
10#include "grit/generated_resources.h"
11#include "net/base/net_util.h"
12#include "net/test/test_server.h"
13
14namespace {
15
16class SessionHistoryTest : public UITest {
17 protected:
18  SessionHistoryTest()
19      : test_server_(net::TestServer::TYPE_HTTP,
20                     FilePath(FILE_PATH_LITERAL("chrome/test/data"))) {
21    dom_automation_enabled_ = true;
22  }
23
24  virtual void SetUp() {
25    UITest::SetUp();
26
27    window_ = automation()->GetBrowserWindow(0);
28    ASSERT_TRUE(window_.get());
29
30    tab_ = window_->GetActiveTab();
31    ASSERT_TRUE(tab_.get());
32  }
33
34  // Simulate clicking a link.  Only works on the frames.html testserver page.
35  void ClickLink(std::string node_id) {
36    GURL url("javascript:clickLink('" + node_id + "')");
37    ASSERT_TRUE(tab_->NavigateToURL(url));
38  }
39
40  // Simulate filling in form data.  Only works on the frames.html page with
41  // subframe = form.html, and on form.html itself.
42  void FillForm(std::string node_id, std::string value) {
43    GURL url("javascript:fillForm('" + node_id + "', '" + value + "')");
44    // This will return immediately, but since the JS executes synchronously
45    // on the renderer, it will complete before the next navigate message is
46    // processed.
47    ASSERT_TRUE(tab_->NavigateToURLAsync(url));
48  }
49
50  // Simulate submitting a form.  Only works on the frames.html page with
51  // subframe = form.html, and on form.html itself.
52  void SubmitForm(std::string node_id) {
53    GURL url("javascript:submitForm('" + node_id + "')");
54    ASSERT_TRUE(tab_->NavigateToURL(url));
55  }
56
57  // Navigate session history using history.go(distance).
58  void JavascriptGo(std::string distance) {
59    GURL url("javascript:history.go('" + distance + "')");
60    ASSERT_TRUE(tab_->NavigateToURL(url));
61  }
62
63  std::wstring GetTabTitle() {
64    std::wstring title;
65    EXPECT_TRUE(tab_->GetTabTitle(&title));
66    return title;
67  }
68
69  GURL GetTabURL() {
70    GURL url;
71    EXPECT_TRUE(tab_->GetCurrentURL(&url));
72    return url;
73  }
74
75 protected:
76  scoped_refptr<BrowserProxy> window_;
77  scoped_refptr<TabProxy> tab_;
78
79  net::TestServer test_server_;
80};
81
82#if defined(OS_WIN)
83// See http://crbug.com/61619
84#define MAYBE_BasicBackForward FLAKY_BasicBackForward
85#else
86#define MAYBE_BasicBackForward BasicBackForward
87#endif
88
89TEST_F(SessionHistoryTest, MAYBE_BasicBackForward) {
90  ASSERT_TRUE(test_server_.Start());
91
92  // about:blank should be loaded first.
93  ASSERT_FALSE(tab_->GoBack());
94  EXPECT_EQ(L"about:blank", GetTabTitle());
95
96  ASSERT_TRUE(tab_->NavigateToURL(
97      test_server_.GetURL("files/session_history/bot1.html")));
98  EXPECT_EQ(L"bot1", GetTabTitle());
99
100  ASSERT_TRUE(tab_->NavigateToURL(
101      test_server_.GetURL("files/session_history/bot2.html")));
102  EXPECT_EQ(L"bot2", GetTabTitle());
103
104  ASSERT_TRUE(tab_->NavigateToURL(
105      test_server_.GetURL("files/session_history/bot3.html")));
106  EXPECT_EQ(L"bot3", GetTabTitle());
107
108  // history is [blank, bot1, bot2, *bot3]
109
110  ASSERT_TRUE(tab_->GoBack());
111  EXPECT_EQ(L"bot2", GetTabTitle());
112
113  ASSERT_TRUE(tab_->GoBack());
114  EXPECT_EQ(L"bot1", GetTabTitle());
115
116  ASSERT_TRUE(tab_->GoForward());
117  EXPECT_EQ(L"bot2", GetTabTitle());
118
119  ASSERT_TRUE(tab_->GoBack());
120  EXPECT_EQ(L"bot1", GetTabTitle());
121
122  ASSERT_TRUE(tab_->NavigateToURL(
123      test_server_.GetURL("files/session_history/bot3.html")));
124  EXPECT_EQ(L"bot3", GetTabTitle());
125
126  // history is [blank, bot1, *bot3]
127
128  ASSERT_FALSE(tab_->GoForward());
129  EXPECT_EQ(L"bot3", GetTabTitle());
130
131  ASSERT_TRUE(tab_->GoBack());
132  EXPECT_EQ(L"bot1", GetTabTitle());
133
134  ASSERT_TRUE(tab_->GoBack());
135  EXPECT_EQ(L"about:blank", GetTabTitle());
136
137  ASSERT_FALSE(tab_->GoBack());
138  EXPECT_EQ(L"about:blank", GetTabTitle());
139
140  ASSERT_TRUE(tab_->GoForward());
141  EXPECT_EQ(L"bot1", GetTabTitle());
142
143  ASSERT_TRUE(tab_->GoForward());
144  EXPECT_EQ(L"bot3", GetTabTitle());
145}
146
147#if defined(OS_WIN)
148// See http://crbug.com/61619
149#define MAYBE_FrameBackForward FLAKY_FrameBackForward
150#else
151#define MAYBE_FrameBackForward FrameBackForward
152#endif
153
154// Test that back/forward works when navigating in subframes.
155TEST_F(SessionHistoryTest, MAYBE_FrameBackForward) {
156  ASSERT_TRUE(test_server_.Start());
157
158  // about:blank should be loaded first.
159  GURL home(homepage());
160  ASSERT_FALSE(tab_->GoBack());
161  EXPECT_EQ(L"about:blank", GetTabTitle());
162  EXPECT_EQ(home, GetTabURL());
163
164  GURL frames(test_server_.GetURL("files/session_history/frames.html"));
165  ASSERT_TRUE(tab_->NavigateToURL(frames));
166  EXPECT_EQ(L"bot1", GetTabTitle());
167  EXPECT_EQ(frames, GetTabURL());
168
169  ClickLink("abot2");
170  EXPECT_EQ(L"bot2", GetTabTitle());
171  EXPECT_EQ(frames, GetTabURL());
172
173  ClickLink("abot3");
174  EXPECT_EQ(L"bot3", GetTabTitle());
175  EXPECT_EQ(frames, GetTabURL());
176
177  // history is [blank, bot1, bot2, *bot3]
178
179  ASSERT_TRUE(tab_->GoBack());
180  EXPECT_EQ(L"bot2", GetTabTitle());
181  EXPECT_EQ(frames, GetTabURL());
182
183  ASSERT_TRUE(tab_->GoBack());
184  EXPECT_EQ(L"bot1", GetTabTitle());
185  EXPECT_EQ(frames, GetTabURL());
186
187  ASSERT_TRUE(tab_->GoBack());
188  EXPECT_EQ(L"about:blank", GetTabTitle());
189  EXPECT_EQ(home, GetTabURL());
190
191  ASSERT_TRUE(tab_->GoForward());
192  EXPECT_EQ(L"bot1", GetTabTitle());
193  EXPECT_EQ(frames, GetTabURL());
194
195  ASSERT_TRUE(tab_->GoForward());
196  EXPECT_EQ(L"bot2", GetTabTitle());
197  EXPECT_EQ(frames, GetTabURL());
198
199  ClickLink("abot1");
200  EXPECT_EQ(L"bot1", GetTabTitle());
201  EXPECT_EQ(frames, GetTabURL());
202
203  // history is [blank, bot1, bot2, *bot1]
204
205  ASSERT_FALSE(tab_->GoForward());
206  EXPECT_EQ(L"bot1", GetTabTitle());
207  EXPECT_EQ(frames, GetTabURL());
208
209  ASSERT_TRUE(tab_->GoBack());
210  EXPECT_EQ(L"bot2", GetTabTitle());
211  EXPECT_EQ(frames, GetTabURL());
212
213  ASSERT_TRUE(tab_->GoBack());
214  EXPECT_EQ(L"bot1", GetTabTitle());
215  EXPECT_EQ(frames, GetTabURL());
216}
217
218// See http://crbug.com/61619
219// Test that back/forward preserves POST data and document state in subframes.
220TEST_F(SessionHistoryTest, FLAKY_FrameFormBackForward) {
221  ASSERT_TRUE(test_server_.Start());
222
223  // about:blank should be loaded first.
224  ASSERT_FALSE(tab_->GoBack());
225  EXPECT_EQ(L"", GetTabTitle());
226
227  GURL frames(test_server_.GetURL("files/session_history/frames.html"));
228  ASSERT_TRUE(tab_->NavigateToURL(frames));
229  EXPECT_EQ(L"bot1", GetTabTitle());
230
231  ClickLink("aform");
232  EXPECT_EQ(L"form", GetTabTitle());
233  EXPECT_EQ(frames, GetTabURL());
234
235  SubmitForm("isubmit");
236  EXPECT_EQ(L"text=&select=a", GetTabTitle());
237  EXPECT_EQ(frames, GetTabURL());
238
239  ASSERT_TRUE(tab_->GoBack());
240  EXPECT_EQ(L"form", GetTabTitle());
241  EXPECT_EQ(frames, GetTabURL());
242
243  // history is [blank, bot1, *form, post]
244
245  ClickLink("abot2");
246  EXPECT_EQ(L"bot2", GetTabTitle());
247  EXPECT_EQ(frames, GetTabURL());
248
249  // history is [blank, bot1, form, *bot2]
250
251  ASSERT_TRUE(tab_->GoBack());
252  EXPECT_EQ(L"form", GetTabTitle());
253  EXPECT_EQ(frames, GetTabURL());
254
255  SubmitForm("isubmit");
256  EXPECT_EQ(L"text=&select=a", GetTabTitle());
257  EXPECT_EQ(frames, GetTabURL());
258
259  // history is [blank, bot1, form, *post]
260
261  if (false) {
262    // TODO(mpcomplete): reenable this when WebKit bug 10199 is fixed:
263    // "returning to a POST result within a frame does a GET instead of a POST"
264    ClickLink("abot2");
265    EXPECT_EQ(L"bot2", GetTabTitle());
266    EXPECT_EQ(frames, GetTabURL());
267
268    ASSERT_TRUE(tab_->GoBack());
269    EXPECT_EQ(L"text=&select=a", GetTabTitle());
270    EXPECT_EQ(frames, GetTabURL());
271  }
272}
273
274// TODO(mpcomplete): enable this when Bug 734372 is fixed:
275// "Doing a session history navigation does not restore newly-created subframe
276// document state"
277// Test that back/forward preserves POST data and document state when navigating
278// across frames (ie, from frame -> nonframe).
279// Hangs, see http://crbug.com/45058.
280TEST_F(SessionHistoryTest, DISABLED_CrossFrameFormBackForward) {
281  ASSERT_TRUE(test_server_.Start());
282
283  // about:blank should be loaded first.
284  ASSERT_FALSE(tab_->GoBack());
285  EXPECT_EQ(L"", GetTabTitle());
286
287  GURL frames(test_server_.GetURL("files/session_history/frames.html"));
288  ASSERT_TRUE(tab_->NavigateToURL(frames));
289  EXPECT_EQ(L"bot1", GetTabTitle());
290
291  ClickLink("aform");
292  EXPECT_EQ(L"form", GetTabTitle());
293  EXPECT_EQ(frames, GetTabURL());
294
295  SubmitForm("isubmit");
296  EXPECT_EQ(L"text=&select=a", GetTabTitle());
297  EXPECT_EQ(frames, GetTabURL());
298
299  ASSERT_TRUE(tab_->GoBack());
300  EXPECT_EQ(L"form", GetTabTitle());
301  EXPECT_EQ(frames, GetTabURL());
302
303  // history is [blank, bot1, *form, post]
304
305  // ClickLink(L"abot2");
306  GURL bot2("files/session_history/bot2.html");
307  ASSERT_TRUE(tab_->NavigateToURL(bot2));
308  EXPECT_EQ(L"bot2", GetTabTitle());
309  EXPECT_EQ(bot2, GetTabURL());
310
311  // history is [blank, bot1, form, *bot2]
312
313  ASSERT_TRUE(tab_->GoBack());
314  EXPECT_EQ(L"form", GetTabTitle());
315  EXPECT_EQ(frames, GetTabURL());
316
317  SubmitForm("isubmit");
318  EXPECT_EQ(L"text=&select=a", GetTabTitle());
319  EXPECT_EQ(frames, GetTabURL());
320}
321
322
323#if defined(OS_WIN)
324// See http://crbug.com/61619
325#define MAYBE_FragmentBackForward FLAKY_FragmentBackForward
326#else
327#define MAYBE_FragmentBackForward FragmentBackForward
328#endif
329
330// Test that back/forward entries are created for reference fragment
331// navigations. Bug 730379.
332TEST_F(SessionHistoryTest, MAYBE_FragmentBackForward) {
333  ASSERT_TRUE(test_server_.Start());
334
335  // about:blank should be loaded first.
336  ASSERT_FALSE(tab_->GoBack());
337  EXPECT_EQ(L"about:blank", GetTabTitle());
338
339  GURL fragment(test_server_.GetURL("files/session_history/fragment.html"));
340  ASSERT_TRUE(tab_->NavigateToURL(fragment));
341  EXPECT_EQ(L"fragment", GetTabTitle());
342  EXPECT_EQ(fragment, GetTabURL());
343
344  GURL::Replacements ref_params;
345
346  ref_params.SetRef("a", url_parse::Component(0, 1));
347  GURL fragment_a(fragment.ReplaceComponents(ref_params));
348  ASSERT_TRUE(tab_->NavigateToURL(fragment_a));
349  EXPECT_EQ(L"fragment", GetTabTitle());
350  EXPECT_EQ(fragment_a, GetTabURL());
351
352  ref_params.SetRef("b", url_parse::Component(0, 1));
353  GURL fragment_b(fragment.ReplaceComponents(ref_params));
354  ASSERT_TRUE(tab_->NavigateToURL(fragment_b));
355  EXPECT_EQ(L"fragment", GetTabTitle());
356  EXPECT_EQ(fragment_b, GetTabURL());
357
358  ref_params.SetRef("c", url_parse::Component(0, 1));
359  GURL fragment_c(fragment.ReplaceComponents(ref_params));
360  ASSERT_TRUE(tab_->NavigateToURL(fragment_c));
361  EXPECT_EQ(L"fragment", GetTabTitle());
362  EXPECT_EQ(fragment_c, GetTabURL());
363
364  // history is [blank, fragment, fragment#a, fragment#b, *fragment#c]
365
366  ASSERT_TRUE(tab_->GoBack());
367  EXPECT_EQ(fragment_b, GetTabURL());
368
369  ASSERT_TRUE(tab_->GoBack());
370  EXPECT_EQ(fragment_a, GetTabURL());
371
372  ASSERT_TRUE(tab_->GoBack());
373  EXPECT_EQ(fragment, GetTabURL());
374
375  ASSERT_TRUE(tab_->GoForward());
376  EXPECT_EQ(fragment_a, GetTabURL());
377
378  GURL bot3(test_server_.GetURL("files/session_history/bot3.html"));
379  ASSERT_TRUE(tab_->NavigateToURL(bot3));
380  EXPECT_EQ(L"bot3", GetTabTitle());
381  EXPECT_EQ(bot3, GetTabURL());
382
383  // history is [blank, fragment, fragment#a, bot3]
384
385  ASSERT_FALSE(tab_->GoForward());
386  EXPECT_EQ(bot3, GetTabURL());
387
388  ASSERT_TRUE(tab_->GoBack());
389  EXPECT_EQ(fragment_a, GetTabURL());
390
391  ASSERT_TRUE(tab_->GoBack());
392  EXPECT_EQ(fragment, GetTabURL());
393}
394
395// Test that the javascript window.history object works.
396// NOTE: history.go(N) does not do anything if N is outside the bounds of the
397// back/forward list (such as trigger our start/stop loading events).  This
398// means the test will hang if it attempts to navigate too far forward or back,
399// since we'll be waiting forever for a load stop event.
400//
401// TODO(brettw) bug 50648: fix flakyness. This test seems like it was failing
402// about 1/4 of the time on Vista by failing to execute JavascriptGo (see bug).
403TEST_F(SessionHistoryTest, FLAKY_JavascriptHistory) {
404  ASSERT_TRUE(test_server_.Start());
405
406  // about:blank should be loaded first.
407  ASSERT_FALSE(tab_->GoBack());
408  EXPECT_EQ(L"about:blank", GetTabTitle());
409
410  ASSERT_TRUE(tab_->NavigateToURL(
411      test_server_.GetURL("files/session_history/bot1.html")));
412  EXPECT_EQ(L"bot1", GetTabTitle());
413
414  ASSERT_TRUE(tab_->NavigateToURL(
415      test_server_.GetURL("files/session_history/bot2.html")));
416  EXPECT_EQ(L"bot2", GetTabTitle());
417
418  ASSERT_TRUE(tab_->NavigateToURL(
419      test_server_.GetURL("files/session_history/bot3.html")));
420  EXPECT_EQ(L"bot3", GetTabTitle());
421
422  // history is [blank, bot1, bot2, *bot3]
423
424  JavascriptGo("-1");
425  EXPECT_EQ(L"bot2", GetTabTitle());
426
427  JavascriptGo("-1");
428  EXPECT_EQ(L"bot1", GetTabTitle());
429
430  JavascriptGo("1");
431  EXPECT_EQ(L"bot2", GetTabTitle());
432
433  JavascriptGo("-1");
434  EXPECT_EQ(L"bot1", GetTabTitle());
435
436  JavascriptGo("2");
437  EXPECT_EQ(L"bot3", GetTabTitle());
438
439  // history is [blank, bot1, bot2, *bot3]
440
441  JavascriptGo("-3");
442  EXPECT_EQ(L"about:blank", GetTabTitle());
443
444  ASSERT_FALSE(tab_->GoBack());
445  EXPECT_EQ(L"about:blank", GetTabTitle());
446
447  JavascriptGo("1");
448  EXPECT_EQ(L"bot1", GetTabTitle());
449
450  ASSERT_TRUE(tab_->NavigateToURL(
451      test_server_.GetURL("files/session_history/bot3.html")));
452  EXPECT_EQ(L"bot3", GetTabTitle());
453
454  // history is [blank, bot1, *bot3]
455
456  ASSERT_FALSE(tab_->GoForward());
457  EXPECT_EQ(L"bot3", GetTabTitle());
458
459  JavascriptGo("-1");
460  EXPECT_EQ(L"bot1", GetTabTitle());
461
462  JavascriptGo("-1");
463  EXPECT_EQ(L"about:blank", GetTabTitle());
464
465  ASSERT_FALSE(tab_->GoBack());
466  EXPECT_EQ(L"about:blank", GetTabTitle());
467
468  JavascriptGo("1");
469  EXPECT_EQ(L"bot1", GetTabTitle());
470
471  JavascriptGo("1");
472  EXPECT_EQ(L"bot3", GetTabTitle());
473
474  // TODO(creis): Test that JavaScript history navigations work across tab
475  // types.  For example, load about:network in a tab, then a real page, then
476  // try to go back and forward with JavaScript.  Bug 1136715.
477  // (Hard to test right now, because pages like about:network cause the
478  // TabProxy to hang.  This is because they do not appear to use the
479  // NotificationService.)
480}
481
482// This test is failing consistently. See http://crbug.com/22560
483TEST_F(SessionHistoryTest, FAILS_LocationReplace) {
484  ASSERT_TRUE(test_server_.Start());
485
486  // Test that using location.replace doesn't leave the title of the old page
487  // visible.
488  ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL(
489      "files/session_history/replace.html?no-title.html")));
490  EXPECT_EQ(L"", GetTabTitle());
491}
492
493// This test is flaky. See bug 22111.
494TEST_F(SessionHistoryTest, FLAKY_HistorySearchXSS) {
495  // about:blank should be loaded first.
496  ASSERT_FALSE(tab_->GoBack());
497  EXPECT_EQ(L"about:blank", GetTabTitle());
498
499  GURL url(std::string(chrome::kChromeUIHistoryURL) +
500      "#q=%3Cimg%20src%3Dx%3Ax%20onerror%3D%22document.title%3D'XSS'%22%3E");
501  ASSERT_TRUE(tab_->NavigateToURL(url));
502  // Mainly, this is to ensure we send a synchronous message to the renderer
503  // so that we're not susceptible (less susceptible?) to a race condition.
504  // Should a race condition ever trigger, it won't result in flakiness.
505  int num = tab_->FindInPage(L"<img", FWD, CASE_SENSITIVE, false, NULL);
506  EXPECT_GT(num, 0);
507  EXPECT_EQ(L"History", GetTabTitle());
508}
509
510#if defined(OS_WIN)
511// See http://crbug.com/61619
512#define MAYBE_LocationChangeInSubframe FLAKY_LocationChangeInSubframe
513#else
514#define MAYBE_LocationChangeInSubframe LocationChangeInSubframe
515#endif
516
517TEST_F(SessionHistoryTest, MAYBE_LocationChangeInSubframe) {
518  ASSERT_TRUE(test_server_.Start());
519
520  ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL(
521      "files/session_history/location_redirect.html")));
522  EXPECT_EQ(L"Default Title", GetTabTitle());
523
524  ASSERT_TRUE(tab_->NavigateToURL(GURL(
525      "javascript:void(frames[0].navigate())")));
526  EXPECT_EQ(L"foo", GetTabTitle());
527
528  ASSERT_TRUE(tab_->GoBack());
529  EXPECT_EQ(L"Default Title", GetTabTitle());
530}
531
532// http://code.google.com/p/chromium/issues/detail?id=56267
533TEST_F(SessionHistoryTest, DISABLED_HistoryLength) {
534  ASSERT_TRUE(test_server_.Start());
535
536  int length;
537  ASSERT_TRUE(tab_->ExecuteAndExtractInt(
538      L"", L"domAutomationController.send(history.length)", &length));
539  EXPECT_EQ(1, length);
540
541  ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL("files/title1.html")));
542
543  ASSERT_TRUE(tab_->ExecuteAndExtractInt(
544      L"", L"domAutomationController.send(history.length)", &length));
545  EXPECT_EQ(2, length);
546
547  // Now test that history.length is updated when the navigation is committed.
548  ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL(
549      "files/session_history/record_length.html")));
550  ASSERT_TRUE(tab_->ExecuteAndExtractInt(
551      L"", L"domAutomationController.send(history.length)", &length));
552  EXPECT_EQ(3, length);
553  ASSERT_TRUE(tab_->ExecuteAndExtractInt(
554      L"", L"domAutomationController.send(history_length)", &length));
555  EXPECT_EQ(3, length);
556
557  ASSERT_TRUE(tab_->GoBack());
558  ASSERT_TRUE(tab_->GoBack());
559
560  // Ensure history.length is properly truncated.
561  ASSERT_TRUE(tab_->NavigateToURL(test_server_.GetURL("files/title2.html")));
562  ASSERT_TRUE(tab_->ExecuteAndExtractInt(
563      L"", L"domAutomationController.send(history.length)", &length));
564  EXPECT_EQ(2, length);
565}
566
567}  // namespace
568