11cb0ef41Sopenharmony_ci// META: global=window,worker
21cb0ef41Sopenharmony_ci// META: script=../resources/test-utils.js
31cb0ef41Sopenharmony_ci// META: script=../resources/recording-streams.js
41cb0ef41Sopenharmony_ci'use strict';
51cb0ef41Sopenharmony_ci
61cb0ef41Sopenharmony_ciconst error1 = new Error('error1');
71cb0ef41Sopenharmony_cierror1.name = 'error1';
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ciconst error2 = new Error('error2');
101cb0ef41Sopenharmony_cierror2.name = 'error2';
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_cifunction writeArrayToStream(array, writableStreamWriter) {
131cb0ef41Sopenharmony_ci  array.forEach(chunk => writableStreamWriter.write(chunk));
141cb0ef41Sopenharmony_ci  return writableStreamWriter.close();
151cb0ef41Sopenharmony_ci}
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_cipromise_test(() => {
181cb0ef41Sopenharmony_ci  let storage;
191cb0ef41Sopenharmony_ci  const ws = new WritableStream({
201cb0ef41Sopenharmony_ci    start() {
211cb0ef41Sopenharmony_ci      storage = [];
221cb0ef41Sopenharmony_ci    },
231cb0ef41Sopenharmony_ci
241cb0ef41Sopenharmony_ci    write(chunk) {
251cb0ef41Sopenharmony_ci      return delay(0).then(() => storage.push(chunk));
261cb0ef41Sopenharmony_ci    },
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci    close() {
291cb0ef41Sopenharmony_ci      return delay(0);
301cb0ef41Sopenharmony_ci    }
311cb0ef41Sopenharmony_ci  });
321cb0ef41Sopenharmony_ci
331cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_ci  const input = [1, 2, 3, 4, 5];
361cb0ef41Sopenharmony_ci  return writeArrayToStream(input, writer)
371cb0ef41Sopenharmony_ci      .then(() => assert_array_equals(storage, input, 'correct data should be relayed to underlying sink'));
381cb0ef41Sopenharmony_ci}, 'WritableStream should complete asynchronous writes before close resolves');
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_cipromise_test(() => {
411cb0ef41Sopenharmony_ci  const ws = recordingWritableStream();
421cb0ef41Sopenharmony_ci
431cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci  const input = [1, 2, 3, 4, 5];
461cb0ef41Sopenharmony_ci  return writeArrayToStream(input, writer)
471cb0ef41Sopenharmony_ci      .then(() => assert_array_equals(ws.events, ['write', 1, 'write', 2, 'write', 3, 'write', 4, 'write', 5, 'close'],
481cb0ef41Sopenharmony_ci                                      'correct data should be relayed to underlying sink'));
491cb0ef41Sopenharmony_ci}, 'WritableStream should complete synchronous writes before close resolves');
501cb0ef41Sopenharmony_ci
511cb0ef41Sopenharmony_cipromise_test(() => {
521cb0ef41Sopenharmony_ci  const ws = new WritableStream({
531cb0ef41Sopenharmony_ci    write() {
541cb0ef41Sopenharmony_ci      return 'Hello';
551cb0ef41Sopenharmony_ci    }
561cb0ef41Sopenharmony_ci  });
571cb0ef41Sopenharmony_ci
581cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci  const writePromise = writer.write('a');
611cb0ef41Sopenharmony_ci  return writePromise
621cb0ef41Sopenharmony_ci      .then(value => assert_equals(value, undefined, 'fulfillment value must be undefined'));
631cb0ef41Sopenharmony_ci}, 'fulfillment value of ws.write() call should be undefined even if the underlying sink returns a non-undefined ' +
641cb0ef41Sopenharmony_ci    'value');
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_cipromise_test(() => {
671cb0ef41Sopenharmony_ci  let resolveSinkWritePromise;
681cb0ef41Sopenharmony_ci  const ws = new WritableStream({
691cb0ef41Sopenharmony_ci    write() {
701cb0ef41Sopenharmony_ci      return new Promise(resolve => {
711cb0ef41Sopenharmony_ci        resolveSinkWritePromise = resolve;
721cb0ef41Sopenharmony_ci      });
731cb0ef41Sopenharmony_ci    }
741cb0ef41Sopenharmony_ci  });
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
771cb0ef41Sopenharmony_ci
781cb0ef41Sopenharmony_ci  assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ci  return writer.ready.then(() => {
811cb0ef41Sopenharmony_ci    const writePromise = writer.write('a');
821cb0ef41Sopenharmony_ci    let writePromiseResolved = false;
831cb0ef41Sopenharmony_ci    assert_not_equals(resolveSinkWritePromise, undefined, 'resolveSinkWritePromise should not be undefined');
841cb0ef41Sopenharmony_ci
851cb0ef41Sopenharmony_ci    assert_equals(writer.desiredSize, 0, 'desiredSize should be 0 after writer.write()');
861cb0ef41Sopenharmony_ci
871cb0ef41Sopenharmony_ci    return Promise.all([
881cb0ef41Sopenharmony_ci      writePromise.then(value => {
891cb0ef41Sopenharmony_ci        writePromiseResolved = true;
901cb0ef41Sopenharmony_ci        assert_equals(resolveSinkWritePromise, undefined, 'sinkWritePromise should be fulfilled before writePromise');
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci        assert_equals(value, undefined, 'writePromise should be fulfilled with undefined');
931cb0ef41Sopenharmony_ci      }),
941cb0ef41Sopenharmony_ci      writer.ready.then(value => {
951cb0ef41Sopenharmony_ci        assert_equals(resolveSinkWritePromise, undefined, 'sinkWritePromise should be fulfilled before writer.ready');
961cb0ef41Sopenharmony_ci        assert_true(writePromiseResolved, 'writePromise should be fulfilled before writer.ready');
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci        assert_equals(writer.desiredSize, 1, 'desiredSize should be 1 again');
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci        assert_equals(value, undefined, 'writePromise should be fulfilled with undefined');
1011cb0ef41Sopenharmony_ci      }),
1021cb0ef41Sopenharmony_ci      flushAsyncEvents().then(() => {
1031cb0ef41Sopenharmony_ci        resolveSinkWritePromise();
1041cb0ef41Sopenharmony_ci        resolveSinkWritePromise = undefined;
1051cb0ef41Sopenharmony_ci      })
1061cb0ef41Sopenharmony_ci    ]);
1071cb0ef41Sopenharmony_ci  });
1081cb0ef41Sopenharmony_ci}, 'WritableStream should transition to waiting until write is acknowledged');
1091cb0ef41Sopenharmony_ci
1101cb0ef41Sopenharmony_cipromise_test(t => {
1111cb0ef41Sopenharmony_ci  let sinkWritePromiseRejectors = [];
1121cb0ef41Sopenharmony_ci  const ws = new WritableStream({
1131cb0ef41Sopenharmony_ci    write() {
1141cb0ef41Sopenharmony_ci      const sinkWritePromise = new Promise((r, reject) => sinkWritePromiseRejectors.push(reject));
1151cb0ef41Sopenharmony_ci      return sinkWritePromise;
1161cb0ef41Sopenharmony_ci    }
1171cb0ef41Sopenharmony_ci  });
1181cb0ef41Sopenharmony_ci
1191cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci  assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  return writer.ready.then(() => {
1241cb0ef41Sopenharmony_ci    const writePromise = writer.write('a');
1251cb0ef41Sopenharmony_ci    assert_equals(sinkWritePromiseRejectors.length, 1, 'there should be 1 rejector');
1261cb0ef41Sopenharmony_ci    assert_equals(writer.desiredSize, 0, 'desiredSize should be 0');
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci    const writePromise2 = writer.write('b');
1291cb0ef41Sopenharmony_ci    assert_equals(sinkWritePromiseRejectors.length, 1, 'there should be still 1 rejector');
1301cb0ef41Sopenharmony_ci    assert_equals(writer.desiredSize, -1, 'desiredSize should be -1');
1311cb0ef41Sopenharmony_ci
1321cb0ef41Sopenharmony_ci    const closedPromise = writer.close();
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci    assert_equals(writer.desiredSize, -1, 'desiredSize should still be -1');
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci    return Promise.all([
1371cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, error1, closedPromise,
1381cb0ef41Sopenharmony_ci                              'closedPromise should reject with the error returned from the sink\'s write method')
1391cb0ef41Sopenharmony_ci          .then(() => assert_equals(sinkWritePromiseRejectors.length, 0,
1401cb0ef41Sopenharmony_ci                                    'sinkWritePromise should reject before closedPromise')),
1411cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, error1, writePromise,
1421cb0ef41Sopenharmony_ci                              'writePromise should reject with the error returned from the sink\'s write method')
1431cb0ef41Sopenharmony_ci          .then(() => assert_equals(sinkWritePromiseRejectors.length, 0,
1441cb0ef41Sopenharmony_ci                                    'sinkWritePromise should reject before writePromise')),
1451cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, error1, writePromise2,
1461cb0ef41Sopenharmony_ci                              'writePromise2 should reject with the error returned from the sink\'s write method')
1471cb0ef41Sopenharmony_ci          .then(() => assert_equals(sinkWritePromiseRejectors.length, 0,
1481cb0ef41Sopenharmony_ci                                    'sinkWritePromise should reject before writePromise2')),
1491cb0ef41Sopenharmony_ci      flushAsyncEvents().then(() => {
1501cb0ef41Sopenharmony_ci        sinkWritePromiseRejectors[0](error1);
1511cb0ef41Sopenharmony_ci        sinkWritePromiseRejectors = [];
1521cb0ef41Sopenharmony_ci      })
1531cb0ef41Sopenharmony_ci    ]);
1541cb0ef41Sopenharmony_ci  });
1551cb0ef41Sopenharmony_ci}, 'when write returns a rejected promise, queued writes and close should be cleared');
1561cb0ef41Sopenharmony_ci
1571cb0ef41Sopenharmony_cipromise_test(t => {
1581cb0ef41Sopenharmony_ci  const ws = new WritableStream({
1591cb0ef41Sopenharmony_ci    write() {
1601cb0ef41Sopenharmony_ci      throw error1;
1611cb0ef41Sopenharmony_ci    }
1621cb0ef41Sopenharmony_ci  });
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
1651cb0ef41Sopenharmony_ci
1661cb0ef41Sopenharmony_ci  return promise_rejects_exactly(t, error1, writer.write('a'),
1671cb0ef41Sopenharmony_ci                                 'write() should reject with the error returned from the sink\'s write method')
1681cb0ef41Sopenharmony_ci      .then(() => promise_rejects_js(t, TypeError, writer.close(), 'close() should be rejected'));
1691cb0ef41Sopenharmony_ci}, 'when sink\'s write throws an error, the stream should become errored and the promise should reject');
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_cipromise_test(t => {
1721cb0ef41Sopenharmony_ci  const ws = new WritableStream({
1731cb0ef41Sopenharmony_ci    write(chunk, controller) {
1741cb0ef41Sopenharmony_ci      controller.error(error1);
1751cb0ef41Sopenharmony_ci      throw error2;
1761cb0ef41Sopenharmony_ci    }
1771cb0ef41Sopenharmony_ci  });
1781cb0ef41Sopenharmony_ci
1791cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
1801cb0ef41Sopenharmony_ci
1811cb0ef41Sopenharmony_ci  return promise_rejects_exactly(t, error2, writer.write('a'),
1821cb0ef41Sopenharmony_ci                                 'write() should reject with the error returned from the sink\'s write method ')
1831cb0ef41Sopenharmony_ci  .then(() => {
1841cb0ef41Sopenharmony_ci    return Promise.all([
1851cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, error1, writer.ready,
1861cb0ef41Sopenharmony_ci                              'writer.ready must reject with the error passed to the controller'),
1871cb0ef41Sopenharmony_ci      promise_rejects_exactly(t, error1, writer.closed,
1881cb0ef41Sopenharmony_ci                              'writer.closed must reject with the error passed to the controller')
1891cb0ef41Sopenharmony_ci    ]);
1901cb0ef41Sopenharmony_ci  });
1911cb0ef41Sopenharmony_ci}, 'writer.write(), ready and closed reject with the error passed to controller.error() made before sink.write' +
1921cb0ef41Sopenharmony_ci    ' rejection');
1931cb0ef41Sopenharmony_ci
1941cb0ef41Sopenharmony_cipromise_test(() => {
1951cb0ef41Sopenharmony_ci  const numberOfWrites = 1000;
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  let resolveFirstWritePromise;
1981cb0ef41Sopenharmony_ci  let writeCount = 0;
1991cb0ef41Sopenharmony_ci  const ws = new WritableStream({
2001cb0ef41Sopenharmony_ci    write() {
2011cb0ef41Sopenharmony_ci      ++writeCount;
2021cb0ef41Sopenharmony_ci      if (!resolveFirstWritePromise) {
2031cb0ef41Sopenharmony_ci        return new Promise(resolve => {
2041cb0ef41Sopenharmony_ci          resolveFirstWritePromise = resolve;
2051cb0ef41Sopenharmony_ci        });
2061cb0ef41Sopenharmony_ci      }
2071cb0ef41Sopenharmony_ci      return Promise.resolve();
2081cb0ef41Sopenharmony_ci    }
2091cb0ef41Sopenharmony_ci  });
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
2121cb0ef41Sopenharmony_ci  return writer.ready.then(() => {
2131cb0ef41Sopenharmony_ci    for (let i = 1; i < numberOfWrites; ++i) {
2141cb0ef41Sopenharmony_ci      writer.write('a');
2151cb0ef41Sopenharmony_ci    }
2161cb0ef41Sopenharmony_ci    const writePromise = writer.write('a');
2171cb0ef41Sopenharmony_ci
2181cb0ef41Sopenharmony_ci    assert_equals(writeCount, 1, 'should have called sink\'s write once');
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci    resolveFirstWritePromise();
2211cb0ef41Sopenharmony_ci
2221cb0ef41Sopenharmony_ci    return writePromise
2231cb0ef41Sopenharmony_ci        .then(() =>
2241cb0ef41Sopenharmony_ci        assert_equals(writeCount, numberOfWrites, `should have called sink's write ${numberOfWrites} times`));
2251cb0ef41Sopenharmony_ci  });
2261cb0ef41Sopenharmony_ci}, 'a large queue of writes should be processed completely');
2271cb0ef41Sopenharmony_ci
2281cb0ef41Sopenharmony_cipromise_test(() => {
2291cb0ef41Sopenharmony_ci  const stream = recordingWritableStream();
2301cb0ef41Sopenharmony_ci  const w = stream.getWriter();
2311cb0ef41Sopenharmony_ci  const WritableStreamDefaultWriter = w.constructor;
2321cb0ef41Sopenharmony_ci  w.releaseLock();
2331cb0ef41Sopenharmony_ci  const writer = new WritableStreamDefaultWriter(stream);
2341cb0ef41Sopenharmony_ci  return writer.ready.then(() => {
2351cb0ef41Sopenharmony_ci    writer.write('a');
2361cb0ef41Sopenharmony_ci    assert_array_equals(stream.events, ['write', 'a'], 'write() should be passed to sink');
2371cb0ef41Sopenharmony_ci  });
2381cb0ef41Sopenharmony_ci}, 'WritableStreamDefaultWriter should work when manually constructed');
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_cipromise_test(() => {
2411cb0ef41Sopenharmony_ci  let thenCalled = false;
2421cb0ef41Sopenharmony_ci  const ws = new WritableStream({
2431cb0ef41Sopenharmony_ci    write() {
2441cb0ef41Sopenharmony_ci      return {
2451cb0ef41Sopenharmony_ci        then(onFulfilled) {
2461cb0ef41Sopenharmony_ci          thenCalled = true;
2471cb0ef41Sopenharmony_ci          onFulfilled();
2481cb0ef41Sopenharmony_ci        }
2491cb0ef41Sopenharmony_ci      };
2501cb0ef41Sopenharmony_ci    }
2511cb0ef41Sopenharmony_ci  });
2521cb0ef41Sopenharmony_ci  return ws.getWriter().write('a').then(() => assert_true(thenCalled, 'thenCalled should be true'));
2531cb0ef41Sopenharmony_ci}, 'returning a thenable from write() should work');
2541cb0ef41Sopenharmony_ci
2551cb0ef41Sopenharmony_cipromise_test(() => {
2561cb0ef41Sopenharmony_ci  const stream = new WritableStream();
2571cb0ef41Sopenharmony_ci  const writer = stream.getWriter();
2581cb0ef41Sopenharmony_ci  const WritableStreamDefaultWriter = writer.constructor;
2591cb0ef41Sopenharmony_ci  assert_throws_js(TypeError, () => new WritableStreamDefaultWriter(stream),
2601cb0ef41Sopenharmony_ci                   'should not be able to construct on locked stream');
2611cb0ef41Sopenharmony_ci  // If stream.[[writer]] no longer points to |writer| then the closed Promise
2621cb0ef41Sopenharmony_ci  // won't work properly.
2631cb0ef41Sopenharmony_ci  return Promise.all([writer.close(), writer.closed]);
2641cb0ef41Sopenharmony_ci}, 'failing DefaultWriter constructor should not release an existing writer');
2651cb0ef41Sopenharmony_ci
2661cb0ef41Sopenharmony_cipromise_test(t => {
2671cb0ef41Sopenharmony_ci  const ws = new WritableStream({
2681cb0ef41Sopenharmony_ci    start() {
2691cb0ef41Sopenharmony_ci      return Promise.reject(error1);
2701cb0ef41Sopenharmony_ci    }
2711cb0ef41Sopenharmony_ci  }, { highWaterMark: 0 });
2721cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
2731cb0ef41Sopenharmony_ci  return Promise.all([
2741cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, error1, writer.ready, 'ready should be rejected'),
2751cb0ef41Sopenharmony_ci    promise_rejects_exactly(t, error1, writer.write(), 'write() should be rejected')
2761cb0ef41Sopenharmony_ci  ]);
2771cb0ef41Sopenharmony_ci}, 'write() on a stream with HWM 0 should not cause the ready Promise to resolve');
2781cb0ef41Sopenharmony_ci
2791cb0ef41Sopenharmony_cipromise_test(t => {
2801cb0ef41Sopenharmony_ci  const ws = new WritableStream();
2811cb0ef41Sopenharmony_ci  const writer = ws.getWriter();
2821cb0ef41Sopenharmony_ci  writer.releaseLock();
2831cb0ef41Sopenharmony_ci  return promise_rejects_js(t, TypeError, writer.write(), 'write should reject');
2841cb0ef41Sopenharmony_ci}, 'writing to a released writer should reject the returned promise');
285