promise-job-incumbent.html (5000B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>Incumbent settings object for promise jobs</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 7 <!-- This is the entry page. --> 8 9 <iframe src="resources/promise-job-incumbent-incumbent.html"></iframe> 10 <iframe src="resources/promise-job-incumbent-resolver.html"></iframe> 11 12 <script> 13 setup({ explicit_done: true }); 14 15 // postMessage should pick the incumbent page as its .source value to set on the MessageEvent, even 16 // inside promise jobs. 17 const expectedURL = (new URL("resources/promise-job-incumbent-incumbent.html", location.href)).href; 18 19 let testId = 0; 20 21 window.onload = () => { 22 const relevantWindow = frames[0].document.querySelector("#r").contentWindow; 23 const runInResolver = frames[1].runWhatYouGiveMe; 24 25 function setupTest(t) { 26 ++testId; 27 const thisTestId = testId; 28 29 relevantWindow.addEventListener("messagereceived", t.step_func(e => { 30 const [receivedTestId, receivedSourceURL] = e.detail; 31 32 if (receivedTestId !== thisTestId) { 33 return; 34 } 35 36 assert_equals(receivedSourceURL, expectedURL); 37 t.done(); 38 })); 39 40 return thisTestId; 41 } 42 43 async_test(t => { 44 const thisTestId = setupTest(t); 45 46 frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); 47 }, "Sanity check: this all works as expected with no promises involved"); 48 49 async_test(t => { 50 const thisTestId = setupTest(t); 51 52 // No t.step_func because that could change the realms 53 Promise.resolve().then(() => { 54 frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); 55 }); 56 }, "Fulfillment handler on fulfilled promise"); 57 58 async_test(t => { 59 const thisTestId = setupTest(t); 60 61 const p = Promise.resolve(); 62 frames[0].runWindowPostMessageVeryIndirectlyWithNoUserCode(p, "then", thisTestId, "*"); 63 }, "Fulfillment handler on fulfilled promise, using backup incumbent settings object stack"); 64 65 async_test(t => { 66 const thisTestId = setupTest(t); 67 68 // No t.step_func because that could change the realms 69 Promise.reject().catch(() => { 70 frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); 71 }); 72 }, "Rejection handler on rejected promise"); 73 74 async_test(t => { 75 const thisTestId = setupTest(t); 76 77 const p = Promise.reject(); 78 frames[0].runWindowPostMessageVeryIndirectlyWithNoUserCode(p, "catch", thisTestId, "*"); 79 }, "Rejection handler on rejected promise, using backup incumbent settings object stack"); 80 81 // The following tests test that we derive the incumbent settings object at promise-job time from 82 // the incumbent realm at the time the handler was added, not at the time the resolve()/reject() 83 // was done. See https://github.com/whatwg/html/issues/5213 for the spec side of this issue. 84 85 async_test(t => { 86 const thisTestId = setupTest(t); 87 88 let resolve; 89 const p = new Promise(r => { resolve = r; }); 90 91 // No t.step_func because that could change the realms 92 p.then(() => { 93 frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); 94 }); 95 96 t.step_timeout(() => { 97 runInResolver(resolve); 98 }, 0); 99 }, "Fulfillment handler on pending-then-fulfilled promise"); 100 101 async_test(t => { 102 const thisTestId = setupTest(t); 103 104 let resolve; 105 const p = new Promise(r => { resolve = r; }); 106 107 frames[0].runWindowPostMessageVeryIndirectlyWithNoUserCode(p, "then", thisTestId, "*"); 108 109 t.step_timeout(() => { 110 runInResolver(resolve); 111 }, 0); 112 }, "Fulfillment handler on pending-then-fulfilled promise, using backup incumbent settings object stack"); 113 114 async_test(t => { 115 const thisTestId = setupTest(t); 116 117 let reject; 118 const p = new Promise((_, r) => { reject = r; }); 119 120 // No t.step_func because that could change the realms 121 p.catch(() => { 122 frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); 123 }); 124 125 t.step_timeout(() => { 126 runInResolver(reject); 127 }, 0); 128 }, "Rejection handler on pending-then-rejected promise"); 129 130 async_test(t => { 131 const thisTestId = setupTest(t); 132 133 let reject; 134 const p = new Promise((_, r) => { reject = r; }); 135 136 frames[0].runWindowPostMessageVeryIndirectlyWithNoUserCode(p, "catch", thisTestId, "*"); 137 138 t.step_timeout(() => { 139 runInResolver(reject); 140 }, 0); 141 }, "Rejection handler on pending-then-rejected promise, using backup incumbent settings object stack"); 142 143 async_test(t => { 144 const thisTestId = setupTest(t); 145 146 const thenable = { 147 // No t.step_func because that could change the realms 148 then(f) { 149 frames[0].runWindowPostMessageVeryIndirectly(thisTestId, "*"); 150 } 151 }; 152 153 Promise.resolve(thenable); 154 }, "Thenable resolution"); 155 156 async_test(t => { 157 const thisTestId = setupTest(t); 158 159 frames[0].resolveThenableThatRunsWindowPostMessageVeryIndirectlyWithNoUserCode(testId, "*", []); 160 }, "Thenable resolution, using backup incumbent settings object stack"); 161 162 done(); 163 }; 164 </script>