https://github.com/web-platform-tests/wpt
Tip revision: 9b6e516d529b526e06447d171dc2937f646bbe89 authored by Bear Travis on 11 July 2014, 21:52:43 UTC
Adding basic tests for the CSS.supports API as part of the CSS Conditional Rules Module L3.
Adding basic tests for the CSS.supports API as part of the CSS Conditional Rules Module L3.
Tip revision: 9b6e516
aborting.js
'use strict';
if (self.importScripts) {
self.importScripts('/resources/testharness.js');
self.importScripts('../resources/test-utils.js');
self.importScripts('../resources/recording-streams.js');
}
const error1 = new Error('error1');
error1.name = 'error1';
const error2 = new Error('error2');
error2.name = 'error2';
promise_test(t => {
const ws = new WritableStream({
write() {
return new Promise(() => { }); // forever-pending, so normally .ready would not fulfill.
}
});
const writer = ws.getWriter();
const writePromise = writer.write('a');
const readyPromise = writer.ready;
writer.abort(error1);
assert_equals(writer.ready, readyPromise, 'the ready promise property should not change');
return Promise.all([
promise_rejects(t, new TypeError(), readyPromise, 'the ready promise should reject with a TypeError'),
promise_rejects(t, new TypeError(), writePromise, 'the write() promise should reject with a TypeError')
]);
}, 'Aborting a WritableStream before it starts should cause the writer\'s unsettled ready promise to reject');
promise_test(t => {
const ws = new WritableStream();
const writer = ws.getWriter();
writer.write('a');
const readyPromise = writer.ready;
return readyPromise.then(() => {
writer.abort(error1);
assert_not_equals(writer.ready, readyPromise, 'the ready promise property should change');
return promise_rejects(t, new TypeError(), writer.ready, 'the ready promise should reject with a TypeError');
});
}, 'Aborting a WritableStream should cause the writer\'s fulfilled ready promise to reset to a rejected one');
promise_test(t => {
const ws = new WritableStream();
const writer = ws.getWriter();
writer.releaseLock();
return promise_rejects(t, new TypeError(), writer.abort(), 'abort() should reject with a TypeError');
}, 'abort() on a released writer rejects');
promise_test(t => {
const ws = recordingWritableStream();
return delay(0)
.then(() => {
const writer = ws.getWriter();
writer.abort();
return Promise.all([
promise_rejects(t, new TypeError(), writer.write(1), 'write(1) must reject with a TypeError'),
promise_rejects(t, new TypeError(), writer.write(2), 'write(2) must reject with a TypeError')
]);
})
.then(() => {
assert_array_equals(ws.events, ['abort', undefined]);
});
}, 'Aborting a WritableStream immediately prevents future writes');
promise_test(t => {
const ws = recordingWritableStream();
const results = [];
return delay(0)
.then(() => {
const writer = ws.getWriter();
results.push(
writer.write(1),
promise_rejects(t, new TypeError(), writer.write(2), 'write(2) must reject with a TypeError'),
promise_rejects(t, new TypeError(), writer.write(3), 'write(3) must reject with a TypeError')
);
const abortPromise = writer.abort();
results.push(
promise_rejects(t, new TypeError(), writer.write(4), 'write(4) must reject with a TypeError'),
promise_rejects(t, new TypeError(), writer.write(5), 'write(5) must reject with a TypeError')
);
return abortPromise;
}).then(() => {
assert_array_equals(ws.events, ['write', 1, 'abort', undefined]);
return Promise.all(results);
});
}, 'Aborting a WritableStream prevents further writes after any that are in progress');
promise_test(() => {
const ws = new WritableStream({
abort() {
return 'Hello';
}
});
const writer = ws.getWriter();
return writer.abort('a').then(value => {
assert_equals(value, undefined, 'fulfillment value must be undefined');
});
}, 'Fulfillment value of ws.abort() call must be undefined even if the underlying sink returns a non-undefined value');
promise_test(t => {
const ws = new WritableStream({
abort() {
throw error1;
}
});
const writer = ws.getWriter();
return promise_rejects(t, error1, writer.abort(undefined),
'rejection reason of abortPromise must be the error thrown by abort');
}, 'WritableStream if sink\'s abort throws, the promise returned by writer.abort() rejects');
promise_test(t => {
const ws = new WritableStream({
abort() {
throw error1;
}
});
return promise_rejects(t, error1, ws.abort(undefined),
'rejection reason of abortPromise must be the error thrown by abort');
}, 'WritableStream if sink\'s abort throws, the promise returned by ws.abort() rejects');
promise_test(t => {
let resolveWritePromise;
const ws = new WritableStream({
write() {
return new Promise(resolve => {
resolveWritePromise = resolve;
});
},
abort() {
throw error1;
}
});
const writer = ws.getWriter();
writer.write().catch(() => {});
return flushAsyncEvents().then(() => {
const abortPromise = writer.abort(undefined);
resolveWritePromise();
return promise_rejects(t, error1, abortPromise,
'rejection reason of abortPromise must be the error thrown by abort');
});
}, 'WritableStream if sink\'s abort throws, for an abort performed during a write, the promise returned by ' +
'ws.abort() rejects');
promise_test(() => {
const ws = recordingWritableStream();
const writer = ws.getWriter();
return writer.abort(error1).then(() => {
assert_array_equals(ws.events, ['abort', error1]);
});
}, 'Aborting a WritableStream passes through the given reason');
promise_test(t => {
const ws = new WritableStream();
const writer = ws.getWriter();
writer.abort(error1);
const events = [];
writer.ready.catch(() => {
events.push('ready');
});
writer.closed.catch(() => {
events.push('closed');
});
return Promise.all([
promise_rejects(t, new TypeError(), writer.write(), 'writing should reject with a TypeError'),
promise_rejects(t, new TypeError(), writer.close(), 'closing should reject with a TypeError'),
promise_rejects(t, new TypeError(), writer.abort(), 'aborting should reject with a TypeError'),
promise_rejects(t, new TypeError(), writer.ready, 'ready should reject with a TypeError'),
promise_rejects(t, new TypeError(), writer.closed, 'closed should reject with a TypeError')
]).then(() => {
assert_array_equals(['ready', 'closed'], events, 'ready should reject before closed');
});
}, 'Aborting a WritableStream puts it in an errored state, with a TypeError as the stored error');
promise_test(t => {
const ws = new WritableStream();
const writer = ws.getWriter();
const writePromise = promise_rejects(t, new TypeError(), writer.write('a'),
'writing should reject with a TypeError');
writer.abort(error1);
return writePromise;
}, 'Aborting a WritableStream causes any outstanding write() promises to be rejected with a TypeError');
promise_test(t => {
const ws = recordingWritableStream();
const writer = ws.getWriter();
const closePromise = writer.close();
const abortPromise = writer.abort(error1);
return Promise.all([
promise_rejects(t, new TypeError(), writer.closed, 'closed should reject with a TypeError'),
promise_rejects(t, new TypeError(), closePromise, 'close() should reject with a TypeError'),
abortPromise
]).then(() => {
assert_array_equals(ws.events, ['abort', error1]);
});
}, 'Closing but then immediately aborting a WritableStream causes the stream to error');
promise_test(t => {
let resolveClose;
const ws = new WritableStream({
close() {
return new Promise(resolve => {
resolveClose = resolve;
});
}
});
const writer = ws.getWriter();
const closePromise = writer.close();
return delay(0).then(() => {
const abortPromise = writer.abort(error1);
resolveClose();
return Promise.all([
writer.closed,
abortPromise,
closePromise
]);
});
}, 'Closing a WritableStream and aborting it while it closes causes the stream to ignore the abort attempt');
promise_test(() => {
const ws = new WritableStream();
const writer = ws.getWriter();
writer.close();
return delay(0).then(() => writer.abort());
}, 'Aborting a WritableStream after it is closed is a no-op');
promise_test(t => {
// Testing that per https://github.com/whatwg/streams/issues/620#issuecomment-263483953 the fallback to close was
// removed.
// Cannot use recordingWritableStream since it always has an abort
let closeCalled = false;
const ws = new WritableStream({
close() {
closeCalled = true;
}
});
const writer = ws.getWriter();
writer.abort();
return promise_rejects(t, new TypeError(), writer.closed, 'closed should reject with a TypeError').then(() => {
assert_false(closeCalled, 'close must not have been called');
});
}, 'WritableStream should NOT call underlying sink\'s close if no abort is supplied (historical)');
promise_test(() => {
let thenCalled = false;
const ws = new WritableStream({
abort() {
return {
then(onFulfilled) {
thenCalled = true;
onFulfilled();
}
};
}
});
const writer = ws.getWriter();
return writer.abort().then(() => assert_true(thenCalled, 'then() should be called'));
}, 'returning a thenable from abort() should work');
promise_test(t => {
const ws = new WritableStream({
write() {
return flushAsyncEvents();
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
const writePromise = writer.write('a');
writer.abort(error1);
let closedResolved = false;
return Promise.all([
writePromise.then(() => assert_false(closedResolved, '.closed should not resolve before write()')),
promise_rejects(t, new TypeError(), writer.closed, '.closed should reject').then(() => {
closedResolved = true;
})
]);
});
}, '.closed should not resolve before fulfilled write()');
promise_test(t => {
const ws = new WritableStream({
write() {
return Promise.reject(error1);
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
const writePromise = writer.write('a');
const abortPromise = writer.abort(error2);
let closedResolved = false;
return Promise.all([
promise_rejects(t, error1, writePromise, 'write() should reject')
.then(() => assert_false(closedResolved, '.closed should not resolve before write()')),
promise_rejects(t, error1, writer.closed, '.closed should reject')
.then(() => {
closedResolved = true;
}),
promise_rejects(t, error1, abortPromise, 'abort() should reject')]);
});
}, '.closed should not resolve before rejected write(); write() error should overwrite abort() error');
promise_test(t => {
const ws = new WritableStream({
write() {
return flushAsyncEvents();
}
}, new CountQueuingStrategy(4));
const writer = ws.getWriter();
return writer.ready.then(() => {
const settlementOrder = [];
return Promise.all([
writer.write('1').then(() => settlementOrder.push(1)),
promise_rejects(t, new TypeError(), writer.write('2'), 'first queued write should be rejected')
.then(() => settlementOrder.push(2)),
promise_rejects(t, new TypeError(), writer.write('3'), 'second queued write should be rejected')
.then(() => settlementOrder.push(3)),
writer.abort(error1)
]).then(() => assert_array_equals([1, 2, 3], settlementOrder, 'writes should be satisfied in order'));
});
}, 'writes should be satisfied in order when aborting');
promise_test(t => {
const ws = new WritableStream({
write() {
return Promise.reject(error1);
}
}, new CountQueuingStrategy(4));
const writer = ws.getWriter();
return writer.ready.then(() => {
const settlementOrder = [];
return Promise.all([
promise_rejects(t, error1, writer.write('1'), 'in-flight write should be rejected')
.then(() => settlementOrder.push(1)),
promise_rejects(t, error1, writer.write('2'), 'first queued write should be rejected')
.then(() => settlementOrder.push(2)),
promise_rejects(t, error1, writer.write('3'), 'second queued write should be rejected')
.then(() => settlementOrder.push(3)),
promise_rejects(t, error1, writer.abort(error1), 'abort should be rejected')
]).then(() => assert_array_equals([1, 2, 3], settlementOrder, 'writes should be satisfied in order'));
});
}, 'writes should be satisfied in order after rejected write when aborting');
promise_test(t => {
const ws = new WritableStream({
write() {
return Promise.reject(error1);
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
return Promise.all([
promise_rejects(t, error1, writer.write('a'), 'writer.write() should reject with error from underlying write()'),
promise_rejects(t, error1, writer.close(), 'writer.close() should reject with error from underlying write()'),
promise_rejects(t, error1, writer.abort(), 'writer.abort() should reject with error from underlying write()')
]);
});
}, 'close() should use error from underlying write() on abort');
promise_test(() => {
let resolveWrite;
const ws = recordingWritableStream({
write() {
return new Promise(resolve => {
resolveWrite = resolve;
});
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
writer.write('a');
const abortPromise = writer.abort('b');
return flushAsyncEvents().then(() => {
assert_array_equals(ws.events, ['write', 'a'], 'abort should not be called while write is in-flight');
resolveWrite();
return abortPromise.then(() => {
assert_array_equals(ws.events, ['write', 'a', 'abort', 'b'], 'abort should be called after the write finishes');
});
});
});
}, 'underlying abort() should not be called until underlying write() completes');
promise_test(() => {
let resolveClose;
const ws = recordingWritableStream({
close() {
return new Promise(resolve => {
resolveClose = resolve;
});
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
writer.close();
const abortPromise = writer.abort();
return flushAsyncEvents().then(() => {
assert_array_equals(ws.events, ['close'], 'abort should not be called while close is in-flight');
resolveClose();
return abortPromise.then(() => {
assert_array_equals(ws.events, ['close'], 'abort should not be called');
});
});
});
}, 'underlying abort() should not be called if underlying close() has started');
promise_test(t => {
let rejectClose;
let abortCalled = false;
const ws = new WritableStream({
close() {
return new Promise((resolve, reject) => {
rejectClose = reject;
});
},
abort() {
abortCalled = true;
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
const closePromise = writer.close();
const abortPromise = writer.abort();
return flushAsyncEvents().then(() => {
assert_false(abortCalled, 'underlying abort should not be called while close is in-flight');
rejectClose(error1);
return promise_rejects(t, error1, abortPromise, 'abort should reject with the same reason').then(() => {
return promise_rejects(t, error1, closePromise, 'close should reject with the same reason');
}).then(() => {
assert_false(abortCalled, 'underlying abort should not be called after close completes');
});
});
});
}, 'if underlying close() has started and then rejects, the abort() and close() promises should reject with the ' +
'underlying close rejection reason');
promise_test(t => {
let resolveWrite;
const ws = recordingWritableStream({
write() {
return new Promise(resolve => {
resolveWrite = resolve;
});
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
writer.write('a');
const closePromise = writer.close();
const abortPromise = writer.abort('b');
return flushAsyncEvents().then(() => {
assert_array_equals(ws.events, ['write', 'a'], 'abort should not be called while write is in-flight');
resolveWrite();
return abortPromise.then(() => {
assert_array_equals(ws.events, ['write', 'a', 'abort', 'b'], 'abort should be called after write completes');
return promise_rejects(t, new TypeError(), closePromise, 'promise returned by close() should be rejected');
});
});
});
}, 'an abort() that happens during a write() should trigger the underlying abort() even with a close() queued');
promise_test(t => {
const ws = new WritableStream({
write() {
return new Promise(() => {});
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
writer.write('a');
writer.abort();
writer.releaseLock();
const writer2 = ws.getWriter();
return promise_rejects(t, new TypeError(), writer2.ready,
'ready of the second writer should be rejected with a TypeError');
});
}, 'if a writer is created for a stream with a pending abort, its ready should be rejected with a TypeError');
promise_test(() => {
const ws = new WritableStream();
const writer = ws.getWriter();
return writer.ready.then(() => {
const closePromise = writer.close();
const abortPromise = writer.abort();
const events = [];
return Promise.all([
closePromise.then(() => { events.push('close'); }),
abortPromise.then(() => { events.push('abort'); })
]).then(() => {
assert_array_equals(events, ['close', 'abort']);
});
});
}, 'writer close() promise should resolve before abort() promise');
promise_test(t => {
const ws = new WritableStream({
write(chunk, controller) {
controller.error(error1);
return new Promise(() => {});
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
writer.write('a');
return promise_rejects(t, error1, writer.ready, 'writer.ready should reject');
});
}, 'writer.ready should reject on controller error without waiting for underlying write');
promise_test(t => {
let rejectWrite;
const ws = new WritableStream({
write() {
return new Promise((resolve, reject) => {
rejectWrite = reject;
});
}
});
let writePromise;
let abortPromise;
const events = [];
const writer = ws.getWriter();
writer.closed.catch(() => {
events.push('closed');
});
// Wait for ws to start
return flushAsyncEvents().then(() => {
writePromise = writer.write('a');
writePromise.catch(() => {
events.push('writePromise');
});
abortPromise = writer.abort(error1);
abortPromise.catch(() => {
events.push('abortPromise');
});
const writePromise2 = writer.write('a');
return Promise.all([
promise_rejects(t, new TypeError(), writePromise2, 'writePromise2 must reject with an error indicating abort'),
promise_rejects(t, new TypeError(), writer.ready, 'writer.ready must reject with an error indicating abort'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(events, [], 'writePromise, abortPromise and writer.closed must not be rejected yet');
rejectWrite(error2);
return Promise.all([
promise_rejects(t, error2, writePromise,
'writePromise must reject with the error returned from the sink\'s write method'),
promise_rejects(t, error2, abortPromise,
'abortPromise must reject with the error returned from the sink\'s write method'),
promise_rejects(t, error2, writer.closed,
'writer.closed must reject with the error returned from the sink\'s write method'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(events, ['writePromise', 'closed', 'abortPromise'],
'writePromise, abortPromise and writer.closed must reject');
const writePromise3 = writer.write('a');
return Promise.all([
promise_rejects(t, error2, writePromise3,
'writePromise3 must reject with the error returned from the sink\'s write method'),
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be still rejected with the error indicating abort')
]);
}).then(() => {
writer.releaseLock();
return Promise.all([
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be rejected with an error indicating release'),
promise_rejects(t, new TypeError(), writer.closed,
'writer.closed must be rejected with an error indicating release')
]);
});
}, 'writer.abort() while there is an in-flight write, and then finish the write with rejection');
promise_test(t => {
let resolveWrite;
let controller;
const ws = new WritableStream({
write(chunk, c) {
controller = c;
return new Promise(resolve => {
resolveWrite = resolve;
});
}
});
let writePromise;
let abortPromise;
const events = [];
const writer = ws.getWriter();
writer.closed.catch(() => {
events.push('closed');
});
// Wait for ws to start
return flushAsyncEvents().then(() => {
writePromise = writer.write('a');
writePromise.then(() => {
events.push('writePromise');
});
abortPromise = writer.abort(error1);
abortPromise.catch(() => {
events.push('abortPromise');
});
const writePromise2 = writer.write('a');
return Promise.all([
promise_rejects(t, new TypeError(), writePromise2, 'writePromise2 must reject with an error indicating abort'),
promise_rejects(t, new TypeError(), writer.ready, 'writer.ready must reject with an error indicating abort'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(events, [], 'writePromise, abortPromise and writer.closed must not be fulfilled/rejected yet');
controller.error(error2);
const writePromise3 = writer.write('a');
return Promise.all([
promise_rejects(t, error2, writePromise3,
'writePromise3 must reject with the error passed to the controller\'s error method'),
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be still rejected with the error indicating abort'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(
events, [],
'writePromise, abortPromise and writer.closed must not be fulfilled/rejected yet even after ' +
'controller.error() call');
resolveWrite();
return Promise.all([
writePromise,
promise_rejects(t, error2, abortPromise,
'abortPromise must reject with the error passed to the controller\'s error method'),
promise_rejects(t, error2, writer.closed,
'writer.closed must reject with the error passed to the controller\'s error method'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(events, ['writePromise', 'abortPromise', 'closed'],
'writePromise, abortPromise and writer.closed must reject');
const writePromise4 = writer.write('a');
return Promise.all([
writePromise,
promise_rejects(t, error2, writePromise4,
'writePromise4 must reject with the error passed to the controller\'s error method'),
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be still rejected with the error indicating abort')
]);
}).then(() => {
writer.releaseLock();
return Promise.all([
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be rejected with an error indicating release'),
promise_rejects(t, new TypeError(), writer.closed,
'writer.closed must be rejected with an error indicating release')
]);
});
}, 'writer.abort(), controller.error() while there is an in-flight write, and then finish the write');
promise_test(t => {
let resolveClose;
let controller;
const ws = new WritableStream({
start(c) {
controller = c;
},
close() {
return new Promise(resolve => {
resolveClose = resolve;
});
}
});
let closePromise;
let abortPromise;
const events = [];
const writer = ws.getWriter();
writer.closed.catch(() => {
events.push('closed');
});
// Wait for ws to start
return flushAsyncEvents().then(() => {
closePromise = writer.close();
closePromise.then(() => {
events.push('closePromise');
});
abortPromise = writer.abort(error1);
abortPromise.catch(() => {
events.push('abortPromise');
});
return Promise.all([
promise_rejects(t, new TypeError(), writer.close(),
'writer.close() must reject with an error indicating already closing'),
promise_rejects(t, new TypeError(), writer.ready, 'writer.ready must reject with an error indicating abort'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(events, [], 'closePromise, abortPromise and writer.closed must not be fulfilled/rejected yet');
controller.error(error2);
return Promise.all([
promise_rejects(t, new TypeError(), writer.close(),
'writer.close() must reject with an error indicating already closing'),
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be still rejected with the error indicating abort'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(
events, [],
'closePromise, abortPromise and writer.closed must not be fulfilled/rejected yet even after ' +
'controller.error() call');
resolveClose();
return Promise.all([
closePromise,
promise_rejects(t, error2, abortPromise,
'abortPromise must reject with the error passed to the controller\'s error method'),
promise_rejects(t, error2, writer.closed,
'writer.closed must reject with the error passed to the controller\'s error method'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(events, ['closePromise', 'abortPromise', 'closed'],
'closedPromise, abortPromise and writer.closed must reject');
return Promise.all([
promise_rejects(t, new TypeError(), writer.close(),
'writer.close() must reject with an error indicating already closing'),
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be still rejected with the error indicating abort')
]);
}).then(() => {
writer.releaseLock();
return Promise.all([
promise_rejects(t, new TypeError(), writer.close(),
'writer.close() must reject with an error indicating release'),
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be rejected with an error indicating release'),
promise_rejects(t, new TypeError(), writer.closed,
'writer.closed must be rejected with an error indicating release')
]);
});
}, 'writer.abort(), controller.error() while there is an in-flight close, and then finish the close');
promise_test(t => {
let resolveWrite;
let controller;
const ws = new WritableStream({
write(chunk, c) {
controller = c;
return new Promise(resolve => {
resolveWrite = resolve;
});
}
});
let writePromise;
let abortPromise;
const events = [];
const writer = ws.getWriter();
writer.closed.catch(() => {
events.push('closed');
});
// Wait for ws to start
return flushAsyncEvents().then(() => {
writePromise = writer.write('a');
writePromise.then(() => {
events.push('writePromise');
});
controller.error(error2);
const writePromise2 = writer.write('a');
return Promise.all([
promise_rejects(t, error2, writePromise2,
'writePromise2 must reject with the error passed to the controller\'s error method'),
promise_rejects(t, error2, writer.ready,
'writer.ready must reject with the error passed to the controller\'s error method'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(events, [], 'writePromise and writer.closed must not be fulfilled/rejected yet');
abortPromise = writer.abort(error1);
abortPromise.catch(() => {
events.push('abortPromise');
});
const writePromise3 = writer.write('a');
return Promise.all([
promise_rejects(t, error2, abortPromise,
'abortPromise must reject with the error passed to the controller\'s error method'),
promise_rejects(t, error2, writePromise3,
'writePromise3 must reject with the error passed to the controller\'s error method'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(
events, ['abortPromise'],
'writePromise and writer.closed must not be fulfilled/rejected yet even after writer.abort()');
resolveWrite();
return Promise.all([
promise_rejects(t, error2, writer.closed,
'writer.closed must reject with the error passed to the controller\'s error method'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(events, ['abortPromise', 'writePromise', 'closed'],
'writePromise, abortPromise and writer.closed must fulfill/reject');
const writePromise4 = writer.write('a');
return Promise.all([
writePromise,
promise_rejects(t, error2, writePromise4,
'writePromise4 must reject with the error passed to the controller\'s error method'),
promise_rejects(t, error2, writer.ready,
'writer.ready must be still rejected with the error passed to the controller\'s error method')
]);
}).then(() => {
writer.releaseLock();
return Promise.all([
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be rejected with an error indicating release'),
promise_rejects(t, new TypeError(), writer.closed,
'writer.closed must be rejected with an error indicating release')
]);
});
}, 'controller.error(), writer.abort() while there is an in-flight write, and then finish the write');
promise_test(t => {
let resolveClose;
let controller;
const ws = new WritableStream({
start(c) {
controller = c;
},
close() {
return new Promise(resolve => {
resolveClose = resolve;
});
}
});
let closePromise;
let abortPromise;
const events = [];
const writer = ws.getWriter();
writer.closed.catch(() => {
events.push('closed');
});
// Wait for ws to start
return flushAsyncEvents().then(() => {
closePromise = writer.close();
closePromise.then(() => {
events.push('closePromise');
});
controller.error(error2);
return flushAsyncEvents();
}).then(() => {
assert_array_equals(events, [], 'closePromise must not be fulfilled/rejected yet');
abortPromise = writer.abort(error1);
abortPromise.catch(() => {
events.push('abortPromise');
});
return Promise.all([
promise_rejects(t, error2, writer.ready,
'writer.ready must reject with the error passed to the controller\'s error method'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(
events, ['abortPromise'],
'closePromise and writer.closed must not be fulfilled/rejected yet even after writer.abort()');
resolveClose();
return Promise.all([
closePromise,
promise_rejects(t, error2, writer.ready,
'writer.ready must be still rejected with the error passed to the controller\'s error method'),
promise_rejects(t, error2, writer.closed,
'writer.closed must reject with the error passed to the controller\'s error method'),
flushAsyncEvents()
]);
}).then(() => {
assert_array_equals(events, ['abortPromise', 'closePromise', 'closed'],
'abortPromise, closePromise and writer.closed must fulfill/reject');
}).then(() => {
writer.releaseLock();
return Promise.all([
promise_rejects(t, new TypeError(), writer.ready,
'writer.ready must be rejected with an error indicating release'),
promise_rejects(t, new TypeError(), writer.closed,
'writer.closed must be rejected with an error indicating release')
]);
});
}, 'controller.error(), writer.abort() while there is an in-flight close, and then finish the close');
promise_test(t => {
let resolveWrite;
const ws = new WritableStream({
write() {
return new Promise(resolve => {
resolveWrite = resolve;
});
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
const writePromise = writer.write('a');
const closed = writer.closed;
const abortPromise = writer.abort();
writer.releaseLock();
resolveWrite();
return Promise.all([
writePromise,
abortPromise,
promise_rejects(t, new TypeError(), closed, 'closed should reject')]);
});
}, 'releaseLock() while aborting should reject the original closed promise');
promise_test(t => {
let resolveWrite;
let resolveAbort;
let resolveAbortStarted;
const abortStarted = new Promise(resolve => {
resolveAbortStarted = resolve;
});
const ws = new WritableStream({
write() {
return new Promise(resolve => {
resolveWrite = resolve;
});
},
abort() {
resolveAbortStarted();
return new Promise(resolve => {
resolveAbort = resolve;
});
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
const writePromise = writer.write('a');
const closed = writer.closed;
const abortPromise = writer.abort();
resolveWrite();
return abortStarted.then(() => {
writer.releaseLock();
assert_not_equals(writer.closed, closed, 'closed promise should have changed');
resolveAbort();
return Promise.all([
writePromise,
abortPromise,
promise_rejects(t, new TypeError(), closed, 'original closed should reject'),
promise_rejects(t, new TypeError(), writer.closed, 'new closed should reject')]);
});
});
}, 'releaseLock() during delayed async abort() should create a new rejected closed promise');
promise_test(() => {
let resolveStart;
const ws = recordingWritableStream({
start() {
return new Promise(resolve => {
resolveStart = resolve;
});
}
});
const abortPromise = ws.abort('done');
return flushAsyncEvents().then(() => {
assert_array_equals(ws.events, [], 'abort() should not be called during start()');
resolveStart();
return abortPromise.then(() => {
assert_array_equals(ws.events, ['abort', 'done'], 'abort() should be called after start() is done');
});
});
}, 'sink abort() should not be called until sink start() is done');
promise_test(t => {
let resolveStart;
let controller;
const ws = recordingWritableStream({
start(c) {
controller = c;
return new Promise(resolve => {
resolveStart = resolve;
});
}
});
const abortPromise = ws.abort('done');
controller.error(error1);
resolveStart();
return promise_rejects(t, error1, abortPromise, 'abort() should reject if start() errors the controller')
.then(() =>
assert_array_equals(ws.events, [], 'abort() should be not be called if start() errors the controller'));
}, 'abort() promise should reject if start() errors the controller');
promise_test(t => {
const ws = recordingWritableStream({
start() {
return Promise.reject(error1);
}
});
return promise_rejects(t, error1, ws.abort('done'), 'abort() should reject if start() rejects')
.then(() =>
assert_array_equals(ws.events, [], 'abort() should be not be called if start() rejects'));
}, 'stream abort() promise should reject if sink start() rejects');
promise_test(t => {
const ws = new WritableStream();
const writer = ws.getWriter();
const writerReady1 = writer.ready;
writer.abort('a');
const writerReady2 = writer.ready;
assert_not_equals(writerReady1, writerReady2, 'abort() should replace the ready promise with a rejected one');
return Promise.all([writerReady1,
promise_rejects(t, new TypeError(), writerReady2, 'writerReady2 should reject')]);
}, 'writer abort() during sink start() should replace the writer.ready promise synchronously');
promise_test(t => {
const promises = [];
const resolved = [];
const ws = recordingWritableStream();
const writer = ws.getWriter();
promises.push(promise_rejects(t, new TypeError(), writer.write(1), 'first write() should reject')
.then(() => resolved.push('write1')));
promises.push(writer.abort('a')
.then(() => resolved.push('abort')));
promises.push(promise_rejects(t, new TypeError(), writer.write(2), 'second write() should reject')
.then(() => resolved.push('write2')));
promises.push(promise_rejects(t, new TypeError(), writer.close(), 'close() should reject')
.then(() => resolved.push('close')));
return Promise.all(promises)
.then(() => {
assert_array_equals(resolved, ['write2', 'close', 'write1', 'abort'],
'promises should resolve in the standard order');
assert_array_equals(ws.events, ['abort', 'a'], 'underlying sink write() should not be called');
});
}, 'promises returned from other writer methods should be rejected when writer abort() happens during sink start()');
promise_test(t => {
let writeReject;
let controller;
const ws = new WritableStream({
write(chunk, c) {
controller = c;
return new Promise((resolve, reject) => {
writeReject = reject;
});
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
const writePromise = writer.write('a');
const abortPromise = writer.abort();
controller.error(error1);
writeReject(error2);
return Promise.all([
promise_rejects(t, error2, writePromise, 'write() should reject with error2'),
promise_rejects(t, error1, abortPromise, 'abort() should reject with error1')
]);
});
}, 'abort() should be rejected with the error passed to controller.error() during pending write()');
promise_test(t => {
let closeReject;
let controller;
const ws = new WritableStream({
close(c) {
controller = c;
return new Promise((resolve, reject) => {
closeReject = reject;
});
}
});
const writer = ws.getWriter();
return writer.ready.then(() => {
const closePromise = writer.close();
const abortPromise = writer.abort();
controller.error(error1);
closeReject(error2);
return Promise.all([
promise_rejects(t, error2, closePromise, 'close() should reject with error2'),
promise_rejects(t, error1, abortPromise, 'abort() should reject with error1')
]);
});
}, 'abort() should be rejected with the error passed to controller.error() during pending close()');
done();