| // Flags: --expose-internals --no-warnings |
| 'use strict'; |
| |
| const common = require('../common'); |
| const assert = require('assert'); |
| |
| const { |
| WritableStream, |
| WritableStreamDefaultController, |
| WritableStreamDefaultWriter, |
| CountQueuingStrategy, |
| } = require('stream/web'); |
| |
| const { |
| kState, |
| } = require('internal/webstreams/util'); |
| |
| const { |
| isPromise, |
| } = require('util/types'); |
| |
| const { |
| kTransfer, |
| } = require('internal/worker/js_transferable'); |
| |
| const { |
| inspect, |
| } = require('util'); |
| |
| class Sink { |
| constructor() { |
| this.chunks = []; |
| } |
| |
| start() { |
| this.started = true; |
| } |
| |
| write(chunk) { |
| this.chunks.push(chunk); |
| } |
| |
| close() { |
| this.closed = true; |
| } |
| |
| abort() { |
| this.aborted = true; |
| } |
| } |
| |
| { |
| const stream = new WritableStream(); |
| |
| assert(stream[kState].controller instanceof WritableStreamDefaultController); |
| assert(!stream.locked); |
| |
| assert.strictEqual(typeof stream.abort, 'function'); |
| assert.strictEqual(typeof stream.close, 'function'); |
| assert.strictEqual(typeof stream.getWriter, 'function'); |
| } |
| |
| ['a', false, 1, null].forEach((sink) => { |
| assert.throws(() => new WritableStream(sink), { |
| code: 'ERR_INVALID_ARG_TYPE', |
| }); |
| }); |
| |
| ['a', false, 1].forEach((strategy) => { |
| assert.throws(() => new WritableStream({}, strategy), { |
| code: 'ERR_INVALID_ARG_TYPE', |
| }); |
| }); |
| |
| [1, false, ''].forEach((type) => { |
| assert.throws(() => new WritableStream({ type }), { |
| code: 'ERR_INVALID_ARG_VALUE', |
| }); |
| }); |
| |
| ['a', {}].forEach((highWaterMark) => { |
| assert.throws(() => new WritableStream({}, { highWaterMark }), { |
| code: 'ERR_INVALID_ARG_VALUE', |
| }); |
| }); |
| |
| ['a', false, {}].forEach((size) => { |
| assert.throws(() => new WritableStream({}, { size }), { |
| code: 'ERR_INVALID_ARG_TYPE', |
| }); |
| }); |
| |
| { |
| new WritableStream({}); |
| new WritableStream([]); |
| new WritableStream({}, null); |
| new WritableStream({}, {}); |
| new WritableStream({}, []); |
| } |
| |
| { |
| const sink = new Sink(); |
| const stream = new WritableStream( |
| sink, |
| new CountQueuingStrategy({ highWaterMark: 1 })); |
| |
| assert(!stream.locked); |
| const writer = stream.getWriter(); |
| assert(stream.locked); |
| assert(writer instanceof WritableStreamDefaultWriter); |
| |
| assert(isPromise(writer.closed)); |
| assert(isPromise(writer.ready)); |
| assert(typeof writer.desiredSize, 'number'); |
| assert(typeof writer.abort, 'function'); |
| assert(typeof writer.close, 'function'); |
| assert(typeof writer.releaseLock, 'function'); |
| assert(typeof writer.write, 'function'); |
| |
| writer.releaseLock(); |
| assert(!stream.locked); |
| |
| const writer2 = stream.getWriter(); |
| |
| assert(sink.started); |
| |
| writer2.closed.then(common.mustCall()); |
| writer2.ready.then(common.mustCall()); |
| |
| writer2.close().then(common.mustCall(() => { |
| assert.strict(sink.closed); |
| })); |
| } |
| |
| { |
| const sink = new Sink(); |
| |
| const stream = new WritableStream( |
| sink, |
| new CountQueuingStrategy({ highWaterMark: 1 })); |
| |
| const error = new Error('boom'); |
| |
| const writer = stream.getWriter(); |
| |
| assert.rejects(writer.closed, error).then(common.mustCall()); |
| |
| writer.abort(error).then(common.mustCall(() => { |
| assert.strictEqual(stream[kState].state, 'errored'); |
| assert(sink.aborted); |
| })); |
| } |
| |
| { |
| const sink = new Sink(); |
| |
| const stream = new WritableStream( |
| sink, { highWaterMark: 1 } |
| ); |
| |
| async function write(stream) { |
| const writer = stream.getWriter(); |
| const p = writer.write('hello'); |
| assert.strictEqual(writer.desiredSize, 0); |
| await p; |
| assert.strictEqual(writer.desiredSize, 1); |
| } |
| |
| write(stream).then(common.mustCall(() => { |
| assert.deepStrictEqual(['hello'], sink.chunks); |
| })); |
| } |
| |
| { |
| assert.throws(() => Reflect.get(WritableStream.prototype, 'locked', {}), { |
| code: 'ERR_INVALID_THIS', |
| }); |
| assert.rejects(() => WritableStream.prototype.abort({}), { |
| code: 'ERR_INVALID_THIS', |
| }).then(common.mustCall()); |
| assert.rejects(() => WritableStream.prototype.close({}), { |
| code: 'ERR_INVALID_THIS', |
| }).then(common.mustCall()); |
| assert.throws(() => WritableStream.prototype.getWriter.call(), { |
| code: 'ERR_INVALID_THIS', |
| }); |
| assert.throws(() => WritableStream.prototype[kTransfer].call(), { |
| code: 'ERR_INVALID_THIS', |
| }); |
| assert.rejects( |
| Reflect.get(WritableStreamDefaultWriter.prototype, 'closed'), { |
| code: 'ERR_INVALID_THIS', |
| }).then(common.mustCall()); |
| assert.rejects( |
| Reflect.get(WritableStreamDefaultWriter.prototype, 'ready'), { |
| code: 'ERR_INVALID_THIS', |
| }).then(common.mustCall()); |
| assert.throws( |
| () => Reflect.get(WritableStreamDefaultWriter.prototype, 'desiredSize'), { |
| code: 'ERR_INVALID_THIS', |
| }); |
| assert.rejects(WritableStreamDefaultWriter.prototype.abort({}), { |
| code: 'ERR_INVALID_THIS', |
| }).then(common.mustCall()); |
| assert.rejects(WritableStreamDefaultWriter.prototype.close({}), { |
| code: 'ERR_INVALID_THIS', |
| }).then(common.mustCall()); |
| assert.rejects(WritableStreamDefaultWriter.prototype.write({}), { |
| code: 'ERR_INVALID_THIS', |
| }).then(common.mustCall()); |
| assert.throws(() => WritableStreamDefaultWriter.prototype.releaseLock({}), { |
| code: 'ERR_INVALID_THIS', |
| }); |
| |
| assert.throws(() => { |
| Reflect.get(WritableStreamDefaultController.prototype, 'signal', {}); |
| }, { |
| code: 'ERR_INVALID_THIS', |
| }); |
| |
| assert.throws(() => { |
| WritableStreamDefaultController.prototype.error({}); |
| }, { |
| code: 'ERR_INVALID_THIS', |
| }); |
| } |
| |
| { |
| let controller; |
| const writable = new WritableStream({ |
| start(c) { controller = c; } |
| }); |
| assert.strictEqual( |
| inspect(writable), |
| 'WritableStream { locked: false, state: \'writable\' }'); |
| assert.strictEqual( |
| inspect(writable, { depth: null }), |
| 'WritableStream { locked: false, state: \'writable\' }'); |
| assert.strictEqual( |
| inspect(writable, { depth: 0 }), |
| 'WritableStream [Object]'); |
| |
| const writer = writable.getWriter(); |
| assert.match( |
| inspect(writer), |
| /WritableStreamDefaultWriter/); |
| assert.match( |
| inspect(writer, { depth: null }), |
| /WritableStreamDefaultWriter/); |
| assert.match( |
| inspect(writer, { depth: 0 }), |
| /WritableStreamDefaultWriter \[/); |
| |
| assert.match( |
| inspect(controller), |
| /WritableStreamDefaultController/); |
| assert.match( |
| inspect(controller, { depth: null }), |
| /WritableStreamDefaultController/); |
| assert.match( |
| inspect(controller, { depth: 0 }), |
| /WritableStreamDefaultController \[/); |
| |
| writer.abort(new Error('boom')); |
| |
| assert.strictEqual(writer.desiredSize, null); |
| setImmediate(() => assert.strictEqual(writer.desiredSize, null)); |
| } |