Files
SeungJun Lee 3dc16aff5e Bug 2068951 [wpt PR 62349] - FileReader: Suppress stale loadend after reentrant read, a=testonly
Automatic update from web-platform-tests
FileReader: Suppress stale loadend after reentrant read

Do not fire loadend for a completed, aborted, or failed read when its terminal event handler starts a new read on the same FileReader.

Add regression coverage for reentrant reads from abort, load, and error handlers.

Bug: 40763894
Change-Id: Ie51c5c9652f85e3feaeccc5f9591ddea35f72801
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8300812
Reviewed-by: Rakina Zata Amni <rakina@chromium.org>
Commit-Queue: Amos Lim <amoseui@chromium.org>
Reviewed-by: Fergal Daly <fergal@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1690598}

--

wpt-commits: 666797a05cd728e328bc2161fe58a46ad11bfcb8
wpt-pr: 62349
2026-09-10 11:29:01 +00:00

145 lines
4.9 KiB
JavaScript

// META: title=FileReader: starting new reads while one is in progress
test(function() {
var blob_1 = new Blob(['TEST000000001'])
var blob_2 = new Blob(['TEST000000002'])
var reader = new FileReader();
reader.readAsText(blob_1)
assert_equals(reader.readyState, FileReader.LOADING, "readyState Must be LOADING")
assert_throws_dom("InvalidStateError", function () {
reader.readAsText(blob_2)
})
}, 'test FileReader InvalidStateError exception for readAsText');
test(function() {
var blob_1 = new Blob(['TEST000000001'])
var blob_2 = new Blob(['TEST000000002'])
var reader = new FileReader();
reader.readAsDataURL(blob_1)
assert_equals(reader.readyState, FileReader.LOADING, "readyState Must be LOADING")
assert_throws_dom("InvalidStateError", function () {
reader.readAsDataURL(blob_2)
})
}, 'test FileReader InvalidStateError exception for readAsDataURL');
test(function() {
var blob_1 = new Blob(['TEST000000001'])
var blob_2 = new Blob(['TEST000000002'])
var reader = new FileReader();
reader.readAsArrayBuffer(blob_1)
assert_equals(reader.readyState, FileReader.LOADING, "readyState Must be LOADING")
assert_throws_dom("InvalidStateError", function () {
reader.readAsArrayBuffer(blob_2)
})
}, 'test FileReader InvalidStateError exception for readAsArrayBuffer');
async_test(function() {
var blob_1 = new Blob(['TEST000000001'])
var blob_2 = new Blob(['TEST000000002'])
var reader = new FileReader();
var triggered = false;
reader.onloadstart = this.step_func_done(function() {
assert_false(triggered, "Only one loadstart event should be dispatched");
triggered = true;
assert_equals(reader.readyState, FileReader.LOADING,
"readyState must be LOADING")
assert_throws_dom("InvalidStateError", function () {
reader.readAsArrayBuffer(blob_2)
})
});
reader.readAsArrayBuffer(blob_1)
assert_equals(reader.readyState, FileReader.LOADING, "readyState Must be LOADING")
}, 'test FileReader InvalidStateError exception in onloadstart event for readAsArrayBuffer');
async_test(function() {
var blob_1 = new Blob(['TEST000000001'])
var blob_2 = new Blob(['TEST000000002'])
var reader = new FileReader();
reader.onloadend = this.step_func_done(function() {
assert_equals(reader.readyState, FileReader.DONE,
"readyState must be DONE")
reader.readAsArrayBuffer(blob_2)
assert_equals(reader.readyState, FileReader.LOADING, "readyState Must be LOADING")
});
reader.readAsArrayBuffer(blob_1)
assert_equals(reader.readyState, FileReader.LOADING, "readyState Must be LOADING")
}, 'test FileReader no InvalidStateError exception in loadend event handler for readAsArrayBuffer');
async_test(function() {
var blob_1 = new Blob([new Uint8Array(0x414141)]);
var blob_2 = new Blob(['TEST000000002']);
var reader = new FileReader();
reader.onloadstart = this.step_func(function() {
reader.abort();
reader.onloadstart = null;
reader.onloadend = this.step_func_done(function() {
assert_equals('TEST000000002', reader.result);
});
reader.readAsText(blob_2);
});
reader.readAsText(blob_1);
}, 'test abort and restart in onloadstart event for readAsText');
promise_test(async t => {
const reader = new FileReader();
const events = [];
for (const type of ['abort', 'load', 'loadend']) {
reader.addEventListener(type, () => events.push(type));
}
reader.addEventListener('error', t.unreached_func('Unexpected error event'));
reader.addEventListener('abort', t.step_func(() => {
reader.readAsText(new Blob(['second']));
}),
{once: true});
const firstLoadstart = new Promise(resolve => {
reader.addEventListener('loadstart', resolve, {once: true});
});
const secondLoadend = new Promise(resolve => {
reader.addEventListener('loadend', t.step_func(() => {
if (reader.result === 'second') {
resolve();
}
}));
});
reader.readAsText(new Blob([new Uint8Array(1024 * 1024)]));
await firstLoadstart;
reader.abort();
await secondLoadend;
assert_array_equals(events, ['abort', 'load', 'loadend']);
}, 'A new read in an abort handler suppresses the old read loadend');
promise_test(async t => {
const reader = new FileReader();
const events = [];
let load_count = 0;
for (const type of ['load', 'loadend']) {
reader.addEventListener(type, () => events.push(type));
}
reader.addEventListener('error', t.unreached_func('Unexpected error event'));
reader.addEventListener('load', t.step_func(() => {
if (++load_count === 1) {
reader.readAsText(new Blob(['second']));
}
}));
const secondLoadend = new Promise(resolve => {
reader.addEventListener('loadend', t.step_func(() => {
if (reader.result === 'second') {
resolve();
}
}));
});
reader.readAsText(new Blob(['first']));
await secondLoadend;
assert_array_equals(events, ['load', 'load', 'loadend']);
}, 'A new read in a load handler suppresses the old read loadend');