promise-job-detached-iframe.html (8311B)
1 <!DOCTYPE html> 2 <script src="/resources/testharness.js"></script> 3 <script src="/resources/testharnessreport.js"></script> 4 <body> 5 6 <script> 7 function async_iframe_test(f, name) { 8 async_test(t => { 9 const iframe = document.createElement("iframe"); 10 iframe.src = "resources/empty.html"; 11 document.body.append(iframe); 12 13 iframe.onload = () => { 14 f(t, iframe); 15 }; 16 }, name); 17 } 18 19 async_iframe_test((t, iframe) => { 20 // A promise reaction job is created with the iframe's realm, retrieved 21 // from the onFulfilled callback function. 22 const { p, result } = iframe.contentWindow.eval(` 23 const result = { called: false }; 24 const p = Promise.resolve(1).then(function onFulfilled() { 25 result.called = true; 26 }); 27 ({ p, result }); 28 `); 29 30 // The global becomes not-fully-active before the next microtask checkpoint. 31 iframe.remove(); 32 33 // Verify the result after the next microtask checkpoint. 34 t.step_timeout(() => { 35 assert_equals(result.called, false); 36 t.done(); 37 }, 0); 38 }, "Reaction job should be skipped if onFulfilled handler belongs to detached iframe"); 39 40 async_iframe_test((t, iframe) => { 41 // A promise reaction job is created with the iframe's realm, retrieved 42 // from the onRejected callback function. 43 const { p, result } = iframe.contentWindow.eval(` 44 const result = { called: false }; 45 const p = Promise.reject(1).then(() => {}, function onRejected() { 46 result.called = true; 47 }); 48 ({ p, result }); 49 `); 50 51 // The global becomes not-fully-active before the next microtask checkpoint. 52 iframe.remove(); 53 54 t.step_timeout(() => { 55 assert_equals(result.called, false); 56 t.done(); 57 }, 0); 58 }, "Reaction job should be skipped if onRejected handler belongs to detached iframe"); 59 60 async_iframe_test((t, iframe) => { 61 const p = iframe.contentWindow.eval(`Promise.resolve(1);`); 62 63 iframe.remove(); 64 65 let called = false; 66 67 // A promise reaction job is created with the current realm, retrieved 68 // from the onFulfilled callback function. 69 p.then(function onFulfilled() { 70 called = true; 71 }); 72 73 t.step_timeout(() => { 74 assert_equals(called, true); 75 t.done(); 76 }, 0); 77 }, "Reaction job should not be skipped if onFulfilled handler belongs to fully active global"); 78 79 async_iframe_test((t, iframe) => { 80 const p = iframe.contentWindow.eval(`Promise.reject(1);`); 81 82 iframe.remove(); 83 84 let called = false; 85 86 // A promise reaction job is created with the current realm, retrieved 87 // from the onRejected callback function. 88 p.then(() => {}, function onRejected() { 89 called = true; 90 }); 91 92 t.step_timeout(() => { 93 assert_equals(called, true); 94 t.done(); 95 }, 0); 96 }, "Reaction job should not be skipped if onRejected handler belongs to fully active global"); 97 98 async_iframe_test((t, iframe) => { 99 const p = iframe.contentWindow.eval(`Promise.resolve(1);`); 100 101 iframe.remove(); 102 103 let called = false; 104 105 // A thenable job is created with the iframe's realm, retrieved from p.then 106 // function. 107 const p2 = Promise.resolve(p); 108 109 p2.then(function onFulfilled() { 110 called = true; 111 }); 112 113 t.step_timeout(() => { 114 assert_equals(called, false); 115 t.done(); 116 }, 0); 117 }, "Thenable job for fulfilled promise should be skipped if it belongs to detached iframe"); 118 119 async_iframe_test((t, iframe) => { 120 const p = iframe.contentWindow.eval(`Promise.reject(1);`); 121 122 iframe.remove(); 123 124 let called = false; 125 126 // A thenable job is created with the iframe's realm, retrieved from p.then 127 // function. 128 const p2 = Promise.resolve(p); 129 130 p2.then(() => {}, function onRejected() { 131 called = true; 132 }); 133 134 t.step_timeout(() => { 135 assert_equals(called, false); 136 t.done(); 137 }, 0); 138 }, "Thenable job for rejected promise should be skipped if it belongs to detached iframe"); 139 140 async_iframe_test((t, iframe) => { 141 const p = iframe.contentWindow.eval(`Promise.resolve(1);`); 142 143 iframe.remove(); 144 145 let called = false; 146 147 // In contrast to Promise.resolve, Promise.reject doesn't create a thenable 148 // job. 149 const p2 = Promise.reject(p); 150 151 p2.then(() => {}, function onRejected() { 152 called = true; 153 }); 154 155 t.step_timeout(() => { 156 assert_equals(called, true); 157 t.done(); 158 }, 0); 159 }, "No job with detached iframe's realm should be used for Promise.reject on fulfilled promise"); 160 161 async_iframe_test((t, iframe) => { 162 const p = iframe.contentWindow.eval(`Promise.reject(1);`); 163 164 iframe.remove(); 165 166 let called = false; 167 168 // In contrast to Promise.resolve, Promise.reject doesn't create a thenable 169 // job. 170 const p2 = Promise.reject(p); 171 172 p2.then(() => {}, function onRejected() { 173 called = true; 174 }); 175 176 t.step_timeout(() => { 177 assert_equals(called, true); 178 t.done(); 179 }, 0); 180 }, "No job with detached iframe's realm should be used for Promise.reject on rejected promise"); 181 182 async_iframe_test((t, iframe) => { 183 const p = iframe.contentWindow.eval(`Promise.resolve(1);`); 184 185 iframe.remove(); 186 187 let called = false; 188 189 // Promise.prototype.then resolves the result capability's promise with the 190 // handler's return value, and a thenable job is created with the iframe's 191 // realm, retrieved from p.then function. 192 const p2 = Promise.resolve(1).then(() => p); 193 194 p2.then(function onFulfilled() { 195 called = true; 196 }); 197 198 t.step_timeout(() => { 199 assert_equals(called, false); 200 t.done(); 201 }, 0); 202 }, "Thenable job created by reaction job for fulfillment should be skipped if it belongs to detached iframe"); 203 204 async_iframe_test((t, iframe) => { 205 const p = iframe.contentWindow.eval(`Promise.resolve(1);`); 206 207 iframe.remove(); 208 209 let called = false; 210 211 // Promise.prototype.then resolves the result capability's promise with the 212 // handler's return value, and a thenable job is created with the iframe's 213 // realm, retrieved from p.then function. 214 const p2 = Promise.reject(1).then(() => {}, () => p); 215 216 p2.then(function onFulfilled() { 217 called = true; 218 }); 219 220 t.step_timeout(() => { 221 assert_equals(called, false); 222 t.done(); 223 }, 0); 224 }, "Thenable job created by reaction job for rejection should be skipped if it belongs to detached iframe"); 225 226 async_iframe_test((t, iframe) => { 227 const p = iframe.contentWindow.eval(`Promise.resolve(1);`); 228 229 iframe.remove(); 230 231 let called = false; 232 233 // Promise.all internally performs Promise.resolve, and a thenable job 234 // is created with the iframe's realm, retrieved from p.then function. 235 const p2 = Promise.all([p]); 236 237 p2.then(function onFulfilled() { 238 called = true; 239 }); 240 241 t.step_timeout(() => { 242 assert_equals(called, false); 243 t.done(); 244 }, 0); 245 }, "Thenable job created by Promise.all should be skipped if it belongs to detached iframe"); 246 247 async_iframe_test((t, iframe) => { 248 const p = iframe.contentWindow.eval(`Promise.resolve(1);`); 249 250 iframe.remove(); 251 252 let called = false; 253 254 // Promise.allSettled internally performs Promise.resolve, and a thenable job 255 // is created with the iframe's realm, retrieved from p.then function. 256 const p2 = Promise.allSettled([p]); 257 258 p2.then(function onFulfilled() { 259 called = true; 260 }); 261 262 t.step_timeout(() => { 263 assert_equals(called, false); 264 t.done(); 265 }, 0); 266 }, "Thenable job created by Promise.allSettled should be skipped if it belongs to detached iframe"); 267 268 async_iframe_test((t, iframe) => { 269 const p = iframe.contentWindow.eval(`Promise.resolve(1);`); 270 271 iframe.remove(); 272 273 let called = false; 274 275 // Promise.any internally performs Promise.resolve, and a thenable job 276 // is created with the iframe's realm, retrieved from p.then function. 277 const p2 = Promise.any([p]); 278 279 p2.then(function onFulfilled() { 280 called = true; 281 }); 282 283 t.step_timeout(() => { 284 assert_equals(called, false); 285 t.done(); 286 }, 0); 287 }, "Thenable job created by Promise.any should be skipped if it belongs to detached iframe"); 288 289 async_iframe_test((t, iframe) => { 290 const p = iframe.contentWindow.eval(`Promise.resolve(1);`); 291 292 iframe.remove(); 293 294 let called = false; 295 296 // Promise.race internally performs Promise.resolve, and a thenable job 297 // is created with the iframe's realm, retrieved from p.then function. 298 const p2 = Promise.race([p]); 299 300 p2.then(function onFulfilled() { 301 called = true; 302 }); 303 304 t.step_timeout(() => { 305 assert_equals(called, false); 306 t.done(); 307 }, 0); 308 }, "Thenable job created by Promise.race should be skipped if it belongs to detached iframe"); 309 </script> 310 </body>