gecko-dev/testing/web-platform/tests/streams/readable-streams/cancel.any.js
Jason Orendorff 47519c94b2 Bug 1513570 - Part 1: Adapt stream tests to run in the shell. r=Ms2ger
We don't support byte streams, transform streams, writable streams, or piping
yet, but we will, and in the meantime our own meta files disable those tests
for us.

Differential Revision: https://phabricator.services.mozilla.com/D14314

--HG--
extra : moz-landing-system : lando
2018-12-14 18:14:56 +00:00

236 lines
7.1 KiB
JavaScript

// META: global=worker,jsshell
// META: script=../resources/test-utils.js
// META: script=../resources/rs-utils.js
'use strict';
promise_test(t => {
const randomSource = new RandomPushSource();
let cancellationFinished = false;
const rs = new ReadableStream({
start(c) {
randomSource.ondata = c.enqueue.bind(c);
randomSource.onend = c.close.bind(c);
randomSource.onerror = c.error.bind(c);
},
pull() {
randomSource.readStart();
},
cancel() {
randomSource.readStop();
return new Promise(resolve => {
t.step_timeout(() => {
cancellationFinished = true;
resolve();
}, 1);
});
}
});
const reader = rs.getReader();
// We call delay multiple times to avoid cancelling too early for the
// source to enqueue at least one chunk.
const cancel = delay(5).then(() => delay(5)).then(() => delay(5)).then(() => {
const cancelPromise = reader.cancel();
assert_false(cancellationFinished, 'cancellation in source should happen later');
return cancelPromise;
});
return readableStreamToArray(rs, reader).then(chunks => {
assert_greater_than(chunks.length, 0, 'at least one chunk should be read');
for (let i = 0; i < chunks.length; i++) {
assert_equals(chunks[i].length, 128, 'chunk ' + i + ' should have 128 bytes');
}
return cancel;
}).then(() => {
assert_true(cancellationFinished, 'it returns a promise that is fulfilled when the cancellation finishes');
});
}, 'ReadableStream cancellation: integration test on an infinite stream derived from a random push source');
test(() => {
let recordedReason;
const rs = new ReadableStream({
cancel(reason) {
recordedReason = reason;
}
});
const passedReason = new Error('Sorry, it just wasn\'t meant to be.');
rs.cancel(passedReason);
assert_equals(recordedReason, passedReason,
'the error passed to the underlying source\'s cancel method should equal the one passed to the stream\'s cancel');
}, 'ReadableStream cancellation: cancel(reason) should pass through the given reason to the underlying source');
promise_test(() => {
const rs = new ReadableStream({
start(c) {
c.enqueue('a');
c.close();
},
cancel() {
assert_unreached('underlying source cancel() should not have been called');
}
});
const reader = rs.getReader();
return rs.cancel().then(() => {
assert_unreached('cancel() should be rejected');
}, e => {
assert_equals(e.name, 'TypeError', 'cancel() should be rejected with a TypeError');
}).then(() => {
return reader.read();
}).then(result => {
assert_object_equals(result, { value: 'a', done: false }, 'read() should still work after the attempted cancel');
return reader.closed;
});
}, 'ReadableStream cancellation: cancel() on a locked stream should fail and not call the underlying source cancel');
promise_test(() => {
let cancelReceived = false;
const cancelReason = new Error('I am tired of this stream, I prefer to cancel it');
const rs = new ReadableStream({
cancel(reason) {
cancelReceived = true;
assert_equals(reason, cancelReason, 'cancellation reason given to the underlying source should be equal to the one passed');
}
});
return rs.cancel(cancelReason).then(() => {
assert_true(cancelReceived);
});
}, 'ReadableStream cancellation: should fulfill promise when cancel callback went fine');
promise_test(() => {
const rs = new ReadableStream({
cancel() {
return 'Hello';
}
});
return rs.cancel().then(v => {
assert_equals(v, undefined, 'cancel() return value should be fulfilled with undefined');
});
}, 'ReadableStream cancellation: returning a value from the underlying source\'s cancel should not affect the fulfillment value of the promise returned by the stream\'s cancel');
promise_test(() => {
const thrownError = new Error('test');
let cancelCalled = false;
const rs = new ReadableStream({
cancel() {
cancelCalled = true;
throw thrownError;
}
});
return rs.cancel('test').then(() => {
assert_unreached('cancel should reject');
}, e => {
assert_true(cancelCalled);
assert_equals(e, thrownError);
});
}, 'ReadableStream cancellation: should reject promise when cancel callback raises an exception');
promise_test(() => {
const cancelReason = new Error('test');
const rs = new ReadableStream({
cancel(error) {
assert_equals(error, cancelReason);
return delay(1);
}
});
return rs.cancel(cancelReason);
}, 'ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should fulfill when that one does (1)');
promise_test(t => {
let resolveSourceCancelPromise;
let sourceCancelPromiseHasFulfilled = false;
const rs = new ReadableStream({
cancel() {
const sourceCancelPromise = new Promise(resolve => resolveSourceCancelPromise = resolve);
sourceCancelPromise.then(() => {
sourceCancelPromiseHasFulfilled = true;
});
return sourceCancelPromise;
}
});
t.step_timeout(() => resolveSourceCancelPromise('Hello'), 1);
return rs.cancel().then(value => {
assert_true(sourceCancelPromiseHasFulfilled, 'cancel() return value should be fulfilled only after the promise returned by the underlying source\'s cancel');
assert_equals(value, undefined, 'cancel() return value should be fulfilled with undefined');
});
}, 'ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should fulfill when that one does (2)');
promise_test(t => {
let rejectSourceCancelPromise;
let sourceCancelPromiseHasRejected = false;
const rs = new ReadableStream({
cancel() {
const sourceCancelPromise = new Promise((resolve, reject) => rejectSourceCancelPromise = reject);
sourceCancelPromise.catch(() => {
sourceCancelPromiseHasRejected = true;
});
return sourceCancelPromise;
}
});
const errorInCancel = new Error('Sorry, it just wasn\'t meant to be.');
t.step_timeout(() => rejectSourceCancelPromise(errorInCancel), 1);
return rs.cancel().then(() => {
assert_unreached('cancel() return value should be rejected');
}, r => {
assert_true(sourceCancelPromiseHasRejected, 'cancel() return value should be rejected only after the promise returned by the underlying source\'s cancel');
assert_equals(r, errorInCancel, 'cancel() return value should be rejected with the underlying source\'s rejection reason');
});
}, 'ReadableStream cancellation: if the underlying source\'s cancel method returns a promise, the promise returned by the stream\'s cancel should reject when that one does');
promise_test(() => {
const rs = new ReadableStream({
start() {
return new Promise(() => {});
},
pull() {
assert_unreached('pull should not have been called');
}
});
return Promise.all([rs.cancel(), rs.getReader().closed]);
}, 'ReadableStream cancellation: cancelling before start finishes should prevent pull() from being called');