1// META: global=window,worker 2'use strict'; 3 4 5test(() => { 6 7 const theError = new Error('a unique string'); 8 9 assert_throws_exactly(theError, () => { 10 new ReadableStream({ 11 get start() { 12 throw theError; 13 } 14 }); 15 }, 'constructing the stream should re-throw the error'); 16 17}, 'Underlying source start: throwing getter'); 18 19 20test(() => { 21 22 const theError = new Error('a unique string'); 23 24 assert_throws_exactly(theError, () => { 25 new ReadableStream({ 26 start() { 27 throw theError; 28 } 29 }); 30 }, 'constructing the stream should re-throw the error'); 31 32}, 'Underlying source start: throwing method'); 33 34 35test(() => { 36 37 const theError = new Error('a unique string'); 38 assert_throws_exactly(theError, () => new ReadableStream({ 39 get pull() { 40 throw theError; 41 } 42 }), 'constructor should throw'); 43 44}, 'Underlying source: throwing pull getter (initial pull)'); 45 46 47promise_test(t => { 48 49 const theError = new Error('a unique string'); 50 const rs = new ReadableStream({ 51 pull() { 52 throw theError; 53 } 54 }); 55 56 return promise_rejects_exactly(t, theError, rs.getReader().closed); 57 58}, 'Underlying source: throwing pull method (initial pull)'); 59 60 61promise_test(t => { 62 63 const theError = new Error('a unique string'); 64 65 let counter = 0; 66 const rs = new ReadableStream({ 67 get pull() { 68 ++counter; 69 if (counter === 1) { 70 return c => c.enqueue('a'); 71 } 72 73 throw theError; 74 } 75 }); 76 const reader = rs.getReader(); 77 78 return Promise.all([ 79 reader.read().then(r => { 80 assert_object_equals(r, { value: 'a', done: false }, 'the first chunk read should be correct'); 81 }), 82 reader.read().then(r => { 83 assert_object_equals(r, { value: 'a', done: false }, 'the second chunk read should be correct'); 84 assert_equals(counter, 1, 'counter should be 1'); 85 }) 86 ]); 87 88}, 'Underlying source pull: throwing getter (second pull does not result in a second get)'); 89 90promise_test(t => { 91 92 const theError = new Error('a unique string'); 93 94 let counter = 0; 95 const rs = new ReadableStream({ 96 pull(c) { 97 ++counter; 98 if (counter === 1) { 99 c.enqueue('a'); 100 return; 101 } 102 103 throw theError; 104 } 105 }); 106 const reader = rs.getReader(); 107 108 return Promise.all([ 109 reader.read().then(r => { 110 assert_object_equals(r, { value: 'a', done: false }, 'the chunk read should be correct'); 111 }), 112 promise_rejects_exactly(t, theError, reader.closed) 113 ]); 114 115}, 'Underlying source pull: throwing method (second pull)'); 116 117test(() => { 118 119 const theError = new Error('a unique string'); 120 assert_throws_exactly(theError, () => new ReadableStream({ 121 get cancel() { 122 throw theError; 123 } 124 }), 'constructor should throw'); 125 126}, 'Underlying source cancel: throwing getter'); 127 128promise_test(t => { 129 130 const theError = new Error('a unique string'); 131 const rs = new ReadableStream({ 132 cancel() { 133 throw theError; 134 } 135 }); 136 137 return promise_rejects_exactly(t, theError, rs.cancel()); 138 139}, 'Underlying source cancel: throwing method'); 140 141promise_test(() => { 142 143 let controller; 144 const rs = new ReadableStream({ 145 start(c) { 146 controller = c; 147 } 148 }); 149 150 rs.cancel(); 151 assert_throws_js(TypeError, () => controller.enqueue('a'), 'Calling enqueue after canceling should throw'); 152 153 return rs.getReader().closed; 154 155}, 'Underlying source: calling enqueue on an empty canceled stream should throw'); 156 157promise_test(() => { 158 159 let controller; 160 const rs = new ReadableStream({ 161 start(c) { 162 c.enqueue('a'); 163 c.enqueue('b'); 164 controller = c; 165 } 166 }); 167 168 rs.cancel(); 169 assert_throws_js(TypeError, () => controller.enqueue('c'), 'Calling enqueue after canceling should throw'); 170 171 return rs.getReader().closed; 172 173}, 'Underlying source: calling enqueue on a non-empty canceled stream should throw'); 174 175promise_test(() => { 176 177 return new ReadableStream({ 178 start(c) { 179 c.close(); 180 assert_throws_js(TypeError, () => c.enqueue('a'), 'call to enqueue should throw a TypeError'); 181 } 182 }).getReader().closed; 183 184}, 'Underlying source: calling enqueue on a closed stream should throw'); 185 186promise_test(t => { 187 188 const theError = new Error('boo'); 189 const closed = new ReadableStream({ 190 start(c) { 191 c.error(theError); 192 assert_throws_js(TypeError, () => c.enqueue('a'), 'call to enqueue should throw the error'); 193 } 194 }).getReader().closed; 195 196 return promise_rejects_exactly(t, theError, closed); 197 198}, 'Underlying source: calling enqueue on an errored stream should throw'); 199 200promise_test(() => { 201 202 return new ReadableStream({ 203 start(c) { 204 c.close(); 205 assert_throws_js(TypeError, () => c.close(), 'second call to close should throw a TypeError'); 206 } 207 }).getReader().closed; 208 209}, 'Underlying source: calling close twice on an empty stream should throw the second time'); 210 211promise_test(() => { 212 213 let startCalled = false; 214 let readCalled = false; 215 const reader = new ReadableStream({ 216 start(c) { 217 c.enqueue('a'); 218 c.close(); 219 assert_throws_js(TypeError, () => c.close(), 'second call to close should throw a TypeError'); 220 startCalled = true; 221 } 222 }).getReader(); 223 224 return Promise.all([ 225 reader.read().then(r => { 226 assert_object_equals(r, { value: 'a', done: false }, 'read() should read the enqueued chunk'); 227 readCalled = true; 228 }), 229 reader.closed.then(() => { 230 assert_true(startCalled); 231 assert_true(readCalled); 232 }) 233 ]); 234 235}, 'Underlying source: calling close twice on a non-empty stream should throw the second time'); 236 237promise_test(() => { 238 239 let controller; 240 let startCalled = false; 241 const rs = new ReadableStream({ 242 start(c) { 243 controller = c; 244 startCalled = true; 245 } 246 }); 247 248 rs.cancel(); 249 assert_throws_js(TypeError, () => controller.close(), 'Calling close after canceling should throw'); 250 251 return rs.getReader().closed.then(() => { 252 assert_true(startCalled); 253 }); 254 255}, 'Underlying source: calling close on an empty canceled stream should throw'); 256 257promise_test(() => { 258 259 let controller; 260 let startCalled = false; 261 const rs = new ReadableStream({ 262 start(c) { 263 controller = c; 264 c.enqueue('a'); 265 startCalled = true; 266 } 267 }); 268 269 rs.cancel(); 270 assert_throws_js(TypeError, () => controller.close(), 'Calling close after canceling should throw'); 271 272 return rs.getReader().closed.then(() => { 273 assert_true(startCalled); 274 }); 275 276}, 'Underlying source: calling close on a non-empty canceled stream should throw'); 277 278promise_test(() => { 279 280 const theError = new Error('boo'); 281 let startCalled = false; 282 283 const closed = new ReadableStream({ 284 start(c) { 285 c.error(theError); 286 assert_throws_js(TypeError, () => c.close(), 'call to close should throw a TypeError'); 287 startCalled = true; 288 } 289 }).getReader().closed; 290 291 return closed.catch(e => { 292 assert_true(startCalled); 293 assert_equals(e, theError, 'closed should reject with the error'); 294 }); 295 296}, 'Underlying source: calling close after error should throw'); 297 298promise_test(() => { 299 300 const theError = new Error('boo'); 301 let startCalled = false; 302 303 const closed = new ReadableStream({ 304 start(c) { 305 c.error(theError); 306 c.error(); 307 startCalled = true; 308 } 309 }).getReader().closed; 310 311 return closed.catch(e => { 312 assert_true(startCalled); 313 assert_equals(e, theError, 'closed should reject with the error'); 314 }); 315 316}, 'Underlying source: calling error twice should not throw'); 317 318promise_test(() => { 319 320 let startCalled = false; 321 322 const closed = new ReadableStream({ 323 start(c) { 324 c.close(); 325 c.error(); 326 startCalled = true; 327 } 328 }).getReader().closed; 329 330 return closed.then(() => assert_true(startCalled)); 331 332}, 'Underlying source: calling error after close should not throw'); 333 334promise_test(() => { 335 336 let startCalled = false; 337 const firstError = new Error('1'); 338 const secondError = new Error('2'); 339 340 const closed = new ReadableStream({ 341 start(c) { 342 c.error(firstError); 343 startCalled = true; 344 return Promise.reject(secondError); 345 } 346 }).getReader().closed; 347 348 return closed.catch(e => { 349 assert_true(startCalled); 350 assert_equals(e, firstError, 'closed should reject with the first error'); 351 }); 352 353}, 'Underlying source: calling error and returning a rejected promise from start should cause the stream to error ' + 354 'with the first error'); 355 356promise_test(() => { 357 358 let startCalled = false; 359 const firstError = new Error('1'); 360 const secondError = new Error('2'); 361 362 const closed = new ReadableStream({ 363 pull(c) { 364 c.error(firstError); 365 startCalled = true; 366 return Promise.reject(secondError); 367 } 368 }).getReader().closed; 369 370 return closed.catch(e => { 371 assert_true(startCalled); 372 assert_equals(e, firstError, 'closed should reject with the first error'); 373 }); 374 375}, 'Underlying source: calling error and returning a rejected promise from pull should cause the stream to error ' + 376 'with the first error'); 377 378const error1 = { name: 'error1' }; 379 380promise_test(t => { 381 382 let pullShouldThrow = false; 383 const rs = new ReadableStream({ 384 pull(controller) { 385 if (pullShouldThrow) { 386 throw error1; 387 } 388 controller.enqueue(0); 389 } 390 }, new CountQueuingStrategy({highWaterMark: 1})); 391 const reader = rs.getReader(); 392 return Promise.resolve().then(() => { 393 pullShouldThrow = true; 394 return Promise.all([ 395 reader.read(), 396 promise_rejects_exactly(t, error1, reader.closed, '.closed promise should reject') 397 ]); 398 }); 399 400}, 'read should not error if it dequeues and pull() throws'); 401