1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.javascript.host;
16
17 import static java.nio.charset.StandardCharsets.ISO_8859_1;
18
19 import java.time.Duration;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.List;
23
24 import org.htmlunit.WebDriverTestCase;
25 import org.htmlunit.junit.annotation.Alerts;
26 import org.htmlunit.junit.annotation.HtmlUnitNYI;
27 import org.htmlunit.util.NameValuePair;
28 import org.junit.jupiter.api.Test;
29 import org.openqa.selenium.By;
30 import org.openqa.selenium.JavascriptExecutor;
31 import org.openqa.selenium.WebDriver;
32
33
34
35
36
37
38
39
40
41
42
43
44 public class History2Test extends WebDriverTestCase {
45
46
47
48
49 @Test
50 @Alerts("here")
51 public void goShouldIgnoreOutOfBoundIndex() throws Exception {
52 final String html = DOCTYPE_HTML
53 + "<html><body>\n"
54 + "<script>\n"
55 + LOG_TITLE_FUNCTION
56 + "history.go(1);\n"
57 + "log('here');\n"
58 + "</script></body></html>";
59
60 loadPageVerifyTitle2(html);
61 assertEquals(1, getMockWebConnection().getRequestCount());
62 }
63
64
65
66
67 @Test
68 @Alerts({"[object PopStateEvent]", "null"})
69 public void pushStateSimple() throws Exception {
70 final String html = DOCTYPE_HTML
71 + "<html>\n"
72 + "<head>\n"
73 + "<script>\n"
74 + LOG_TITLE_FUNCTION
75 + " function test() {\n"
76 + " if (!window.history.pushState) { log('no pushState'); return }\n"
77 + " var stateObj = { hi: 'there' };\n"
78 + " window.history.pushState(stateObj, 'page 2', 'bar.html');\n"
79 + " }\n"
80
81 + " function popMe(event) {\n"
82 + " var e = event ? event : window.event;\n"
83 + " log(e);\n"
84 + " log(e.state);\n"
85 + " }\n"
86 + "</script>\n"
87 + "</head>\n"
88 + "<body onpopstate='popMe(event)'>\n"
89 + " <button id=myId onclick='test()'>Click me</button>\n"
90 + "</body></html>";
91
92 final String[] expectedAlerts = getExpectedAlerts();
93 final WebDriver driver = loadPage2(html);
94 driver.findElement(By.id("myId")).click();
95
96 if (expectedAlerts.length > 1) {
97 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
98 driver.navigate().back();
99 }
100 verifyTitle2(driver, expectedAlerts);
101 }
102
103
104
105
106 @Test
107 @Alerts({"[object PopStateEvent]", "{\"hi\":\"there\"}",
108 "[object PopStateEvent]", "{\"hi\":\"there\"}",
109 "[object PopStateEvent]", "null",
110 "[object PopStateEvent]", "null",
111 "[object PopStateEvent]", "{\"hi\":\"there\"}",
112 "[object PopStateEvent]", "{\"hi\":\"there\"}",
113 "[object PopStateEvent]", "{\"hi2\":\"there2\"}",
114 "[object PopStateEvent]", "{\"hi2\":\"there2\"}"})
115 public void pushState() throws Exception {
116 final String html = DOCTYPE_HTML
117 + "<html>\n"
118 + "<head>\n"
119 + "<script>\n"
120 + LOG_TITLE_FUNCTION
121 + " function test() {\n"
122 + " if (window.history.pushState) {\n"
123 + " var stateObj = { hi: 'there' };\n"
124 + " window.history.pushState(stateObj, 'page 2', 'bar.html');\n"
125 + " }\n"
126 + " }\n"
127
128 + " function test2() {\n"
129 + " if (window.history.pushState) {\n"
130 + " var stateObj = { hi2: 'there2' };\n"
131 + " window.history.pushState(stateObj, 'page 3', 'bar2.html');\n"
132 + " }\n"
133 + " }\n"
134
135 + " function popMe(event) {\n"
136 + " var e = event ? event : window.event;\n"
137 + " log(e);\n"
138 + " log(JSON.stringify(e.state));\n"
139 + " }\n"
140
141 + " function setWindowName() {\n"
142 + " window.name = window.name + 'a\\u00a7';\n"
143 + " }\n"
144
145 + " window.addEventListener('popstate', popMe);\n"
146 + "</script>\n"
147 + "</head>\n"
148 + "<body onpopstate='popMe(event)' onload='setWindowName()' onbeforeunload='setWindowName()' "
149 + "onunload='setWindowName()'>\n"
150 + " <button id=myId onclick='test()'>Click me</button>\n"
151 + " <button id=myId2 onclick='test2()'>Click me</button>\n"
152 + "</body></html>";
153
154 final String[] expectedAlerts = getExpectedAlerts();
155 int i = 0;
156
157 final WebDriver driver = loadPage2(html);
158 verifyWindowName2(driver, "a");
159
160 final long start = (Long) ((JavascriptExecutor) driver).executeScript("return window.history.length");
161
162 driver.findElement(By.id("myId")).click();
163 verifyWindowName2(driver, "a");
164 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
165 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
166
167 driver.findElement(By.id("myId2")).click();
168 verifyWindowName2(driver, "a");
169 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
170 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
171
172 driver.navigate().back();
173 i = i + 4;
174 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, i));
175 verifyWindowName2(driver, "a");
176 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
177 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
178
179 driver.navigate().back();
180 i = i + 4;
181 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, i));
182 verifyWindowName2(driver, "a");
183 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
184 assertEquals(URL_FIRST.toString(), driver.getCurrentUrl());
185
186 driver.navigate().forward();
187 i = i + 4;
188 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, i));
189 verifyWindowName2(driver, "a");
190 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
191 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
192
193 driver.navigate().forward();
194 i = i + 4;
195 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, i));
196 verifyWindowName2(driver, "a");
197 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
198 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
199
200 assertEquals(1, getMockWebConnection().getRequestCount());
201
202
203 releaseResources();
204 shutDownAll();
205 }
206
207
208
209
210 @Test
211 @Alerts({"[object PopStateEvent]", "{\"hi\":\"there\"}", "true",
212 "[object PopStateEvent]", "{\"hi\":\"there\"}", "true",
213 "[object PopStateEvent]", "null", "true",
214 "[object PopStateEvent]", "null", "true",
215 "[object PopStateEvent]", "{\"hi\":\"there\"}", "true",
216 "[object PopStateEvent]", "{\"hi\":\"there\"}", "true",
217 "[object PopStateEvent]", "{\"hi2\":\"there2\"}", "true",
218 "[object PopStateEvent]", "{\"hi2\":\"there2\"}", "true"})
219 public void pushStateClone() throws Exception {
220 final String html = DOCTYPE_HTML
221 + "<html>\n"
222 + "<head>\n"
223 + "<script>\n"
224 + LOG_TITLE_FUNCTION
225 + " function test() {\n"
226 + " if (window.history.pushState) {\n"
227 + " var stateObj = { hi: 'there' };\n"
228 + " window.history.pushState(stateObj, 'page 2', 'bar.html');\n"
229 + " }\n"
230 + " }\n"
231
232 + " function test2() {\n"
233 + " if (window.history.pushState) {\n"
234 + " var stateObj = { hi2: 'there2' };\n"
235 + " window.history.pushState(stateObj, 'page 3', 'bar2.html');\n"
236 + " }\n"
237 + " }\n"
238
239 + " function popMe(event) {\n"
240 + " var e = event ? event : window.event;\n"
241 + " log(e);\n"
242 + " log(JSON.stringify(e.state));\n"
243 + " log(e.state == history.state);\n"
244 + " }\n"
245
246 + " function setWindowName() {\n"
247 + " window.name = window.name + 'a\\u00a7';\n"
248 + " }\n"
249
250 + " window.addEventListener('popstate', popMe);\n"
251 + "</script>\n"
252 + "</head>\n"
253 + "<body onpopstate='popMe(event)' onload='setWindowName()' onbeforeunload='setWindowName()' "
254 + "onunload='setWindowName()'>\n"
255 + " <button id=myId onclick='test()'>Click me</button>\n"
256 + " <button id=myId2 onclick='test2()'>Click me</button>\n"
257 + "</body></html>";
258
259 final String[] expectedAlerts = getExpectedAlerts();
260 int i = 0;
261 final WebDriver driver = loadPage2(html);
262 verifyWindowName2(driver, "a");
263
264 final long start = (Long) ((JavascriptExecutor) driver).executeScript("return window.history.length");
265
266 final long waitTime = 4 * DEFAULT_WAIT_TIME.toMillis();
267 if (expectedAlerts.length != 0) {
268 driver.findElement(By.id("myId")).click();
269 verifyWindowName2(driver, "a");
270 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
271 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
272
273 driver.findElement(By.id("myId2")).click();
274 verifyWindowName2(driver, "a");
275 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
276 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
277
278 driver.navigate().back();
279 i = 6;
280 verifyTitle2(Duration.ofMillis(waitTime), driver, Arrays.copyOfRange(expectedAlerts, 0, i));
281 verifyWindowName2(driver, "a");
282 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
283 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
284
285 driver.navigate().back();
286 i = i + 6;
287 verifyTitle2(Duration.ofMillis(waitTime), driver, Arrays.copyOfRange(expectedAlerts, 0, i));
288 verifyWindowName2(driver, "a");
289 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
290 assertEquals(URL_FIRST.toString(), driver.getCurrentUrl());
291
292 driver.navigate().forward();
293 i = i + 6;
294 verifyTitle2(Duration.ofMillis(waitTime), driver, Arrays.copyOfRange(expectedAlerts, 0, i));
295 verifyWindowName2(driver, "a");
296 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
297 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
298
299 driver.navigate().forward();
300 i = i + 6;
301 verifyTitle2(Duration.ofMillis(waitTime), driver, Arrays.copyOfRange(expectedAlerts, 0, i));
302 verifyWindowName2(driver, "a");
303 assertEquals(start + 2, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
304 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
305 }
306
307 assertEquals(1, getMockWebConnection().getRequestCount());
308
309
310 releaseResources();
311 shutDownAll();
312 }
313
314
315
316
317 @Test
318 @Alerts({"true", "true"})
319 public void pushStateLocationHref() throws Exception {
320 final String html = DOCTYPE_HTML
321 + "<html>\n"
322 + "<head>\n"
323 + "<script>\n"
324 + LOG_TITLE_FUNCTION
325 + " function test() {\n"
326 + " if (!window.history.pushState) { log('no pushState'); return }\n"
327 + " try {\n"
328 + " var stateObj = { hi: 'there' };\n"
329 + " window.history.pushState(stateObj, 'page 2', 'bar.html');\n"
330 + " log(location.href.indexOf('bar.html') > -1);\n"
331 + " } catch(e) { logEx(e); }\n"
332 + " }\n"
333
334 + " function test2() {\n"
335 + " if (!window.history.pushState) { log('no pushState'); return }\n"
336 + " try {\n"
337 + " var stateObj = { hi2: 'there2' };\n"
338 + " window.history.pushState(stateObj, 'page 3', 'bar2.html');\n"
339 + " log(location.href.indexOf('bar2.html') > -1);\n"
340 + " } catch(e) { logEx(e); }\n"
341 + " }\n"
342
343 + "</script>\n"
344 + "</head>\n"
345 + "<body>\n"
346 + " <button id=myId onclick='test()'>Click me</button>\n"
347 + " <button id=myId2 onclick='test2()'>Click me</button>\n"
348 + "</body></html>";
349
350 final String[] expectedAlerts = getExpectedAlerts();
351 final WebDriver driver = loadPage2(html);
352 driver.findElement(By.id("myId")).click();
353 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, 1));
354
355 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
356 assertEquals(URL_FIRST + "bar.html", ((JavascriptExecutor) driver).executeScript("return location.href"));
357 driver.findElement(By.id("myId2")).click();
358 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, 2));
359
360 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
361 assertEquals(URL_FIRST + "bar2.html", ((JavascriptExecutor) driver).executeScript("return location.href"));
362 driver.navigate().back();
363 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
364 driver.navigate().back();
365 assertEquals(URL_FIRST.toString(), driver.getCurrentUrl());
366 driver.navigate().forward();
367 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
368 driver.navigate().forward();
369 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
370 }
371
372
373
374
375 @Test
376 @Alerts({"[object PopStateEvent]", "null",
377 "[object PopStateEvent]", "null",
378 "[object PopStateEvent]", "{\"hi2\":\"there2\"}",
379 "[object PopStateEvent]", "{\"hi2\":\"there2\"}"})
380 public void replaceState() throws Exception {
381 final String html = DOCTYPE_HTML
382 + "<html>\n"
383 + "<head>\n"
384 + "<script>\n"
385 + LOG_TITLE_FUNCTION
386 + " function test() {\n"
387 + " if (window.history.pushState) {\n"
388 + " var stateObj = { hi: 'there' };\n"
389 + " window.history.pushState(stateObj, 'page 2', 'bar.html');\n"
390 + " }\n"
391 + " }\n"
392
393 + " function test2() {\n"
394 + " if (window.history.replaceState) {\n"
395 + " var stateObj = { hi2: 'there2' };\n"
396 + " window.history.replaceState(stateObj, 'page 3', 'bar2.html');\n"
397 + " }\n"
398 + " }\n"
399
400 + " function popMe(event) {\n"
401 + " var e = event ? event : window.event;\n"
402 + " log(e);\n"
403 + " log(JSON.stringify(e.state));\n"
404 + " }\n"
405
406 + " function setWindowName() {\n"
407 + " window.name = window.name + 'a\\u00a7';\n"
408 + " }\n"
409
410 + " window.addEventListener('popstate', popMe);\n"
411 + "</script>\n"
412 + "</head>\n"
413 + "<body onpopstate='popMe(event)' onload='setWindowName()' onbeforeunload='setWindowName()' "
414 + "onunload='setWindowName()'>\n"
415 + " <button id='myId' onclick='test()'>Click me</button>\n"
416 + " <button id='myId2' onclick='test2()'>Click me</button>\n"
417 + "</body></html>";
418
419 final String[] expectedAlerts = getExpectedAlerts();
420 int i = 0;
421 final WebDriver driver = loadPage2(html);
422
423 verifyWindowName2(driver, "a");
424 final long start = (Long) ((JavascriptExecutor) driver).executeScript("return window.history.length");
425
426 if (expectedAlerts.length != 0) {
427 driver.findElement(By.id("myId")).click();
428 verifyWindowName2(driver, "a");
429 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
430 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
431
432 driver.findElement(By.id("myId2")).click();
433 verifyWindowName2(driver, "a");
434 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
435 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
436
437 driver.navigate().back();
438 i = i + 4;
439 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, i));
440 verifyWindowName2(driver, "a");
441 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
442 assertEquals(URL_FIRST.toString(), driver.getCurrentUrl());
443
444 driver.navigate().forward();
445 i = i + 4;
446 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, i));
447 verifyWindowName2(driver, "a");
448 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
449 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
450 }
451
452 assertEquals(1, getMockWebConnection().getRequestCount());
453
454
455 releaseResources();
456 shutDownAll();
457 }
458
459
460
461
462 @Test
463 @Alerts({"[object PopStateEvent]", "null", "true",
464 "[object PopStateEvent]", "null", "true",
465 "[object PopStateEvent]", "{\"hi2\":\"there2\"}", "true",
466 "[object PopStateEvent]", "{\"hi2\":\"there2\"}", "true"})
467 public void replaceStateClone() throws Exception {
468 final String html = DOCTYPE_HTML
469 + "<html>\n"
470 + "<head>\n"
471 + "<script>\n"
472 + LOG_TITLE_FUNCTION
473 + " function test() {\n"
474 + " if (window.history.pushState) {\n"
475 + " var stateObj = { hi: 'there' };\n"
476 + " window.history.pushState(stateObj, 'page 2', 'bar.html');\n"
477 + " }\n"
478 + " }\n"
479
480 + " function test2() {\n"
481 + " if (window.history.replaceState) {\n"
482 + " var stateObj = { hi2: 'there2' };\n"
483 + " window.history.replaceState(stateObj, 'page 3', 'bar2.html');\n"
484 + " }\n"
485 + " }\n"
486
487 + " function popMe(event) {\n"
488 + " var e = event ? event : window.event;\n"
489 + " log(e);\n"
490 + " log(JSON.stringify(e.state));\n"
491 + " log(e.state == history.state);\n"
492 + " }\n"
493
494 + " function setWindowName() {\n"
495 + " window.name = window.name + 'a\\u00a7';\n"
496 + " }\n"
497
498 + " window.addEventListener('popstate', popMe);\n"
499 + "</script>\n"
500 + "</head>\n"
501 + "<body onpopstate='popMe(event)' onload='setWindowName()' onbeforeunload='setWindowName()' "
502 + "onunload='setWindowName()'>\n"
503 + " <button id=myId onclick='test()'>Click me</button>\n"
504 + " <button id=myId2 onclick='test2()'>Click me</button>\n"
505 + "</body></html>";
506
507 final String[] expectedAlerts = getExpectedAlerts();
508 int i = 0;
509 final WebDriver driver = loadPage2(html);
510
511 verifyWindowName2(driver, "a");
512 final long start = (Long) ((JavascriptExecutor) driver).executeScript("return window.history.length");
513
514 if (expectedAlerts.length != 0) {
515 driver.findElement(By.id("myId")).click();
516 verifyWindowName2(driver, "a");
517 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
518 assertEquals(URL_FIRST + "bar.html", driver.getCurrentUrl());
519
520 driver.findElement(By.id("myId2")).click();
521 verifyWindowName2(driver, "a");
522 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
523 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
524
525 driver.navigate().back();
526 i = i + 6;
527 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, i));
528 verifyWindowName2(driver, "a");
529 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
530 assertEquals(URL_FIRST.toString(), driver.getCurrentUrl());
531
532 driver.navigate().forward();
533 i = i + 6;
534 verifyTitle2(driver, Arrays.copyOfRange(expectedAlerts, 0, i));
535 verifyWindowName2(driver, "a");
536 assertEquals(start + 1, ((JavascriptExecutor) driver).executeScript("return window.history.length"));
537 assertEquals(URL_FIRST + "bar2.html", driver.getCurrentUrl());
538 }
539
540 assertEquals(1, getMockWebConnection().getRequestCount());
541
542
543 releaseResources();
544 shutDownAll();
545 }
546
547
548
549
550 @Test
551 @Alerts(DEFAULT = {"href=§§URL§§", "href=§§URL§§?p=%C3%84"},
552 FF = {"href=§§URL§§", "href=§§URL§§?p=%C4"},
553 FF_ESR = {"href=§§URL§§", "href=§§URL§§?p=%C4"})
554 @HtmlUnitNYI(CHROME = {"href=§§URL§§", "href=§§URL§§?p=%C4"},
555 EDGE = {"href=§§URL§§", "href=§§URL§§?p=%C4"})
556 public void pushStateEncoding() throws Exception {
557 final String html = DOCTYPE_HTML
558 + "<html>\n"
559 + "<head>\n"
560 + "<script>\n"
561 + LOG_TITLE_FUNCTION
562 + " function test() {\n"
563 + " log('href=' + location.href);\n"
564 + " window.history.pushState(null, '', '" + URL_FIRST + "?p=\u00c4');\n"
565 + " log('href=' + location.href);\n"
566 + " }\n"
567 + "</script>\n"
568 + "</head>\n"
569 + "<body onload='test()'>\n"
570 + "</body></html>";
571
572 expandExpectedAlertsVariables(URL_FIRST);
573 loadPageVerifyTitle2(html);
574 }
575
576
577
578
579 @Test
580 @Alerts({"href=§§URL§§", "hash=", "href=§§URL§§#foo", "hash=#foo", "onhashchange #proof"})
581 public void pushStateChangeHash() throws Exception {
582 final String html = DOCTYPE_HTML
583 + "<html>\n"
584 + "<head>\n"
585 + "<script>\n"
586 + LOG_TITLE_FUNCTION
587 + " function test() {\n"
588 + " log('href=' + location.href);\n"
589 + " log('hash=' + location.hash);\n"
590 + " window.history.pushState({ hi: 'there' }, '', '" + URL_FIRST + "#foo');\n"
591 + " log('href=' + location.href);\n"
592 + " log('hash=' + location.hash);\n"
593
594 + " location.hash = 'proof';"
595 + " }\n"
596
597 + " function locationHashChanged(event) {\n"
598 + " log('onhashchange ' + location.hash);\n"
599 + " }\n"
600 + " window.onhashchange = locationHashChanged;\n"
601 + "</script>\n"
602 + "</head>\n"
603 + "<body onload='test()'>\n"
604 + "</body></html>";
605
606 expandExpectedAlertsVariables(URL_FIRST);
607 loadPageVerifyTitle2(html);
608 }
609
610
611
612
613 @Test
614 @Alerts({"href=§§URL§§", "href=§§URL§§"})
615 public void replaceStateNull() throws Exception {
616 final String html = DOCTYPE_HTML
617 + "<html>\n"
618 + "<head>\n"
619 + "<script>\n"
620 + LOG_TITLE_FUNCTION
621 + " function test() {\n"
622 + " log('href=' + location.href);\n"
623 + " window.history.replaceState(null, '', null);\n"
624 + " log('href=' + location.href);\n"
625 + " }\n"
626 + "</script>\n"
627 + "</head>\n"
628 + "<body onload='test()'>\n"
629 + "</body></html>";
630
631 expandExpectedAlertsVariables(URL_FIRST);
632 loadPageVerifyTitle2(html);
633 }
634
635
636
637
638 @Test
639 @Alerts({"href=§§URL§§", "href=§§URL§§"})
640 public void replaceStateUndefined() throws Exception {
641 final String html = DOCTYPE_HTML
642 + "<html>\n"
643 + "<head>\n"
644 + "<script>\n"
645 + LOG_TITLE_FUNCTION
646 + " function test() {\n"
647 + " log('href=' + location.href);\n"
648 + " window.history.replaceState(null, '', undefined);\n"
649 + " log('href=' + location.href);\n"
650 + " }\n"
651 + "</script>\n"
652 + "</head>\n"
653 + "<body onload='test()'>\n"
654 + "</body></html>";
655
656 expandExpectedAlertsVariables(URL_FIRST);
657 loadPageVerifyTitle2(html);
658 }
659
660
661
662
663 @Test
664 @Alerts({"href=§§URL§§", "href=§§URL§§undefined"})
665 public void replaceStateUndefinedString() throws Exception {
666 final String html = DOCTYPE_HTML
667 + "<html>\n"
668 + "<head>\n"
669 + "<script>\n"
670 + LOG_TITLE_FUNCTION
671 + " function test() {\n"
672 + " log('href=' + location.href);\n"
673 + " window.history.replaceState(null, '', 'undefined');\n"
674 + " log('href=' + location.href);\n"
675 + " }\n"
676 + "</script>\n"
677 + "</head>\n"
678 + "<body onload='test()'>\n"
679 + "</body></html>";
680
681 expandExpectedAlertsVariables(URL_FIRST);
682 loadPageVerifyTitle2(html);
683 }
684
685
686
687
688 @Test
689 @Alerts({"href=§§URL§§", "href=§§URL§§[object%20Object]"})
690 @HtmlUnitNYI(CHROME = {"href=§§URL§§", "href=§§URL§§%5Bobject%20Object%5D"},
691 EDGE = {"href=§§URL§§", "href=§§URL§§%5Bobject%20Object%5D"},
692 FF = {"href=§§URL§§", "href=§§URL§§%5Bobject%20Object%5D"},
693 FF_ESR = {"href=§§URL§§", "href=§§URL§§%5Bobject%20Object%5D"})
694 public void replaceStateObj() throws Exception {
695 final String html = DOCTYPE_HTML
696 + "<html>\n"
697 + "<head>\n"
698 + "<script>\n"
699 + LOG_TITLE_FUNCTION
700 + " function test() {\n"
701 + " log('href=' + location.href);\n"
702 + " "
703 + " window.history.replaceState(null, '', { val: 'abcd' });\n"
704 + " log('href=' + location.href);\n"
705 + " }\n"
706 + "</script>\n"
707 + "</head>\n"
708 + "<body onload='test()'>\n"
709 + "</body></html>";
710
711 expandExpectedAlertsVariables(URL_FIRST);
712 loadPageVerifyTitle2(html);
713 }
714
715
716
717
718 @Test
719 @Alerts({"href=§§URL§§", "href=§§URL§§"})
720 public void pushStateNull() throws Exception {
721 final String html = DOCTYPE_HTML
722 + "<html>\n"
723 + "<head>\n"
724 + "<script>\n"
725 + LOG_TITLE_FUNCTION
726 + " function test() {\n"
727 + " log('href=' + location.href);\n"
728 + " window.history.pushState(null, '', null);\n"
729 + " log('href=' + location.href);\n"
730 + " }\n"
731 + "</script>\n"
732 + "</head>\n"
733 + "<body onload='test()'>\n"
734 + "</body></html>";
735
736 expandExpectedAlertsVariables(URL_FIRST);
737 loadPageVerifyTitle2(html);
738 }
739
740
741
742
743 @Test
744 @Alerts({"href=§§URL§§", "href=§§URL§§"})
745 public void pushStateUndefined() throws Exception {
746 final String html = DOCTYPE_HTML
747 + "<html>\n"
748 + "<head>\n"
749 + "<script>\n"
750 + LOG_TITLE_FUNCTION
751 + " function test() {\n"
752 + " log('href=' + location.href);\n"
753 + " window.history.pushState(null, '', undefined);\n"
754 + " log('href=' + location.href);\n"
755 + " }\n"
756 + "</script>\n"
757 + "</head>\n"
758 + "<body onload='test()'>\n"
759 + "</body></html>";
760
761 expandExpectedAlertsVariables(URL_FIRST);
762 loadPageVerifyTitle2(html);
763 }
764
765
766
767
768 @Test
769 @Alerts({"href=§§URL§§", "href=§§URL§§undefined"})
770 public void pushStateUndefinedString() throws Exception {
771 final String html = DOCTYPE_HTML
772 + "<html>\n"
773 + "<head>\n"
774 + "<script>\n"
775 + LOG_TITLE_FUNCTION
776 + " function test() {\n"
777 + " log('href=' + location.href);\n"
778 + " window.history.pushState(null, '', 'undefined');\n"
779 + " log('href=' + location.href);\n"
780 + " }\n"
781 + "</script>\n"
782 + "</head>\n"
783 + "<body onload='test()'>\n"
784 + "</body></html>";
785
786 expandExpectedAlertsVariables(URL_FIRST);
787 loadPageVerifyTitle2(html);
788 }
789
790
791
792
793 @Test
794 @Alerts({"href=§§URL§§", "href=§§URL§§[object%20Object]"})
795 @HtmlUnitNYI(CHROME = {"href=§§URL§§", "href=§§URL§§%5Bobject%20Object%5D"},
796 EDGE = {"href=§§URL§§", "href=§§URL§§%5Bobject%20Object%5D"},
797 FF = {"href=§§URL§§", "href=§§URL§§%5Bobject%20Object%5D"},
798 FF_ESR = {"href=§§URL§§", "href=§§URL§§%5Bobject%20Object%5D"})
799 public void pushStateObj() throws Exception {
800 final String html = DOCTYPE_HTML
801 + "<html>\n"
802 + "<head>\n"
803 + "<script>\n"
804 + LOG_TITLE_FUNCTION
805 + " function test() {\n"
806 + " log('href=' + location.href);\n"
807 + " window.history.pushState(null, '', { val: 'abcd' });\n"
808 + " log('href=' + location.href);\n"
809 + " }\n"
810 + "</script>\n"
811 + "</head>\n"
812 + "<body onload='test()'>\n"
813 + "</body></html>";
814
815 expandExpectedAlertsVariables(URL_FIRST);
816 loadPageVerifyTitle2(html);
817 }
818
819
820
821
822 @Test
823 @Alerts({"href=§§URL§§", "hash=", "href=§§URL§§#foo", "hash=#foo", "onhashchange #proof"})
824 public void pushStateChangeHashNoStore() throws Exception {
825 final String html = DOCTYPE_HTML
826 + "<html>\n"
827 + "<head>\n"
828 + "<script>\n"
829 + LOG_TITLE_FUNCTION
830 + " function test() {\n"
831 + " log('href=' + location.href);\n"
832 + " log('hash=' + location.hash);\n"
833 + " window.history.pushState({ hi: 'there' }, '', '" + URL_FIRST + "#foo');\n"
834 + " log('href=' + location.href);\n"
835 + " log('hash=' + location.hash);\n"
836
837 + " location.hash = 'proof';"
838 + " }\n"
839
840 + " function locationHashChanged(event) {\n"
841 + " log('onhashchange ' + location.hash);\n"
842 + " }\n"
843 + " window.onhashchange = locationHashChanged;\n"
844 + "</script>\n"
845 + "</head>\n"
846 + "<body onload='test()'>\n"
847 + "</body></html>";
848
849 expandExpectedAlertsVariables(URL_FIRST);
850
851 final List<NameValuePair> headers = new ArrayList<>();
852 headers.add(new NameValuePair("Cache-Control", "no-store"));
853 getMockWebConnection().setResponse(URL_FIRST, html, 200, "OK", "text/html;charset=ISO-8859-1",
854 ISO_8859_1, headers);
855
856 final WebDriver driver = loadPage2(URL_FIRST, null);
857 verifyTitle2(driver, getExpectedAlerts());
858 }
859
860
861
862
863 @Test
864 @Alerts(DEFAULT = {"href=§§URL§§", "href=§§URL§§?p=%C3%84"},
865 FF = {"href=§§URL§§", "href=§§URL§§?p=%C4"},
866 FF_ESR = {"href=§§URL§§", "href=§§URL§§?p=%C4"})
867 @HtmlUnitNYI(CHROME = {"href=§§URL§§", "href=§§URL§§?p=%C4"},
868 EDGE = {"href=§§URL§§", "href=§§URL§§?p=%C4"})
869 public void replaceStateEncoding() throws Exception {
870 final String html = DOCTYPE_HTML
871 + "<html>\n"
872 + "<head>\n"
873 + "<script>\n"
874 + LOG_TITLE_FUNCTION
875 + " function test() {\n"
876 + " log('href=' + location.href);\n"
877 + " window.history.replaceState(null, '', '" + URL_FIRST + "?p=\u00c4');\n"
878 + " log('href=' + location.href);\n"
879 + " }\n"
880 + "</script>\n"
881 + "</head>\n"
882 + "<body onload='test()'>\n"
883 + "</body></html>";
884
885 expandExpectedAlertsVariables(URL_FIRST);
886 loadPageVerifyTitle2(html);
887 }
888
889
890
891
892 @Test
893 @Alerts({"href=§§URL§§", "hash=", "href=§§URL§§#foo", "hash=#foo", "onhashchange #proof"})
894 public void replaceStateChangeHash() throws Exception {
895 final String html = DOCTYPE_HTML
896 + "<html>\n"
897 + "<head>\n"
898 + "<script>\n"
899 + LOG_TITLE_FUNCTION
900 + " function test() {\n"
901 + " log('href=' + location.href);\n"
902 + " log('hash=' + location.hash);\n"
903 + " window.history.replaceState({ hi: 'there' }, '', '" + URL_FIRST + "#foo');\n"
904 + " log('href=' + location.href);\n"
905 + " log('hash=' + location.hash);\n"
906
907
908 + " location.hash = 'proof';"
909 + " }\n"
910
911 + " function locationHashChanged(event) {\n"
912 + " log('onhashchange ' + location.hash);\n"
913 + " }\n"
914 + " window.onhashchange = locationHashChanged;\n"
915 + "</script>\n"
916 + "</head>\n"
917 + "<body onload='test()'>\n"
918 + "</body></html>";
919
920 expandExpectedAlertsVariables(URL_FIRST);
921 loadPageVerifyTitle2(html);
922 }
923
924
925
926
927 @Test
928 @Alerts({"href=§§URL§§", "hash=", "href=§§URL§§#foo", "hash=#foo", "onhashchange #proof"})
929 public void replaceStateChangeHashNoStore() throws Exception {
930 final String html = DOCTYPE_HTML
931 + "<html>\n"
932 + "<head>\n"
933 + "<script>\n"
934 + LOG_TITLE_FUNCTION
935 + " function test() {\n"
936 + " log('href=' + location.href);\n"
937 + " log('hash=' + location.hash);\n"
938 + " window.history.replaceState({ hi: 'there' }, '', '" + URL_FIRST + "#foo');\n"
939 + " log('href=' + location.href);\n"
940 + " log('hash=' + location.hash);\n"
941
942
943 + " location.hash = 'proof';"
944 + " }\n"
945
946 + " function locationHashChanged(event) {\n"
947 + " log('onhashchange ' + location.hash);\n"
948 + " }\n"
949 + " window.onhashchange = locationHashChanged;\n"
950 + "</script>\n"
951 + "</head>\n"
952 + "<body onload='test()'>\n"
953 + "</body></html>";
954
955 expandExpectedAlertsVariables(URL_FIRST);
956
957 final List<NameValuePair> headers = new ArrayList<>();
958 headers.add(new NameValuePair("Cache-Control", "no-store"));
959 getMockWebConnection().setResponse(URL_FIRST, html, 200, "OK", "text/html;charset=ISO-8859-1",
960 ISO_8859_1, headers);
961
962 final WebDriver driver = loadPage2(URL_FIRST, null);
963 verifyTitle2(driver, getExpectedAlerts());
964 }
965
966
967
968
969 @Test
970 public void length() throws Exception {
971 final String second = DOCTYPE_HTML
972 + "<html>\n"
973 + "<head></head>\n"
974 + "<body>\n"
975 + "<a name='length' href='' onclick='alert(history.length);return false;'>length</a><br>\n"
976 + "<a name='x' href='#x'>x</a><br>\n"
977 + "</body></html>\n";
978
979 getMockWebConnection().setResponse(URL_SECOND, second);
980
981 final String html = DOCTYPE_HTML
982 + "<html>\n"
983 + "<head></head>\n"
984 + "<body>\n"
985 + "<a name='length' href='' onclick='alert(history.length);return false;'>length</a><br>\n"
986 + "<a name='b' href='" + URL_SECOND + "'>b</a><br>\n"
987 + "</body></html>\n";
988
989 final WebDriver driver = loadPage2(html);
990 driver.findElement(By.name("length")).click();
991
992
993 final int start = Integer.parseInt(getCollectedAlerts(driver, 1).get(0));
994
995 driver.findElement(By.name("b")).click();
996 driver.findElement(By.name("length")).click();
997 assertEquals(new String[] {"" + (start + 1)}, getCollectedAlerts(driver, 1));
998
999 driver.findElement(By.name("x")).click();
1000 driver.findElement(By.name("length")).click();
1001 assertEquals(new String[] {"" + (start + 2)}, getCollectedAlerts(driver, 1));
1002 }
1003
1004
1005
1006
1007
1008
1009 @Test
1010 @Alerts("undefined")
1011 public void previous() throws Exception {
1012 final String html = DOCTYPE_HTML
1013 + "<html>\n"
1014 + "<head>\n"
1015 + "<script>\n"
1016 + LOG_TITLE_FUNCTION
1017 + "</script>\n"
1018 + "</head>\n"
1019 + "<body>\n"
1020 + "<a name='itemZero' href='' onclick='log(history.previous); return false;'>item zero</a>\n"
1021 + "</body></html>\n";
1022
1023 final WebDriver driver = loadPage2(html);
1024 driver.findElement(By.name("itemZero")).click();
1025
1026 verifyTitle2(driver, getExpectedAlerts());
1027 }
1028
1029
1030
1031
1032
1033
1034 @Test
1035 @Alerts("undefined")
1036 public void current() throws Exception {
1037 final String html = DOCTYPE_HTML
1038 + "<html>\n"
1039 + "<head>\n"
1040 + "<script>\n"
1041 + LOG_TITLE_FUNCTION
1042 + "</script>\n"
1043 + "</head>\n"
1044 + "<body>\n"
1045 + "<a name='itemZero' href='' onclick='log(history.current); return false;'>item zero</a>\n"
1046 + "</body></html>\n";
1047
1048 final WebDriver driver = loadPage2(html);
1049 driver.findElement(By.name("itemZero")).click();
1050
1051 verifyTitle2(driver, getExpectedAlerts());
1052 }
1053
1054
1055
1056
1057
1058
1059 @Test
1060 @Alerts("undefined")
1061 public void next() throws Exception {
1062 final String html = DOCTYPE_HTML
1063 + "<html>\n"
1064 + "<head>\n"
1065 + "<script>\n"
1066 + LOG_TITLE_FUNCTION
1067 + "</script>\n"
1068 + "</head>\n"
1069 + "<body>\n"
1070 + "<a name='itemZero' href='' onclick='log(history.next); return false;'>item zero</a>\n"
1071 + "</body></html>\n";
1072
1073 final WebDriver driver = loadPage2(html);
1074 driver.findElement(By.name("itemZero")).click();
1075
1076 verifyTitle2(driver, getExpectedAlerts());
1077 }
1078
1079
1080
1081
1082
1083
1084 @Test
1085 @Alerts("undefined")
1086 public void item() throws Exception {
1087 final String html = DOCTYPE_HTML
1088 + "<html>\n"
1089 + "<head>\n"
1090 + "<script>\n"
1091 + LOG_TITLE_FUNCTION
1092 + "</script>\n"
1093 + "</head>\n"
1094 + "<body>\n"
1095 + "<a name='itemZero' href='' onclick='log(history.item); return false;'>item zero</a>\n"
1096 + "</body></html>\n";
1097
1098 final WebDriver driver = loadPage2(html);
1099 driver.findElement(By.name("itemZero")).click();
1100
1101 verifyTitle2(driver, getExpectedAlerts());
1102 }
1103
1104
1105
1106
1107 @Test
1108 @Alerts({"false", "false", "false", "false", "false", "false"})
1109 public void byIndex() throws Exception {
1110 final String html = DOCTYPE_HTML
1111 + "<html>\n"
1112 + "<head>\n"
1113 + "<script>\n"
1114 + LOG_TITLE_FUNCTION
1115 + "</script>\n"
1116 + "</head>\n"
1117 + "<body>\n"
1118 + "<a name='hasNegativeOne' href='' onclick="
1119 + "'log(\"-1\" in history);log(-1 in history);return false;'>has negative one</a><br>\n"
1120 + "<a name='hasZero' href='' onclick="
1121 + "'log(\"0\" in history);log(0 in history);return false;'>has zero</a><br>\n"
1122 + "<a name='hasPositiveOne' href='' onclick="
1123 + "'log(\"1\" in history);log(1 in history);return false;'>has positive one</a><br>\n"
1124 + "</body></html>\n";
1125
1126 final WebDriver driver = loadPage2(html);
1127 driver.findElement(By.name("hasNegativeOne")).click();
1128 verifyTitle2(driver, Arrays.copyOfRange(getExpectedAlerts(), 0, 2));
1129 driver.findElement(By.name("hasZero")).click();
1130 verifyTitle2(driver, Arrays.copyOfRange(getExpectedAlerts(), 0, 4));
1131 driver.findElement(By.name("hasPositiveOne")).click();
1132 verifyTitle2(driver, Arrays.copyOfRange(getExpectedAlerts(), 0, 6));
1133 }
1134
1135
1136
1137
1138 @Test
1139 @Alerts("undefined")
1140 public void arrayAccess() throws Exception {
1141 final String html = DOCTYPE_HTML
1142 + "<html>\n"
1143 + "<head>\n"
1144 + "<script>\n"
1145 + LOG_TITLE_FUNCTION
1146 + "</script>\n"
1147 + "</head>\n"
1148 + "<body>\n"
1149 + "<a name='arrayAccess' href='' onclick='log(history[0]);return false;'>array access</a><br>\n"
1150 + "</body></html>\n";
1151
1152 final WebDriver driver = loadPage2(html);
1153 driver.findElement(By.name("arrayAccess")).click();
1154
1155 verifyTitle2(driver, getExpectedAlerts());
1156 }
1157
1158
1159
1160
1161 @Test
1162 @Alerts("null")
1163 public void state() throws Exception {
1164 final String html = DOCTYPE_HTML
1165 + "<html><head><script>\n"
1166 + LOG_TITLE_FUNCTION
1167 + " function test() {\n"
1168 + " log(history.state);\n"
1169 + " }\n"
1170 + "</script></head>\n"
1171 + "<body onload='test()'>\n"
1172 + "</body></html>";
1173
1174 loadPageVerifyTitle2(html);
1175 }
1176
1177
1178
1179
1180 @Test
1181 @Alerts({"back", "forward", "go", "length", "pushState", "replaceState",
1182 "scrollRestoration", "state"})
1183 public void properties() throws Exception {
1184 final String html = DOCTYPE_HTML
1185 + "<html><head><script>\n"
1186 + LOG_TITLE_FUNCTION
1187 + " function test() {\n"
1188 + " var props = [];\n"
1189 + " var i = 0;\n"
1190 + " for (prop in window.history) {\n"
1191 + " props[i++] = prop;\n"
1192 + " }\n"
1193 + " props.sort();\n"
1194 + " for (i = 0; i < props.length; i++) {\n"
1195 + " log(props[i]);\n"
1196 + " }\n"
1197 + " }\n"
1198 + "</script></head>\n"
1199 + "<body onload='test()'>\n"
1200 + "</body></html>";
1201
1202 loadPageVerifyTitle2(html);
1203 }
1204
1205
1206
1207
1208
1209 @Test
1210 public void loadPageAfterPushState() throws Exception {
1211 final String html = DOCTYPE_HTML
1212 + "<html>\n"
1213 + "<head>\n"
1214 + "<title>page1</title>\n"
1215 + "<script>\n"
1216 + " function pushState() {\n"
1217 + " window.history.pushState({'key':'value'});\n"
1218 + " }\n"
1219 + "</script>\n"
1220 + "</head>\n"
1221 + "<body onload='pushState()'>\n"
1222 + "</body></html>";
1223 final String html2 = DOCTYPE_HTML
1224 + "<html>\n"
1225 + "<head>\n"
1226 + "<title>page2</title>\n"
1227 + "</head>\n"
1228 + "<body>\n"
1229 + "</body></html>";
1230
1231 final WebDriver driver = loadPage2(html);
1232 assertTitle(driver, "page1");
1233
1234 loadPage2(html2, URL_SECOND);
1235 assertTitle(driver, "page2");
1236 }
1237
1238
1239
1240
1241 @Test
1242 @Alerts({"auto", "manual", "auto", "auto", "auto", "auto"})
1243 public void scrollRestoration() throws Exception {
1244 final String html = DOCTYPE_HTML
1245 + "<html><head><script>\n"
1246 + LOG_TITLE_FUNCTION
1247 + " function test() {\n"
1248 + " log(history.scrollRestoration);\n"
1249
1250 + " history.scrollRestoration = 'manual';\n"
1251 + " log(history.scrollRestoration);\n"
1252
1253 + " history.scrollRestoration = 'auto';\n"
1254 + " log(history.scrollRestoration);\n"
1255
1256 + " history.scrollRestoration = 'MaNUaL';\n"
1257 + " log(history.scrollRestoration);\n"
1258
1259 + " history.scrollRestoration = 'unknown';\n"
1260 + " log(history.scrollRestoration);\n"
1261
1262 + " history.scrollRestoration = undefined;\n"
1263 + " log(history.scrollRestoration);\n"
1264
1265 + " }\n"
1266 + "</script></head>\n"
1267 + "<body onload='test()'>\n"
1268 + "</body></html>";
1269
1270 loadPageVerifyTitle2(html);
1271 }
1272
1273
1274
1275
1276 @Test
1277 public void testHistoryBackAndForwarWithNoStoreCacheControlHeader() throws Exception {
1278 final String html = DOCTYPE_HTML
1279 + "<html><body>"
1280 + "<a id='startButton' href='" + URL_SECOND + "'>Start</a>\n"
1281 + "</body></html>";
1282 final String secondContent = DOCTYPE_HTML
1283 + "<html><head></head>\n"
1284 + "<body>\n"
1285 + " <a id='nextButton' href='" + URL_THIRD + "'>Next</a>\n"
1286 + " <a id='forwardButton' onclick='javascript:window.history.forward()'>Forward</a>\n"
1287 + "</body></html>";
1288 final String thirdContent = DOCTYPE_HTML
1289 + "<html><body>"
1290 + "<a id='backButton' onclick='javascript:window.history.back()'>Back</a>\n"
1291 + "</body></html>";
1292
1293 final List<NameValuePair> headers = new ArrayList<>();
1294 headers.add(new NameValuePair("Cache-Control", "some-other-value, no-store"));
1295 getMockWebConnection().setResponse(URL_SECOND, secondContent, 200, "OK", "text/html;charset=ISO-8859-1",
1296 ISO_8859_1, headers);
1297 getMockWebConnection().setResponse(URL_THIRD, thirdContent, 200, "OK", "text/html;charset=ISO-8859-1",
1298 ISO_8859_1, headers);
1299
1300 final WebDriver driver = loadPage2(html);
1301 driver.findElement(By.id("startButton")).click();
1302 driver.findElement(By.id("nextButton")).click();
1303 driver.findElement(By.id("backButton")).click();
1304
1305 assertEquals(URL_SECOND.toString(), driver.getCurrentUrl());
1306 assertEquals(4, getMockWebConnection().getRequestCount());
1307
1308 driver.findElement(By.id("forwardButton")).click();
1309 assertEquals(URL_THIRD.toString(), driver.getCurrentUrl());
1310 assertEquals(5, getMockWebConnection().getRequestCount());
1311 }
1312 }