summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/streams/writable-streams/start.any.js
blob: 82d869430dd70088a54db856240f4fbe1d2a94d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// META: global=window,worker
// META: script=../resources/test-utils.js
// META: script=../resources/recording-streams.js
'use strict';

const error1 = { name: 'error1' };

promise_test(() => {
  let resolveStartPromise;
  const ws = recordingWritableStream({
    start() {
      return new Promise(resolve => {
        resolveStartPromise = resolve;
      });
    }
  });

  const writer = ws.getWriter();

  assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');
  writer.write('a');
  assert_equals(writer.desiredSize, 0, 'desiredSize should be 0 after writer.write()');

  // Wait and verify that write isn't called.
  return flushAsyncEvents()
      .then(() => {
        assert_array_equals(ws.events, [], 'write should not be called until start promise resolves');
        resolveStartPromise();
        return writer.ready;
      })
      .then(() => assert_array_equals(ws.events, ['write', 'a'],
                                      'write should not be called until start promise resolves'));
}, 'underlying sink\'s write should not be called until start finishes');

promise_test(() => {
  let resolveStartPromise;
  const ws = recordingWritableStream({
    start() {
      return new Promise(resolve => {
        resolveStartPromise = resolve;
      });
    }
  });

  const writer = ws.getWriter();

  writer.close();
  assert_equals(writer.desiredSize, 1, 'desiredSize should be 1');

  // Wait and verify that write isn't called.
  return flushAsyncEvents().then(() => {
    assert_array_equals(ws.events, [], 'close should not be called until start promise resolves');
    resolveStartPromise();
    return writer.closed;
  });
}, 'underlying sink\'s close should not be called until start finishes');

test(() => {
  const passedError = new Error('horrible things');

  let writeCalled = false;
  let closeCalled = false;
  assert_throws_exactly(passedError, () => {
    // recordingWritableStream cannot be used here because the exception in the
    // constructor prevents assigning the object to a variable.
    new WritableStream({
      start() {
        throw passedError;
      },
      write() {
        writeCalled = true;
      },
      close() {
        closeCalled = true;
      }
    });
  }, 'constructor should throw passedError');
  assert_false(writeCalled, 'write should not be called');
  assert_false(closeCalled, 'close should not be called');
}, 'underlying sink\'s write or close should not be called if start throws');

promise_test(() => {
  const ws = recordingWritableStream({
    start() {
      return Promise.reject();
    }
  });

  // Wait and verify that write or close aren't called.
  return flushAsyncEvents()
      .then(() => assert_array_equals(ws.events, [], 'write and close should not be called'));
}, 'underlying sink\'s write or close should not be invoked if the promise returned by start is rejected');

promise_test(t => {
  const ws = new WritableStream({
    start() {
      return {
        then(onFulfilled, onRejected) { onRejected(error1); }
      };
    }
  });
  return promise_rejects_exactly(t, error1, ws.getWriter().closed, 'closed promise should be rejected');
}, 'returning a thenable from start() should work');

promise_test(t => {
  const ws = recordingWritableStream({
    start(controller) {
      controller.error(error1);
    }
  });
  return promise_rejects_exactly(t, error1, ws.getWriter().write('a'), 'write() should reject with the error')
      .then(() => {
        assert_array_equals(ws.events, [], 'sink write() should not have been called');
      });
}, 'controller.error() during start should cause writes to fail');

promise_test(t => {
  let controller;
  let resolveStart;
  const ws = recordingWritableStream({
    start(c) {
      controller = c;
      return new Promise(resolve => {
        resolveStart = resolve;
      });
    }
  });
  const writer = ws.getWriter();
  const writePromise = writer.write('a');
  const closePromise = writer.close();
  controller.error(error1);
  resolveStart();
  return Promise.all([
    promise_rejects_exactly(t, error1, writePromise, 'write() should fail'),
    promise_rejects_exactly(t, error1, closePromise, 'close() should fail')
  ]).then(() => {
    assert_array_equals(ws.events, [], 'sink write() and close() should not have been called');
  });
}, 'controller.error() during async start should cause existing writes to fail');

promise_test(t => {
  const events = [];
  const promises = [];
  function catchAndRecord(promise, name) {
    promises.push(promise.then(t.unreached_func(`promise ${name} should not resolve`),
                               () => {
                                 events.push(name);
                               }));
  }
  const ws = new WritableStream({
    start() {
      return Promise.reject();
    }
  }, { highWaterMark: 0 });
  const writer = ws.getWriter();
  catchAndRecord(writer.ready, 'ready');
  catchAndRecord(writer.closed, 'closed');
  catchAndRecord(writer.write(), 'write');
  return Promise.all(promises)
      .then(() => {
        assert_array_equals(events, ['ready', 'write', 'closed'], 'promises should reject in standard order');
      });
}, 'when start() rejects, writer promises should reject in standard order');