1// META: global=window,worker 2// META: script=../resources/test-utils.js 3// META: script=../resources/recording-streams.js 4'use strict'; 5 6const error1 = { name: 'error1' }; 7 8promise_test(() => { 9 let resolveStartPromise; 10 const ws = recordingWritableStream({ 11 start() { 12 return new Promise(resolve => { 13 resolveStartPromise = resolve; 14 }); 15 } 16 }); 17 18 const writer = ws.getWriter(); 19 20 assert_equals(writer.desiredSize, 1, 'desiredSize should be 1'); 21 writer.write('a'); 22 assert_equals(writer.desiredSize, 0, 'desiredSize should be 0 after writer.write()'); 23 24 // Wait and verify that write isn't called. 25 return flushAsyncEvents() 26 .then(() => { 27 assert_array_equals(ws.events, [], 'write should not be called until start promise resolves'); 28 resolveStartPromise(); 29 return writer.ready; 30 }) 31 .then(() => assert_array_equals(ws.events, ['write', 'a'], 32 'write should not be called until start promise resolves')); 33}, 'underlying sink\'s write should not be called until start finishes'); 34 35promise_test(() => { 36 let resolveStartPromise; 37 const ws = recordingWritableStream({ 38 start() { 39 return new Promise(resolve => { 40 resolveStartPromise = resolve; 41 }); 42 } 43 }); 44 45 const writer = ws.getWriter(); 46 47 writer.close(); 48 assert_equals(writer.desiredSize, 1, 'desiredSize should be 1'); 49 50 // Wait and verify that write isn't called. 51 return flushAsyncEvents().then(() => { 52 assert_array_equals(ws.events, [], 'close should not be called until start promise resolves'); 53 resolveStartPromise(); 54 return writer.closed; 55 }); 56}, 'underlying sink\'s close should not be called until start finishes'); 57 58test(() => { 59 const passedError = new Error('horrible things'); 60 61 let writeCalled = false; 62 let closeCalled = false; 63 assert_throws_exactly(passedError, () => { 64 // recordingWritableStream cannot be used here because the exception in the 65 // constructor prevents assigning the object to a variable. 66 new WritableStream({ 67 start() { 68 throw passedError; 69 }, 70 write() { 71 writeCalled = true; 72 }, 73 close() { 74 closeCalled = true; 75 } 76 }); 77 }, 'constructor should throw passedError'); 78 assert_false(writeCalled, 'write should not be called'); 79 assert_false(closeCalled, 'close should not be called'); 80}, 'underlying sink\'s write or close should not be called if start throws'); 81 82promise_test(() => { 83 const ws = recordingWritableStream({ 84 start() { 85 return Promise.reject(); 86 } 87 }); 88 89 // Wait and verify that write or close aren't called. 90 return flushAsyncEvents() 91 .then(() => assert_array_equals(ws.events, [], 'write and close should not be called')); 92}, 'underlying sink\'s write or close should not be invoked if the promise returned by start is rejected'); 93 94promise_test(t => { 95 const ws = new WritableStream({ 96 start() { 97 return { 98 then(onFulfilled, onRejected) { onRejected(error1); } 99 }; 100 } 101 }); 102 return promise_rejects_exactly(t, error1, ws.getWriter().closed, 'closed promise should be rejected'); 103}, 'returning a thenable from start() should work'); 104 105promise_test(t => { 106 const ws = recordingWritableStream({ 107 start(controller) { 108 controller.error(error1); 109 } 110 }); 111 return promise_rejects_exactly(t, error1, ws.getWriter().write('a'), 'write() should reject with the error') 112 .then(() => { 113 assert_array_equals(ws.events, [], 'sink write() should not have been called'); 114 }); 115}, 'controller.error() during start should cause writes to fail'); 116 117promise_test(t => { 118 let controller; 119 let resolveStart; 120 const ws = recordingWritableStream({ 121 start(c) { 122 controller = c; 123 return new Promise(resolve => { 124 resolveStart = resolve; 125 }); 126 } 127 }); 128 const writer = ws.getWriter(); 129 const writePromise = writer.write('a'); 130 const closePromise = writer.close(); 131 controller.error(error1); 132 resolveStart(); 133 return Promise.all([ 134 promise_rejects_exactly(t, error1, writePromise, 'write() should fail'), 135 promise_rejects_exactly(t, error1, closePromise, 'close() should fail') 136 ]).then(() => { 137 assert_array_equals(ws.events, [], 'sink write() and close() should not have been called'); 138 }); 139}, 'controller.error() during async start should cause existing writes to fail'); 140 141promise_test(t => { 142 const events = []; 143 const promises = []; 144 function catchAndRecord(promise, name) { 145 promises.push(promise.then(t.unreached_func(`promise ${name} should not resolve`), 146 () => { 147 events.push(name); 148 })); 149 } 150 const ws = new WritableStream({ 151 start() { 152 return Promise.reject(); 153 } 154 }, { highWaterMark: 0 }); 155 const writer = ws.getWriter(); 156 catchAndRecord(writer.ready, 'ready'); 157 catchAndRecord(writer.closed, 'closed'); 158 catchAndRecord(writer.write(), 'write'); 159 return Promise.all(promises) 160 .then(() => { 161 assert_array_equals(events, ['ready', 'write', 'closed'], 'promises should reject in standard order'); 162 }); 163}, 'when start() rejects, writer promises should reject in standard order'); 164