Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /xhr/abort-progress-events.any.html - WPT Dashboard Interop Dashboard
- /xhr/abort-progress-events.any.worker.html - WPT Dashboard Interop Dashboard
// META: title=XMLHttpRequest: abort() and progress timer race condition
// Ensures that readystatechange and progress events don't fire when the
// state is UNSENT, as required by the spec.
async_test(t => {
const xhr = new XMLHttpRequest();
let eventsFiredInUnsent = false;
// Monitor for events firing in UNSENT state
xhr.addEventListener('readystatechange', t.step_func(() => {
if (xhr.readyState === XMLHttpRequest.UNSENT) {
eventsFiredInUnsent = true;
}
}));
xhr.addEventListener('progress', t.step_func(() => {
if (xhr.readyState === XMLHttpRequest.UNSENT) {
eventsFiredInUnsent = true;
}
}));
// Start a request and immediately abort it
xhr.open('GET', 'resources/pass.txt');
xhr.send();
xhr.abort();
// The spec says when abort() is called on a DONE request, state changes
// to UNSENT and no readystatechange event is dispatched. Progress events
// should also not fire in UNSENT state.
assert_equals(xhr.readyState, XMLHttpRequest.UNSENT,
'State should be UNSENT immediately after abort');
// Give time for any progress timer callbacks that might have been queued
t.step_timeout(() => {
assert_false(eventsFiredInUnsent,
'No events should fire when state is UNSENT');
t.done();
}, 200);
}, 'Events must not fire when state is UNSENT after abort()');
async_test(t => {
const xhr = new XMLHttpRequest();
let callCount = 0;
// Calling open/abort in a readystatechange handler can trigger
// a scenario where the progress timer callback is queued but then
// the state becomes UNSENT. This should not cause assertions or crashes.
xhr.addEventListener('readystatechange', t.step_func(e => {
// Limit recursion to prevent infinite loop
if (callCount++ < 5) {
e.currentTarget.open('GET', 'resources/pass.txt');
e.currentTarget.abort();
}
}));
xhr.open('GET', 'resources/pass.txt');
xhr.send();
// Allow time for the test to complete
t.step_timeout(() => {
assert_true(callCount > 0, 'readystatechange handler should have been called');
t.done();
}, 200);
}, 'Calling open/abort in readystatechange should not crash');