web-platform-test-shims.js (2693B)
1 // This is used when jstests.py runs web-platform-tests in the shell. 2 // Some tests require browser features that the shell doesn't have built-in. 3 4 // window.self 5 // <https://html.spec.whatwg.org/multipage/window-object.html#dom-self> 6 if (!("self" in this)) { 7 this.self = this; 8 } 9 10 // window.setTimeout, clearTimeout, setInterval, clearInterval 11 // <https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#dom-settimeout> 12 if (!("setTimeout" in this)) { 13 // Not-very-compliant polyfill for setTimeout, based on Promise. 14 15 // When this array becomes non-empty, call scheduleWork. 16 let timeouts = []; 17 18 // Fake clock used to order timeouts. 19 let now = 0; 20 21 // Least positive integer not yet used as a timer id. 22 let next_id = 1; 23 24 // Add an active timer record to timeouts. 25 function enqueue(id, t, cb) { 26 if (typeof cb !== 'function') { 27 let code = "" + cb; 28 cb = () => eval(code); 29 } 30 t += now; 31 timeouts.push({id, t, cb}); 32 timeouts.sort((a, b) => a.t - b.t); 33 if (timeouts.length === 1) { 34 scheduleWork(); 35 } 36 } 37 38 // Register a microtask to make sure timers are actually processed. There 39 // should be at most one of these microtasks pending at a time. 40 function scheduleWork() { 41 // Number of times to let the microtask queue spin before running a 42 // timeout. The idea is to let all Promises resolve between consecutive 43 // timer callbacks. Of course, this is a hack; whatever number is used 44 // here, an async function can simply await that many times plus one to 45 // observe that timeouts are being handled as microtasks, not events. 46 let delay = 10; 47 48 function handleTimeouts() { 49 if (--delay > 0) { 50 Promise.resolve().then(handleTimeouts); 51 return; 52 } 53 if (timeouts.length > 0) { 54 let {t, cb} = timeouts.shift(); 55 if (now < t) { 56 now = t; 57 } 58 if (timeouts.length > 0) { 59 scheduleWork(); // There's more to do after this. 60 } 61 cb(); 62 } 63 } 64 Promise.resolve().then(handleTimeouts); 65 } 66 67 this.setTimeout = function (cb, t, ...args) { 68 let id = next_id++; 69 enqueue(id, t, () => cb(...args)); 70 return id; 71 }; 72 73 this.clearTimeout = function (id) { 74 timeouts = timeouts.filter(obj => obj.id !== id); 75 }; 76 77 this.setInterval = function (cb, t, ...args) { 78 let id = next_id++; 79 let func = () => { 80 enqueue(id, t, func); 81 cb(...args); 82 }; 83 enqueue(id, t, func); 84 return id; 85 }; 86 87 this.clearInterval = this.clearTimeout; 88 } 89 90 // Some tests in web platform tests leave promise rejections unhandled. 91 if ("ignoreUnhandledRejections" in this) { 92 ignoreUnhandledRejections(); 93 }