• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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