history-length-fenced-navigations-replace-do-not-contribute-to-joint-inner.html (4773B)
1 <!DOCTYPE html> 2 <script src="/resources/testharness.js"></script> 3 <script src="utils.js"></script> 4 <title>Nested fenced frame named navigation helper</title> 5 6 <body> 7 <script> 8 (async () => { 9 // We need to wait for the window's `load` event to fire, because client-side 10 // redirect navigations that take place before a document is "completely 11 // loaded" [1] are carried out with replacement, as specified in [2]. Just 12 // waiting for `load` is not enough though! After the `load` event is fired 13 // (but before a document is marked "completely loaded"), a microtask 14 // checkpoint is performed, which is where the below `Promise`'s `then` 15 // handler is invoked (i.e., the rest of the script). So if we just resolve 16 // the promise and continue, the whole script continues in the next immediate 17 // microtask before the document is completely loaded. So we have to queue 18 // another task so that we only continue executing once the document is 19 // considered completely loaded, and then `location.href` assignments will not 20 // be made with replacement history handling. 21 // 22 // [1]: https://html.spec.whatwg.org/C#the-end:completely-finish-loading 23 // [2]: https://html.spec.whatwg.org/#the-location-interface:completely-loaded 24 await new Promise(resolve => { 25 window.onload = e => { 26 setTimeout(resolve, 0); 27 }; 28 }); 29 30 const kNavigationLimit = 5; 31 // This is a helper file meant to be loaded inside a fenced frame. It performs 32 // various navigations inside of the "fence" defined by this document, and 33 // ensures that they are all done in a replace-only fashion [1]. 34 // Once we ensure that they are all done with replacement, we report back to 35 // the outermost page via the server stash, and it ensures that there was no 36 // impact on the joint session history as observed from beyond the fence. 37 // 38 // [1]: https://html.spec.whatwg.org/C/#hh-replace 39 40 // See documentation in the outer page. 41 const [fenced_navigation_complete_key, 42 outer_page_ready_for_next_fenced_navigation_key, 43 level] = parseKeylist(); 44 45 const url = new URL(location.href); 46 const is_top_level_fenced_frame = (level == "top-level-fenced-frame"); 47 48 ////////////// Navigation code that may impact `history.length` should go here 49 // The code in this block performs navigations that will run inside: 50 // - The top-level fenced frame 51 // - The nested fenced frame 52 // - The nested iframe 53 54 // First, perform some real navigations to this same page. Normally this would 55 // increase `history.length`. 56 if (url.searchParams.get("navigationNumber") == null) 57 url.searchParams.append("navigationNumber", 0); 58 59 let navigationNumber = parseInt(url.searchParams.get("navigationNumber")); 60 61 if (navigationNumber <= kNavigationLimit) { 62 url.searchParams.set('navigationNumber', navigationNumber + 1); 63 location.href = url; 64 return; 65 } 66 67 // At this point we're done performing 5 subsequent navigations... 68 69 // Next, perform `history.pushState()`s. 70 history.pushState({} , ""); 71 history.pushState({} , ""); 72 history.pushState({} , ""); 73 ////////////// END 74 75 // Finally observe `history.length` from within the fenced frame, and report 76 // the results back to the outermost page. 77 if (history.length == 1) { 78 writeValueToServer(fenced_navigation_complete_key, "PASS > " + 79 level); 80 } else { 81 writeValueToServer(fenced_navigation_complete_key, 82 "FAIL > " + level + " history.length: " + 83 history.length); 84 } 85 86 // We're only testing fenced frames, nested fenced frames, and iframes nested 87 // within fenced frames. The below code adds a nested fenced frame and a 88 // nested iframe, so it should only be reached by the top-level fenced frame. 89 if (level != "top-level-fenced-frame") 90 return; 91 92 // Only top-level fenced frames will attach a nested fenced frame and run the 93 // same tests there. 94 await nextValueFromServer(outer_page_ready_for_next_fenced_navigation_key); 95 const nested_fenced_frame_level = "nested-fenced-frame"; 96 attachFencedFrame(generateURL( 97 "history-length-fenced-navigations-replace-do-not-" + 98 "contribute-to-joint-inner.html", 99 [fenced_navigation_complete_key, 100 outer_page_ready_for_next_fenced_navigation_key, 101 nested_fenced_frame_level])); 102 103 await nextValueFromServer(outer_page_ready_for_next_fenced_navigation_key); 104 const iframe = document.createElement('iframe'); 105 const nested_iframe_level = "nested-iframe"; 106 iframe.src = generateURL( 107 "history-length-fenced-navigations-replace-do-not-contribute-to-joint-" + 108 "inner.html", 109 [fenced_navigation_complete_key, 110 outer_page_ready_for_next_fenced_navigation_key, 111 nested_iframe_level]); 112 document.body.append(iframe); 113 })(); 114 </script> 115 </body>