Skip to content

Commit

Permalink
Bug 1783602 [wpt PR 35374] - Fetch: Add tests for AbortSignal's abort…
Browse files Browse the repository at this point in the history
… reason, a=testonly

Automatic update from web-platform-tests
Fetch: Add tests for AbortSignal's abort reason (#35374)

Add test cases to check the functionality of AbortSignal's abort reason when aborting fetch, including serialization and that the service worker can observe the reason.

See whatwg/fetch#1343 for accompanying spec changes.
--

wpt-commits: 0e5f85c08e05fb1b9b67fb12c4d7c0de77a4ee9b
wpt-pr: 35374
  • Loading branch information
nidhijaju authored and moz-wptsync-bot committed Oct 21, 2022
1 parent 2ed8f80 commit 77de3ed
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 5 deletions.
29 changes: 29 additions & 0 deletions testing/web-platform/tests/fetch/api/abort/general.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

const BODY_METHODS = ['arrayBuffer', 'blob', 'formData', 'json', 'text'];

const error1 = new Error('error1');
error1.name = 'error1';

// This is used to close connections that weren't correctly closed during the tests,
// otherwise you can end up running out of HTTP connections.
let requestAbortKeys = [];
Expand All @@ -31,6 +34,16 @@ promise_test(async t => {
await promise_rejects_dom(t, "AbortError", fetchPromise);
}, "Aborting rejects with AbortError");

promise_test(async t => {
const controller = new AbortController();
const signal = controller.signal;
controller.abort(error1);

const fetchPromise = fetch('../resources/data.json', { signal });

await promise_rejects_exactly(t, error1, fetchPromise, 'fetch() should reject with abort reason');
}, "Aborting rejects with abort reason");

promise_test(async t => {
const controller = new AbortController();
const signal = controller.signal;
Expand Down Expand Up @@ -91,6 +104,22 @@ promise_test(async t => {
await promise_rejects_dom(t, "AbortError", fetchPromise);
}, "Signal on request object");

promise_test(async t => {
const controller = new AbortController();
const signal = controller.signal;
controller.abort(error1);

const request = new Request('../resources/data.json', { signal });

assert_not_equals(request.signal, signal, 'Request has a new signal, not a reference');
assert_true(request.signal.aborted, `Request's signal has aborted`);
assert_equals(request.signal.reason, error1, `Request's signal's abort reason is error1`);

const fetchPromise = fetch(request);

await promise_rejects_exactly(t, error1, fetchPromise, "fetch() should reject with abort reason");
}, "Signal on request object should also have abort reason");

promise_test(async t => {
const controller = new AbortController();
const signal = controller.signal;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
const SCOPE = '../resources/basic.html';
const BODY_METHODS = ['arrayBuffer', 'blob', 'formData', 'json', 'text'];

async function setupRegistration(t, scope) {
const reg = await navigator.serviceWorker.register('../resources/sw-intercept.js', { scope });
const error1 = new Error('error1');
error1.name = 'error1';

async function setupRegistration(t, scope, service_worker) {
const reg = await navigator.serviceWorker.register(service_worker, { scope });
await wait_for_state(t, reg.installing, 'activated');
add_completion_callback(_ => reg.unregister());
return reg;
Expand All @@ -23,7 +26,7 @@
promise_test(async t => {
const suffix = "?q=aborted-not-intercepted";
const scope = SCOPE + suffix;
await setupRegistration(t, scope);
await setupRegistration(t, scope, '../resources/sw-intercept.js');
const iframe = await with_iframe(scope);
add_completion_callback(_ => iframe.remove());
const w = iframe.contentWindow;
Expand Down Expand Up @@ -56,7 +59,7 @@
for (const bodyMethod of BODY_METHODS) {
promise_test(async t => {
const scope = SCOPE + "?q=aborted-" + bodyMethod + "-rejects";
await setupRegistration(t, scope);
await setupRegistration(t, scope, '../resources/sw-intercept.js');
const iframe = await with_iframe(scope);
add_completion_callback(_ => iframe.remove());
const w = iframe.contentWindow;
Expand Down Expand Up @@ -84,7 +87,7 @@

promise_test(async t => {
const scope = SCOPE + "?q=aborted-stream-errors";
await setupRegistration(t, scope);
await setupRegistration(t, scope, '../resources/sw-intercept.js');
const iframe = await with_iframe(scope);
add_completion_callback(_ => iframe.remove());
const w = iframe.contentWindow;
Expand All @@ -100,6 +103,92 @@
await promise_rejects_dom(t, "AbortError", w.DOMException, reader.read());
await promise_rejects_dom(t, "AbortError", w.DOMException, reader.closed);
}, "Stream errors once aborted.");

promise_test(async t => {
const scope = SCOPE + "?q=aborted-with-abort-reason";
await setupRegistration(t, scope, '../resources/sw-intercept.js');
const iframe = await with_iframe(scope);
add_completion_callback(_ => iframe.remove());
const w = iframe.contentWindow;

const controller = new w.AbortController();
const signal = controller.signal;

const fetchPromise = await w.fetch('data.json', { signal });

controller.abort(error1);

await promise_rejects_exactly(t, error1, fetchPromise);
}, "fetch() rejects with abort reason");

promise_test(async t => {
const scope = SCOPE + "?q=service-worker-observes-abort-reason";
await setupRegistration(t, scope, '../resources/sw-intercept-abort.js');
const iframe = await with_iframe(scope);
add_completion_callback(_ => iframe.remove());
const w = iframe.contentWindow;

const controller = new w.AbortController();
const signal = controller.signal;

const fetchPromise = w.fetch('data.json', { signal });

await new Promise(resolve => {
w.navigator.serviceWorker.addEventListener('message', t.step_func(event => {
assert_equals(event.data, "fetch event has arrived");
resolve();
}), {once: true});
});

controller.abort(error1);

await new Promise(resolve => {
w.navigator.serviceWorker.addEventListener('message', t.step_func(event => {
assert_equals(event.data.message, error1.message);
resolve();
}), {once: true});
});

await promise_rejects_exactly(t, error1, fetchPromise);
}, "Service Worker can observe the fetch abort and associated abort reason");

promise_test(async t => {
let incrementing_error = new Error('error1');
incrementing_error.name = 'error1';

const scope = SCOPE + "?q=serialization-on-abort";
await setupRegistration(t, scope, '../resources/sw-intercept-abort.js');
const iframe = await with_iframe(scope);
add_completion_callback(_ => iframe.remove());
const w = iframe.contentWindow;

const controller = new w.AbortController();
const signal = controller.signal;

const fetchPromise = w.fetch('data.json', { signal });

await new Promise(resolve => {
w.navigator.serviceWorker.addEventListener('message', t.step_func(event => {
assert_equals(event.data, "fetch event has arrived");
resolve();
}), {once: true});
});

controller.abort(incrementing_error);

const original_error_name = incrementing_error.name;

incrementing_error.name = 'error2';

await new Promise(resolve => {
w.navigator.serviceWorker.addEventListener('message', t.step_func(event => {
assert_equals(event.data.name, original_error_name);
resolve();
}), {once: true});
});

await promise_rejects_exactly(t, incrementing_error, fetchPromise);
}, "Abort reason serialization happens on abort");
</script>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
async function messageClient(clientId, message) {
const client = await clients.get(clientId);
client.postMessage(message);
}

addEventListener('fetch', event => {
let resolve;
const promise = new Promise(r => resolve = r);

function onAborted() {
messageClient(event.clientId, event.request.signal.reason);
resolve();
}

messageClient(event.clientId, 'fetch event has arrived');

event.respondWith(promise.then(() => new Response('hello')));
event.request.signal.addEventListener('abort', onAborted);
});

0 comments on commit 77de3ed

Please sign in to comment.