// META: global=window,worker,shadowrealm
// META: script=../resources/test-utils.js
'use strict';
promise_test(() => {
let flushCalled = false;
const ts = new TransformStream({
transform() { },
flush() {
flushCalled = true;
}
});
return ts.writable.getWriter().close().then(() => {
return assert_true(flushCalled, 'closing the writable triggers the transform flush immediately');
});
}, 'TransformStream flush is called immediately when the writable is closed, if no writes are queued');
promise_test(() => {
let flushCalled = false;
let resolveTransform;
const ts = new TransformStream({
transform() {
return new Promise(resolve => {
resolveTransform = resolve;
});
},
flush() {
flushCalled = true;
return new Promise(() => {}); // never resolves
}
}, undefined, { highWaterMark: 1 });
const writer = ts.writable.getWriter();
writer.write('a');
writer.close();
assert_false(flushCalled, 'closing the writable does not immediately call flush if writes are not finished');
let rsClosed = false;
ts.readable.getReader().closed.then(() => {
rsClosed = true;
});
return delay(0).then(() => {
assert_false(flushCalled, 'closing the writable does not asynchronously call flush if writes are not finished');
resolveTransform();
return delay(0);
}).then(() => {
assert_true(flushCalled, 'flush is eventually called');
assert_false(rsClosed, 'if flushPromise does not resolve, the readable does not become closed');
});
}, 'TransformStream flush is called after all queued writes finish, once the writable is closed');
promise_test(() => {
let c;
const ts = new TransformStream({
start(controller) {
c = controller;
},
transform() {
},
flush() {
c.enqueue('x');
c.enqueue('y');
}
});
const reader = ts.readable.getReader();
const writer = ts.writable.getWriter();
writer.write('a');
writer.close();
return reader.read().then(result1 => {
assert_equals(result1.value, 'x', 'the first chunk read is the first one enqueued in flush');
assert_equals(result1.done, false, 'the first chunk read is the first one enqueued in flush');
return reader.read().then(result2 => {
assert_equals(result2.value, 'y', 'the second chunk read is the second one enqueued in flush');
assert_equals(result2.done, false, 'the second chunk read is the second one enqueued in flush');
});
});
}, 'TransformStream flush gets a chance to enqueue more into the readable');
promise_test(() => {
let c;
const ts = new TransformStream({
start(controller) {
c = controller;
},
transform() {
},
flush() {
c.enqueue('x');
c.enqueue('y');
return delay(0);
}
});
const reader = ts.readable.getReader();
const writer = ts.writable.getWriter();
writer.write('a');
writer.close();
return Promise.all([
reader.read().then(result1 => {
assert_equals(result1.value, 'x', 'the first chunk read is the first one enqueued in flush');
assert_equals(result1.done, false, 'the first chunk read is the first one enqueued in flush');
return reader.read().then(result2 => {
assert_equals(result2.value, 'y', 'the second chunk read is the second one enqueued in flush');
assert_equals(result2.done, false, 'the second chunk read is the second one enqueued in flush');
});
}),
reader.closed.then(() => {
assert_true(true, 'readable reader becomes closed');
})
]);
}, 'TransformStream flush gets a chance to enqueue more into the readable, and can then async close');
const error1 = new Error('error1');
error1.name = 'error1';
promise_test(t => {
const ts = new TransformStream({
flush(controller) {
controller.error(error1);
}
});
return promise_rejects_exactly(t, error1, ts.writable.getWriter().close(), 'close() should reject');
}, 'error() during flush should cause writer.close() to reject');
promise_test(async t => {
let flushed = false;
const ts = new TransformStream({
flush() {
flushed = true;
},
cancel: t.unreached_func('cancel should not be called')
});
const closePromise = ts.writable.close();
await delay(0);
const cancelPromise = ts.readable.cancel(error1);
await Promise.all([closePromise, cancelPromise]);
assert_equals(flushed, true, 'transformer.flush() should be called');
}, 'closing the writable side should call transformer.flush() and a parallel readable.cancel() should not reject');