Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /streams/readable-streams/bad-underlying-sources.any.html - WPT Dashboard Interop Dashboard
- /streams/readable-streams/bad-underlying-sources.any.serviceworker.html - WPT Dashboard Interop Dashboard
- /streams/readable-streams/bad-underlying-sources.any.shadowrealm-in-dedicatedworker.html - WPT Dashboard Interop Dashboard
- /streams/readable-streams/bad-underlying-sources.any.shadowrealm-in-shadowrealm.html - WPT Dashboard Interop Dashboard
- /streams/readable-streams/bad-underlying-sources.any.shadowrealm-in-sharedworker.html - WPT Dashboard Interop Dashboard
- /streams/readable-streams/bad-underlying-sources.any.shadowrealm-in-window.html - WPT Dashboard Interop Dashboard
- /streams/readable-streams/bad-underlying-sources.any.sharedworker.html - WPT Dashboard Interop Dashboard
- /streams/readable-streams/bad-underlying-sources.any.worker.html - WPT Dashboard Interop Dashboard
- /streams/readable-streams/bad-underlying-sources.https.any.shadowrealm-in-audioworklet.html - WPT Dashboard Interop Dashboard
- /streams/readable-streams/bad-underlying-sources.https.any.shadowrealm-in-serviceworker.html - WPT Dashboard Interop Dashboard
// META: global=window,worker,shadowrealm
'use strict';
test(() => {
const theError = new Error('a unique string');
assert_throws_exactly(theError, () => {
new ReadableStream({
get start() {
throw theError;
}
});
}, 'constructing the stream should re-throw the error');
}, 'Underlying source start: throwing getter');
test(() => {
const theError = new Error('a unique string');
assert_throws_exactly(theError, () => {
new ReadableStream({
start() {
throw theError;
}
});
}, 'constructing the stream should re-throw the error');
}, 'Underlying source start: throwing method');
test(() => {
const theError = new Error('a unique string');
assert_throws_exactly(theError, () => new ReadableStream({
get pull() {
throw theError;
}
}), 'constructor should throw');
}, 'Underlying source: throwing pull getter (initial pull)');
promise_test(t => {
const theError = new Error('a unique string');
const rs = new ReadableStream({
pull() {
throw theError;
}
});
return promise_rejects_exactly(t, theError, rs.getReader().closed);
}, 'Underlying source: throwing pull method (initial pull)');
promise_test(t => {
const theError = new Error('a unique string');
let counter = 0;
const rs = new ReadableStream({
get pull() {
++counter;
if (counter === 1) {
return c => c.enqueue('a');
}
throw theError;
}
});
const reader = rs.getReader();
return Promise.all([
reader.read().then(r => {
assert_object_equals(r, { value: 'a', done: false }, 'the first chunk read should be correct');
}),
reader.read().then(r => {
assert_object_equals(r, { value: 'a', done: false }, 'the second chunk read should be correct');
assert_equals(counter, 1, 'counter should be 1');
})
]);
}, 'Underlying source pull: throwing getter (second pull does not result in a second get)');
promise_test(t => {
const theError = new Error('a unique string');
let counter = 0;
const rs = new ReadableStream({
pull(c) {
++counter;
if (counter === 1) {
c.enqueue('a');
return;
}
throw theError;
}
});
const reader = rs.getReader();
return Promise.all([
reader.read().then(r => {
assert_object_equals(r, { value: 'a', done: false }, 'the chunk read should be correct');
}),
promise_rejects_exactly(t, theError, reader.closed)
]);
}, 'Underlying source pull: throwing method (second pull)');
test(() => {
const theError = new Error('a unique string');
assert_throws_exactly(theError, () => new ReadableStream({
get cancel() {
throw theError;
}
}), 'constructor should throw');
}, 'Underlying source cancel: throwing getter');
promise_test(t => {
const theError = new Error('a unique string');
const rs = new ReadableStream({
cancel() {
throw theError;
}
});
return promise_rejects_exactly(t, theError, rs.cancel());
}, 'Underlying source cancel: throwing method');
promise_test(() => {
let controller;
const rs = new ReadableStream({
start(c) {
controller = c;
}
});
rs.cancel();
assert_throws_js(TypeError, () => controller.enqueue('a'), 'Calling enqueue after canceling should throw');
return rs.getReader().closed;
}, 'Underlying source: calling enqueue on an empty canceled stream should throw');
promise_test(() => {
let controller;
const rs = new ReadableStream({
start(c) {
c.enqueue('a');
c.enqueue('b');
controller = c;
}
});
rs.cancel();
assert_throws_js(TypeError, () => controller.enqueue('c'), 'Calling enqueue after canceling should throw');
return rs.getReader().closed;
}, 'Underlying source: calling enqueue on a non-empty canceled stream should throw');
promise_test(() => {
return new ReadableStream({
start(c) {
c.close();
assert_throws_js(TypeError, () => c.enqueue('a'), 'call to enqueue should throw a TypeError');
}
}).getReader().closed;
}, 'Underlying source: calling enqueue on a closed stream should throw');
promise_test(t => {
const theError = new Error('boo');
const closed = new ReadableStream({
start(c) {
c.error(theError);
assert_throws_js(TypeError, () => c.enqueue('a'), 'call to enqueue should throw the error');
}
}).getReader().closed;
return promise_rejects_exactly(t, theError, closed);
}, 'Underlying source: calling enqueue on an errored stream should throw');
promise_test(() => {
return new ReadableStream({
start(c) {
c.close();
assert_throws_js(TypeError, () => c.close(), 'second call to close should throw a TypeError');
}
}).getReader().closed;
}, 'Underlying source: calling close twice on an empty stream should throw the second time');
promise_test(() => {
let startCalled = false;
let readCalled = false;
const reader = new ReadableStream({
start(c) {
c.enqueue('a');
c.close();
assert_throws_js(TypeError, () => c.close(), 'second call to close should throw a TypeError');
startCalled = true;
}
}).getReader();
return Promise.all([
reader.read().then(r => {
assert_object_equals(r, { value: 'a', done: false }, 'read() should read the enqueued chunk');
readCalled = true;
}),
reader.closed.then(() => {
assert_true(startCalled);
assert_true(readCalled);
})
]);
}, 'Underlying source: calling close twice on a non-empty stream should throw the second time');
promise_test(() => {
let controller;
let startCalled = false;
const rs = new ReadableStream({
start(c) {
controller = c;
startCalled = true;
}
});
rs.cancel();
assert_throws_js(TypeError, () => controller.close(), 'Calling close after canceling should throw');
return rs.getReader().closed.then(() => {
assert_true(startCalled);
});
}, 'Underlying source: calling close on an empty canceled stream should throw');
promise_test(() => {
let controller;
let startCalled = false;
const rs = new ReadableStream({
start(c) {
controller = c;
c.enqueue('a');
startCalled = true;
}
});
rs.cancel();
assert_throws_js(TypeError, () => controller.close(), 'Calling close after canceling should throw');
return rs.getReader().closed.then(() => {
assert_true(startCalled);
});
}, 'Underlying source: calling close on a non-empty canceled stream should throw');
promise_test(() => {
const theError = new Error('boo');
let startCalled = false;
const closed = new ReadableStream({
start(c) {
c.error(theError);
assert_throws_js(TypeError, () => c.close(), 'call to close should throw a TypeError');
startCalled = true;
}
}).getReader().closed;
return closed.catch(e => {
assert_true(startCalled);
assert_equals(e, theError, 'closed should reject with the error');
});
}, 'Underlying source: calling close after error should throw');
promise_test(() => {
const theError = new Error('boo');
let startCalled = false;
const closed = new ReadableStream({
start(c) {
c.error(theError);
c.error();
startCalled = true;
}
}).getReader().closed;
return closed.catch(e => {
assert_true(startCalled);
assert_equals(e, theError, 'closed should reject with the error');
});
}, 'Underlying source: calling error twice should not throw');
promise_test(() => {
let startCalled = false;
const closed = new ReadableStream({
start(c) {
c.close();
c.error();
startCalled = true;
}
}).getReader().closed;
return closed.then(() => assert_true(startCalled));
}, 'Underlying source: calling error after close should not throw');
promise_test(() => {
let startCalled = false;
const firstError = new Error('1');
const secondError = new Error('2');
const closed = new ReadableStream({
start(c) {
c.error(firstError);
startCalled = true;
return Promise.reject(secondError);
}
}).getReader().closed;
return closed.catch(e => {
assert_true(startCalled);
assert_equals(e, firstError, 'closed should reject with the first error');
});
}, 'Underlying source: calling error and returning a rejected promise from start should cause the stream to error ' +
'with the first error');
promise_test(() => {
let startCalled = false;
const firstError = new Error('1');
const secondError = new Error('2');
const closed = new ReadableStream({
pull(c) {
c.error(firstError);
startCalled = true;
return Promise.reject(secondError);
}
}).getReader().closed;
return closed.catch(e => {
assert_true(startCalled);
assert_equals(e, firstError, 'closed should reject with the first error');
});
}, 'Underlying source: calling error and returning a rejected promise from pull should cause the stream to error ' +
'with the first error');
const error1 = { name: 'error1' };
promise_test(t => {
let pullShouldThrow = false;
const rs = new ReadableStream({
pull(controller) {
if (pullShouldThrow) {
throw error1;
}
controller.enqueue(0);
}
}, new CountQueuingStrategy({highWaterMark: 1}));
const reader = rs.getReader();
return Promise.resolve().then(() => {
pullShouldThrow = true;
return Promise.all([
reader.read(),
promise_rejects_exactly(t, error1, reader.closed, '.closed promise should reject')
]);
});
}, 'read should not error if it dequeues and pull() throws');