Sync web-platform-tests up to revision a5b95cb31914507088a4eda16f7674bbc6f3313f
[WebKit-https.git] / LayoutTests / imported / w3c / web-platform-tests / streams / readable-streams / cancel.js
1 'use strict';
2
3 if (self.importScripts) {
4   self.importScripts('../resources/test-utils.js');
5   self.importScripts('../resources/rs-utils.js');
6   self.importScripts('/resources/testharness.js');
7 }
8
9 promise_test(() => {
10
11   const randomSource = new RandomPushSource();
12
13   let cancellationFinished = false;
14   const rs = new ReadableStream({
15     start(c) {
16       randomSource.ondata = c.enqueue.bind(c);
17       randomSource.onend = c.close.bind(c);
18       randomSource.onerror = c.error.bind(c);
19     },
20
21     pull() {
22       randomSource.readStart();
23     },
24
25     cancel() {
26       randomSource.readStop();
27
28       return new Promise(resolve => {
29         setTimeout(() => {
30           cancellationFinished = true;
31           resolve();
32         }, 1);
33       });
34     }
35   });
36
37   const reader = rs.getReader();
38
39   // We call delay multiple times to avoid cancelling too early for the
40   // source to enqueue at least one chunk.
41   const cancel = delay(5).then(() => delay(5)).then(() => delay(5)).then(() => {
42     const cancelPromise = reader.cancel();
43     assert_false(cancellationFinished, 'cancellation in source should happen later');
44     return cancelPromise;
45   });
46
47   return readableStreamToArray(rs, reader).then(chunks => {
48     assert_greater_than(chunks.length, 0, 'at least one chunk should be read');
49     for (let i = 0; i < chunks.length; i++) {
50       assert_equals(chunks[i].length, 128, 'chunk ' + i + ' should have 128 bytes');
51     }
52     return cancel;
53   }).then(() => {
54     assert_true(cancellationFinished, 'it returns a promise that is fulfilled when the cancellation finishes');
55   });
56
57 }, 'ReadableStream cancellation: integration test on an infinite stream derived from a random push source');
58
59 test(() => {
60
61   let recordedReason;
62   const rs = new ReadableStream({
63     cancel(reason) {
64       recordedReason = reason;
65     }
66   });
67
68   const passedReason = new Error('Sorry, it just wasn\'t meant to be.');
69   rs.cancel(passedReason);
70
71   assert_equals(recordedReason, passedReason,
72     'the error passed to the underlying source\'s cancel method should equal the one passed to the stream\'s cancel');
73
74 }, 'ReadableStream cancellation: cancel(reason) should pass through the given reason to the underlying source');
75
76 promise_test(() => {
77
78   const rs = new ReadableStream({
79     start(c) {
80       c.enqueue('a');
81       c.close();
82     },
83     cancel() {
84       assert_unreached('underlying source cancel() should not have been called');
85     }
86   });
87
88   const reader = rs.getReader();
89
90   return rs.cancel().then(() => {
91     assert_unreached('cancel() should be rejected');
92   }, e => {
93     assert_equals(e.name, 'TypeError', 'cancel() should be rejected with a TypeError');
94   }).then(() => {
95     return reader.read();
96   }).then(result => {
97     assert_object_equals(result, { value: 'a', done: false }, 'read() should still work after the attempted cancel');
98     return reader.closed;
99   });
100
101 }, 'ReadableStream cancellation: cancel() on a locked stream should fail and not call the underlying source cancel');
102
103 promise_test(() => {
104
105   let cancelReceived = false;
106   const cancelReason = new Error('I am tired of this stream, I prefer to cancel it');
107   const rs = new ReadableStream({
108     cancel(reason) {
109       cancelReceived = true;
110       assert_equals(reason, cancelReason, 'cancellation reason given to the underlying source should be equal to the one passed');
111     }
112   });
113
114   return rs.cancel(cancelReason).then(() => {
115     assert_true(cancelReceived);
116   });
117
118 }, 'ReadableStream cancellation: should fulfill promise when cancel callback went fine');
119
120 promise_test(() => {
121
122   const rs = new ReadableStream({
123     cancel() {
124       return 'Hello';
125     }
126   });
127
128   return rs.cancel().then(v => {
129     assert_equals(v, undefined, 'cancel() return value should be fulfilled with undefined');
130   });
131
132 }, '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');
133
134 promise_test(() => {
135
136   const thrownError = new Error('test');
137   let cancelCalled = false;
138
139   const rs = new ReadableStream({
140     cancel() {
141       cancelCalled = true;
142       throw thrownError;
143     }
144   });
145
146   return rs.cancel('test').then(() => {
147     assert_unreached('cancel should reject');
148   }, e => {
149     assert_true(cancelCalled);
150     assert_equals(e, thrownError);
151   });
152
153 }, 'ReadableStream cancellation: should reject promise when cancel callback raises an exception');
154
155 promise_test(() => {
156
157   const cancelReason = new Error('test');
158
159   const rs = new ReadableStream({
160     cancel(error) {
161       assert_equals(error, cancelReason);
162       return delay(1);
163     }
164   });
165
166   return rs.cancel(cancelReason);
167
168 }, '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)');
169
170 promise_test(() => {
171
172   let resolveSourceCancelPromise;
173   let sourceCancelPromiseHasFulfilled = false;
174
175   const rs = new ReadableStream({
176     cancel() {
177       const sourceCancelPromise = new Promise(resolve => resolveSourceCancelPromise = resolve);
178
179       sourceCancelPromise.then(() => {
180         sourceCancelPromiseHasFulfilled = true;
181       });
182
183       return sourceCancelPromise;
184     }
185   });
186
187   setTimeout(() => resolveSourceCancelPromise('Hello'), 1);
188
189   return rs.cancel().then(value => {
190     assert_true(sourceCancelPromiseHasFulfilled, 'cancel() return value should be fulfilled only after the promise returned by the underlying source\'s cancel');
191     assert_equals(value, undefined, 'cancel() return value should be fulfilled with undefined');
192   });
193
194 }, '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)');
195
196 promise_test(() => {
197
198   let rejectSourceCancelPromise;
199   let sourceCancelPromiseHasRejected = false;
200
201   const rs = new ReadableStream({
202     cancel() {
203       const sourceCancelPromise = new Promise((resolve, reject) => rejectSourceCancelPromise = reject);
204
205       sourceCancelPromise.catch(() => {
206         sourceCancelPromiseHasRejected = true;
207       });
208
209       return sourceCancelPromise;
210     }
211   });
212
213   const errorInCancel = new Error('Sorry, it just wasn\'t meant to be.');
214
215   setTimeout(() => rejectSourceCancelPromise(errorInCancel), 1);
216
217   return rs.cancel().then(() => {
218     assert_unreached('cancel() return value should be rejected');
219   }, r => {
220     assert_true(sourceCancelPromiseHasRejected, 'cancel() return value should be rejected only after the promise returned by the underlying source\'s cancel');
221     assert_equals(r, errorInCancel, 'cancel() return value should be rejected with the underlying source\'s rejection reason');
222   });
223
224 }, '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');
225
226 promise_test(() => {
227
228   const rs = new ReadableStream({
229     start() {
230       return new Promise(() => {});
231     },
232     pull() {
233       assert_unreached('pull should not have been called');
234     }
235   });
236
237   return Promise.all([rs.cancel(), rs.getReader().closed]);
238
239 }, 'ReadableStream cancellation: cancelling before start finishes should prevent pull() from being called');
240
241 done();