1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
|
<!DOCTYPE html>
<meta charset="utf-8">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="resources/helpers.js"></script>
<script src="../resources/test-utils.js"></script>
<script src="../resources/recording-streams.js"></script>
<script>
'use strict';
promise_test(t => {
const orig = new WritableStream();
const promise = new Promise(resolve => {
addEventListener('message', t.step_func(evt => {
const transferred = evt.data;
assert_equals(transferred.constructor, WritableStream,
'transferred should be a WritableStream in this realm');
assert_true(transferred instanceof WritableStream,
'instanceof check should pass');
// Perform a brand-check on |transferred|.
const writer = WritableStream.prototype.getWriter.call(transferred);
resolve();
}), {once: true});
});
postMessage(orig, '*', [orig]);
assert_true(orig.locked, 'the original stream should be locked');
return promise;
}, 'window.postMessage should be able to transfer a WritableStream');
test(() => {
const ws = new WritableStream();
const writer = ws.getWriter();
assert_throws_dom('DataCloneError', () => postMessage(ws, '*', [ws]),
'postMessage should throw');
}, 'a locked WritableStream should not be transferable');
promise_test(t => {
const {writable, readable} = new TransformStream();
const promise = new Promise(resolve => {
addEventListener('message', t.step_func(async evt => {
const {writable, readable} = evt.data;
const reader = readable.getReader();
const writer = writable.getWriter();
const writerPromises = Promise.all([
writer.write('hi'),
writer.close(),
]);
const {value, done} = await reader.read();
assert_false(done, 'we should not be done');
assert_equals(value, 'hi', 'chunk should have been delivered');
const readResult = await reader.read();
assert_true(readResult.done, 'readable should be closed');
await writerPromises;
resolve();
}), {once: true});
});
postMessage({writable, readable}, '*', [writable, readable]);
return promise;
}, 'window.postMessage should be able to transfer a {readable, writable} pair');
function transfer(stream) {
return new Promise(resolve => {
addEventListener('message', evt => resolve(evt.data), { once: true });
postMessage(stream, '*', [stream]);
});
}
promise_test(async () => {
const orig = new WritableStream(
{}, new ByteLengthQueuingStrategy({ highWaterMark: 65536 }));
const transferred = await transfer(orig);
const writer = transferred.getWriter();
assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');
}, 'desiredSize for a newly-transferred stream should be 1');
promise_test(async () => {
const orig = new WritableStream({
write() {
return new Promise(() => {});
}
});
const transferred = await transfer(orig);
const writer = transferred.getWriter();
await writer.write('a');
assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');
}, 'effective queue size of a transferred writable should be 2');
promise_test(async () => {
const [writeCalled, resolveWriteCalled] = makePromiseAndResolveFunc();
let resolveWrite;
const orig = new WritableStream({
write() {
resolveWriteCalled();
return new Promise(resolve => {
resolveWrite = resolve;
});
}
});
const transferred = await transfer(orig);
const writer = transferred.getWriter();
await writer.write('a');
let writeDone = false;
const writePromise = writer.write('b').then(() => {
writeDone = true;
});
await writeCalled;
assert_false(writeDone, 'second write should not have resolved yet');
resolveWrite();
await writePromise; // (makes sure this resolves)
}, 'second write should wait for first underlying write to complete');
async function transferredWritableStreamWithAbortPromise() {
const [abortCalled, resolveAbortCalled] = makePromiseAndResolveFunc();
const orig = recordingWritableStream({
abort() {
resolveAbortCalled();
}
});
const transferred = await transfer(orig);
return { orig, transferred, abortCalled };
}
promise_test(async t => {
const { orig, transferred, abortCalled } = await transferredWritableStreamWithAbortPromise();
transferred.abort('p');
await abortCalled;
assert_array_equals(orig.events, ['abort', 'p'],
'abort() should have been called');
}, 'abort() should work');
promise_test(async t => {
const { orig, transferred, abortCalled } = await transferredWritableStreamWithAbortPromise();
const writer = transferred.getWriter();
// A WritableStream object cannot be cloned.
await promise_rejects_dom(t, 'DataCloneError', writer.write(new WritableStream()),
'the write should reject');
await promise_rejects_dom(t, 'DataCloneError', writer.closed,
'the stream should be errored');
await abortCalled;
assert_equals(orig.events.length, 2, 'abort should have been called');
assert_equals(orig.events[0], 'abort', 'first event should be abort');
assert_equals(orig.events[1].name, 'DataCloneError',
'reason should be a DataCloneError');
}, 'writing a unclonable object should error the stream');
</script>
|