diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js')
-rw-r--r-- | testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js b/testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js new file mode 100644 index 0000000000..8a975b0d2e --- /dev/null +++ b/testing/web-platform/tests/service-workers/service-worker/resources/extendable-event-async-waituntil.js @@ -0,0 +1,210 @@ +// This worker calls waitUntil() and respondWith() asynchronously and +// reports back to the test whether they threw. +// +// These test cases are confusing. Bear in mind that the event is active +// (calling waitUntil() is allowed) if: +// * The pending promise count is not 0, or +// * The event dispatch flag is set. + +// Controlled by 'init'/'done' messages. +var resolveLockPromise; +var port; + +self.addEventListener('message', function(event) { + var waitPromise; + var resolveTestPromise; + + switch (event.data.step) { + case 'init': + event.waitUntil(new Promise((res) => { resolveLockPromise = res; })); + port = event.data.port; + break; + case 'done': + resolveLockPromise(); + break; + + // Throws because waitUntil() is called in a task after event dispatch + // finishes. + case 'no-current-extension-different-task': + async_task_waituntil(event).then(reportResultExpecting('InvalidStateError')); + break; + + // OK because waitUntil() is called in a microtask that runs after the + // event handler runs, while the event dispatch flag is still set. + case 'no-current-extension-different-microtask': + async_microtask_waituntil(event).then(reportResultExpecting('OK')); + break; + + // OK because the second waitUntil() is called while the first waitUntil() + // promise is still pending. + case 'current-extension-different-task': + event.waitUntil(new Promise((res) => { resolveTestPromise = res; })); + async_task_waituntil(event).then(reportResultExpecting('OK')).then(resolveTestPromise); + break; + + // OK because all promises involved resolve "immediately", so the second + // waitUntil() is called during the microtask checkpoint at the end of + // event dispatching, when the event dispatch flag is still set. + case 'during-event-dispatch-current-extension-expired-same-microtask-turn': + waitPromise = Promise.resolve(); + event.waitUntil(waitPromise); + waitPromise.then(() => { return sync_waituntil(event); }) + .then(reportResultExpecting('OK')) + break; + + // OK for the same reason as above. + case 'during-event-dispatch-current-extension-expired-same-microtask-turn-extra': + waitPromise = Promise.resolve(); + event.waitUntil(waitPromise); + waitPromise.then(() => { return async_microtask_waituntil(event); }) + .then(reportResultExpecting('OK')) + break; + + + // OK because the pending promise count is decremented in a microtask + // queued upon fulfillment of the first waitUntil() promise, so the second + // waitUntil() is called while the pending promise count is still + // positive. + case 'after-event-dispatch-current-extension-expired-same-microtask-turn': + waitPromise = makeNewTaskPromise(); + event.waitUntil(waitPromise); + waitPromise.then(() => { return sync_waituntil(event); }) + .then(reportResultExpecting('OK')) + break; + + // Throws because the second waitUntil() is called after the pending + // promise count was decremented to 0. + case 'after-event-dispatch-current-extension-expired-same-microtask-turn-extra': + waitPromise = makeNewTaskPromise(); + event.waitUntil(waitPromise); + waitPromise.then(() => { return async_microtask_waituntil(event); }) + .then(reportResultExpecting('InvalidStateError')) + break; + + // Throws because the second waitUntil() is called in a new task, after + // first waitUntil() promise settled and the event dispatch flag is unset. + case 'current-extension-expired-different-task': + event.waitUntil(Promise.resolve()); + async_task_waituntil(event).then(reportResultExpecting('InvalidStateError')); + break; + + case 'script-extendable-event': + self.dispatchEvent(new ExtendableEvent('nontrustedevent')); + break; + } + + event.source.postMessage('ACK'); + }); + +self.addEventListener('fetch', function(event) { + const path = new URL(event.request.url).pathname; + const step = path.substring(path.lastIndexOf('/') + 1); + let response; + switch (step) { + // OK because waitUntil() is called while the respondWith() promise is still + // unsettled, so the pending promise count is positive. + case 'pending-respondwith-async-waituntil': + var resolveFetch; + response = new Promise((res) => { resolveFetch = res; }); + event.respondWith(response); + async_task_waituntil(event) + .then(reportResultExpecting('OK')) + .then(() => { resolveFetch(new Response('OK')); }); + break; + + // OK because all promises involved resolve "immediately", so waitUntil() is + // called during the microtask checkpoint at the end of event dispatching, + // when the event dispatch flag is still set. + case 'during-event-dispatch-respondwith-microtask-sync-waituntil': + response = Promise.resolve(new Response('RESP')); + event.respondWith(response); + response.then(() => { return sync_waituntil(event); }) + .then(reportResultExpecting('OK')); + break; + + // OK because all promises involved resolve "immediately", so waitUntil() is + // called during the microtask checkpoint at the end of event dispatching, + // when the event dispatch flag is still set. + case 'during-event-dispatch-respondwith-microtask-async-waituntil': + response = Promise.resolve(new Response('RESP')); + event.respondWith(response); + response.then(() => { return async_microtask_waituntil(event); }) + .then(reportResultExpecting('OK')); + break; + + // OK because the pending promise count is decremented in a microtask queued + // upon fulfillment of the respondWith() promise, so waitUntil() is called + // while the pending promise count is still positive. + case 'after-event-dispatch-respondwith-microtask-sync-waituntil': + response = makeNewTaskPromise().then(() => {return new Response('RESP');}); + event.respondWith(response); + response.then(() => { return sync_waituntil(event); }) + .then(reportResultExpecting('OK')); + break; + + + // Throws because waitUntil() is called after the pending promise count was + // decremented to 0. + case 'after-event-dispatch-respondwith-microtask-async-waituntil': + response = makeNewTaskPromise().then(() => {return new Response('RESP');}); + event.respondWith(response); + response.then(() => { return async_microtask_waituntil(event); }) + .then(reportResultExpecting('InvalidStateError')) + break; + } +}); + +self.addEventListener('nontrustedevent', function(event) { + sync_waituntil(event).then(reportResultExpecting('InvalidStateError')); + }); + +function reportResultExpecting(expectedResult) { + return function (result) { + port.postMessage({result : result, expected: expectedResult}); + return result; + }; +} + +function sync_waituntil(event) { + return new Promise((res, rej) => { + try { + event.waitUntil(Promise.resolve()); + res('OK'); + } catch (error) { + res(error.name); + } + }); +} + +function async_microtask_waituntil(event) { + return new Promise((res, rej) => { + Promise.resolve().then(() => { + try { + event.waitUntil(Promise.resolve()); + res('OK'); + } catch (error) { + res(error.name); + } + }); + }); +} + +function async_task_waituntil(event) { + return new Promise((res, rej) => { + setTimeout(() => { + try { + event.waitUntil(Promise.resolve()); + res('OK'); + } catch (error) { + res(error.name); + } + }, 0); + }); +} + +// Returns a promise that settles in a separate task. +function makeNewTaskPromise() { + return new Promise(resolve => { + setTimeout(resolve, 0); + }); +} |