1// Flags: --expose-internals --no-warnings 2'use strict'; 3 4const common = require('../common'); 5const assert = require('assert'); 6 7const { 8 WritableStream, 9 WritableStreamDefaultController, 10 WritableStreamDefaultWriter, 11 CountQueuingStrategy, 12} = require('stream/web'); 13 14const { 15 kState, 16} = require('internal/webstreams/util'); 17 18const { 19 isPromise, 20} = require('util/types'); 21 22const { 23 kTransfer, 24} = require('internal/worker/js_transferable'); 25 26const { 27 inspect, 28} = require('util'); 29 30class Sink { 31 constructor() { 32 this.chunks = []; 33 } 34 35 start() { 36 this.started = true; 37 } 38 39 write(chunk) { 40 this.chunks.push(chunk); 41 } 42 43 close() { 44 this.closed = true; 45 } 46 47 abort() { 48 this.aborted = true; 49 } 50} 51 52{ 53 const stream = new WritableStream(); 54 55 assert(stream[kState].controller instanceof WritableStreamDefaultController); 56 assert(!stream.locked); 57 58 assert.strictEqual(typeof stream.abort, 'function'); 59 assert.strictEqual(typeof stream.close, 'function'); 60 assert.strictEqual(typeof stream.getWriter, 'function'); 61} 62 63[1, false, ''].forEach((type) => { 64 assert.throws(() => new WritableStream({ type }), { 65 code: 'ERR_INVALID_ARG_VALUE', 66 }); 67}); 68 69['a', {}].forEach((highWaterMark) => { 70 assert.throws(() => new WritableStream({}, { highWaterMark }), { 71 code: 'ERR_INVALID_ARG_VALUE', 72 }); 73}); 74 75['a', false, {}].forEach((size) => { 76 assert.throws(() => new WritableStream({}, { size }), { 77 code: 'ERR_INVALID_ARG_TYPE', 78 }); 79}); 80 81{ 82 new WritableStream({}, 1); 83 new WritableStream({}, 'a'); 84 new WritableStream({}, null); 85} 86 87{ 88 const sink = new Sink(); 89 const stream = new WritableStream( 90 sink, 91 new CountQueuingStrategy({ highWaterMark: 1 })); 92 93 assert(!stream.locked); 94 const writer = stream.getWriter(); 95 assert(stream.locked); 96 assert(writer instanceof WritableStreamDefaultWriter); 97 98 assert(isPromise(writer.closed)); 99 assert(isPromise(writer.ready)); 100 assert(typeof writer.desiredSize, 'number'); 101 assert(typeof writer.abort, 'function'); 102 assert(typeof writer.close, 'function'); 103 assert(typeof writer.releaseLock, 'function'); 104 assert(typeof writer.write, 'function'); 105 106 writer.releaseLock(); 107 assert(!stream.locked); 108 109 const writer2 = stream.getWriter(); 110 111 assert(sink.started); 112 113 writer2.closed.then(common.mustCall()); 114 writer2.ready.then(common.mustCall()); 115 116 writer2.close().then(common.mustCall(() => { 117 assert.strict(sink.closed); 118 })); 119} 120 121{ 122 const sink = new Sink(); 123 124 const stream = new WritableStream( 125 sink, 126 new CountQueuingStrategy({ highWaterMark: 1 })); 127 128 const error = new Error('boom'); 129 130 const writer = stream.getWriter(); 131 132 assert.rejects(writer.closed, error); 133 134 writer.abort(error).then(common.mustCall(() => { 135 assert.strictEqual(stream[kState].state, 'errored'); 136 assert(sink.aborted); 137 })); 138} 139 140{ 141 const sink = new Sink(); 142 143 const stream = new WritableStream( 144 sink, { highWaterMark: 1 } 145 ); 146 147 async function write(stream) { 148 const writer = stream.getWriter(); 149 const p = writer.write('hello'); 150 assert.strictEqual(writer.desiredSize, 0); 151 await p; 152 assert.strictEqual(writer.desiredSize, 1); 153 } 154 155 write(stream).then(common.mustCall(() => { 156 assert.deepStrictEqual(['hello'], sink.chunks); 157 })); 158} 159 160{ 161 assert.throws(() => Reflect.get(WritableStream.prototype, 'locked', {}), { 162 code: 'ERR_INVALID_THIS', 163 }); 164 assert.rejects(() => WritableStream.prototype.abort({}), { 165 code: 'ERR_INVALID_THIS', 166 }); 167 assert.rejects(() => WritableStream.prototype.close({}), { 168 code: 'ERR_INVALID_THIS', 169 }); 170 assert.throws(() => WritableStream.prototype.getWriter.call(), { 171 code: 'ERR_INVALID_THIS', 172 }); 173 assert.throws(() => WritableStream.prototype[kTransfer].call(), { 174 code: 'ERR_INVALID_THIS', 175 }); 176 assert.rejects( 177 Reflect.get(WritableStreamDefaultWriter.prototype, 'closed'), { 178 code: 'ERR_INVALID_THIS', 179 }); 180 assert.rejects( 181 Reflect.get(WritableStreamDefaultWriter.prototype, 'ready'), { 182 code: 'ERR_INVALID_THIS', 183 }); 184 assert.throws( 185 () => Reflect.get(WritableStreamDefaultWriter.prototype, 'desiredSize'), { 186 code: 'ERR_INVALID_THIS', 187 }); 188 assert.rejects(WritableStreamDefaultWriter.prototype.abort({}), { 189 code: 'ERR_INVALID_THIS', 190 }); 191 assert.rejects(WritableStreamDefaultWriter.prototype.close({}), { 192 code: 'ERR_INVALID_THIS', 193 }); 194 assert.rejects(WritableStreamDefaultWriter.prototype.write({}), { 195 code: 'ERR_INVALID_THIS', 196 }); 197 assert.throws(() => WritableStreamDefaultWriter.prototype.releaseLock({}), { 198 code: 'ERR_INVALID_THIS', 199 }); 200 201 assert.throws(() => { 202 Reflect.get(WritableStreamDefaultController.prototype, 'signal', {}); 203 }, { 204 code: 'ERR_INVALID_THIS', 205 }); 206 207 assert.throws(() => { 208 WritableStreamDefaultController.prototype.error({}); 209 }, { 210 code: 'ERR_INVALID_THIS', 211 }); 212} 213 214{ 215 let controller; 216 const writable = new WritableStream({ 217 start(c) { controller = c; } 218 }); 219 assert.strictEqual( 220 inspect(writable), 221 'WritableStream { locked: false, state: \'writable\' }'); 222 assert.strictEqual( 223 inspect(writable, { depth: null }), 224 'WritableStream { locked: false, state: \'writable\' }'); 225 assert.strictEqual( 226 inspect(writable, { depth: 0 }), 227 'WritableStream [Object]'); 228 229 const writer = writable.getWriter(); 230 assert.match( 231 inspect(writer), 232 /WritableStreamDefaultWriter/); 233 assert.match( 234 inspect(writer, { depth: null }), 235 /WritableStreamDefaultWriter/); 236 assert.match( 237 inspect(writer, { depth: 0 }), 238 /WritableStreamDefaultWriter \[/); 239 240 assert.match( 241 inspect(controller), 242 /WritableStreamDefaultController/); 243 assert.match( 244 inspect(controller, { depth: null }), 245 /WritableStreamDefaultController/); 246 assert.match( 247 inspect(controller, { depth: 0 }), 248 /WritableStreamDefaultController \[/); 249 250 writer.abort(new Error('boom')); 251 252 assert.strictEqual(writer.desiredSize, null); 253 setImmediate(() => assert.strictEqual(writer.desiredSize, null)); 254} 255