window-history.sub.html (5055B)
1 <!DOCTYPE html> 2 <!-- 3 [%provenance%] 4 --> 5 <html lang="en"> 6 <meta charset="utf-8"> 7 {%- if subtests|length > 10 %} 8 <meta name="timeout" content="long"> 9 {%- endif %} 10 <title>HTTP headers on request for navigation via the HTML History API</title> 11 <script src="/resources/testharness.js"></script> 12 <script src="/resources/testharnessreport.js"></script> 13 {%- if subtests|selectattr('userActivated')|list %} 14 <script src="/resources/testdriver.js"></script> 15 <script src="/resources/testdriver-vendor.js"></script> 16 {%- endif %} 17 <script src="/fetch/metadata/resources/helper.sub.js"></script> 18 <body> 19 <script> 20 'use strict'; 21 22 const whenDone = (win) => { 23 return new Promise((resolve) => { 24 addEventListener('message', function handle(event) { 25 if (event.source === win) { 26 resolve(); 27 removeEventListener('message', handle); 28 } 29 }); 30 }) 31 }; 32 33 /** 34 * Prime the UA's session history such that the location of the request is 35 * immediately behind the current entry. Because the location may not be 36 * same-origin with the current browsing context, this must be done via a 37 * true navigation and not, e.g. the `history.pushState` API. The initial 38 * navigation will alter the WPT server's internal state; in order to avoid 39 * false positives, clear that state prior to initiating the second 40 * navigation via `history.back`. 41 */ 42 function induceBackRequest(url, test, clear) { 43 const win = window.open(url); 44 45 test.add_cleanup(() => win.close()); 46 47 return whenDone(win) 48 .then(clear) 49 .then(() => win.history.back()) 50 .then(() => whenDone(win)); 51 } 52 53 /** 54 * Prime the UA's session history such that the location of the request is 55 * immediately ahead of the current entry. Because the location may not be 56 * same-origin with the current browsing context, this must be done via a 57 * true navigation and not, e.g. the `history.pushState` API. The initial 58 * navigation will alter the WPT server's internal state; in order to avoid 59 * false positives, clear that state prior to initiating the second 60 * navigation via `history.forward`. 61 */ 62 function induceForwardRequest(url, test, clear) { 63 const win = window.open(messageOpenerUrl); 64 65 test.add_cleanup(() => win.close()); 66 67 return whenDone(win) 68 .then(() => win.location = url) 69 .then(() => whenDone(win)) 70 .then(clear) 71 .then(() => win.history.go(-2)) 72 .then(() => whenDone(win)) 73 .then(() => win.history.forward()) 74 .then(() => whenDone(win)); 75 } 76 77 const messageOpenerUrl = new URL( 78 '/fetch/metadata/resources/message-opener.html', location 79 ); 80 // For these tests to function, replacement must *not* be enabled during 81 // navigation. Assignment must therefore take place after the document has 82 // completely loaded [1]. This event is not directly observable, but it is 83 // scheduled as a task immediately following the global object's `load` 84 // event [2]. By queuing a task during the dispatch of the `load` event, 85 // navigation can be consistently triggered without replacement. 86 // 87 // [1] https://html.spec.whatwg.org/multipage/history.html#location-object-setter-navigate 88 // [2] https://html.spec.whatwg.org/multipage/parsing.html#the-end 89 const responseParams = { 90 mime: 'text/html', 91 body: `<script> 92 window.addEventListener('load', () => { 93 set`+`Timeout(() => location.assign('${messageOpenerUrl}')); 94 }); 95 <`+`/script>` 96 }; 97 {%- for subtest in subtests %} 98 99 promise_test((t) => { 100 const key = '{{uuid()}}'; 101 const url = makeRequestURL(key, [% subtest.origins %], responseParams); 102 103 return induceBackRequest(url, t, () => retrieve(key)) 104 .then(() => retrieve(key)) 105 .then((headers) => { 106 {%- if subtest.expected == none %} 107 assert_not_own_property(headers, '[%subtest.headerName%]'); 108 {%- else %} 109 assert_own_property(headers, '[%subtest.headerName%]'); 110 assert_array_equals(headers['[%subtest.headerName%]'], ['[%subtest.expected%]']); 111 {%- endif %} 112 }); 113 }, '[%subtest.headerName%] - [%subtest.description | pad("right", " - ")%]history.back[%subtest.api%][% " with user activation" if subtest.userActivated%]'); 114 115 promise_test((t) => { 116 const key = '{{uuid()}}'; 117 const url = makeRequestURL(key, [% subtest.origins %], responseParams); 118 119 return induceForwardRequest(url, t, () => retrieve(key)) 120 .then(() => retrieve(key)) 121 .then((headers) => { 122 {%- if subtest.expected == none %} 123 assert_not_own_property(headers, '[%subtest.headerName%]'); 124 {%- else %} 125 assert_own_property(headers, '[%subtest.headerName%]'); 126 assert_array_equals(headers['[%subtest.headerName%]'], ['[%subtest.expected%]']); 127 {%- endif %} 128 }); 129 }, '[%subtest.headerName%] - [%subtest.description | pad("right", " - ")%]history.forward[%subtest.api%][% " with user activation" if subtest.userActivated%]'); 130 131 {%- endfor %} 132 </script> 133 </body> 134 </html>