1// META: global=window,worker 2// META: script=../resources/test-utils.js 3'use strict'; 4 5promise_test(() => { 6 let flushCalled = false; 7 const ts = new TransformStream({ 8 transform() { }, 9 flush() { 10 flushCalled = true; 11 } 12 }); 13 14 return ts.writable.getWriter().close().then(() => { 15 return assert_true(flushCalled, 'closing the writable triggers the transform flush immediately'); 16 }); 17}, 'TransformStream flush is called immediately when the writable is closed, if no writes are queued'); 18 19promise_test(() => { 20 let flushCalled = false; 21 let resolveTransform; 22 const ts = new TransformStream({ 23 transform() { 24 return new Promise(resolve => { 25 resolveTransform = resolve; 26 }); 27 }, 28 flush() { 29 flushCalled = true; 30 return new Promise(() => {}); // never resolves 31 } 32 }, undefined, { highWaterMark: 1 }); 33 34 const writer = ts.writable.getWriter(); 35 writer.write('a'); 36 writer.close(); 37 assert_false(flushCalled, 'closing the writable does not immediately call flush if writes are not finished'); 38 39 let rsClosed = false; 40 ts.readable.getReader().closed.then(() => { 41 rsClosed = true; 42 }); 43 44 return delay(0).then(() => { 45 assert_false(flushCalled, 'closing the writable does not asynchronously call flush if writes are not finished'); 46 resolveTransform(); 47 return delay(0); 48 }).then(() => { 49 assert_true(flushCalled, 'flush is eventually called'); 50 assert_false(rsClosed, 'if flushPromise does not resolve, the readable does not become closed'); 51 }); 52}, 'TransformStream flush is called after all queued writes finish, once the writable is closed'); 53 54promise_test(() => { 55 let c; 56 const ts = new TransformStream({ 57 start(controller) { 58 c = controller; 59 }, 60 transform() { 61 }, 62 flush() { 63 c.enqueue('x'); 64 c.enqueue('y'); 65 } 66 }); 67 68 const reader = ts.readable.getReader(); 69 70 const writer = ts.writable.getWriter(); 71 writer.write('a'); 72 writer.close(); 73 return reader.read().then(result1 => { 74 assert_equals(result1.value, 'x', 'the first chunk read is the first one enqueued in flush'); 75 assert_equals(result1.done, false, 'the first chunk read is the first one enqueued in flush'); 76 77 return reader.read().then(result2 => { 78 assert_equals(result2.value, 'y', 'the second chunk read is the second one enqueued in flush'); 79 assert_equals(result2.done, false, 'the second chunk read is the second one enqueued in flush'); 80 }); 81 }); 82}, 'TransformStream flush gets a chance to enqueue more into the readable'); 83 84promise_test(() => { 85 let c; 86 const ts = new TransformStream({ 87 start(controller) { 88 c = controller; 89 }, 90 transform() { 91 }, 92 flush() { 93 c.enqueue('x'); 94 c.enqueue('y'); 95 return delay(0); 96 } 97 }); 98 99 const reader = ts.readable.getReader(); 100 101 const writer = ts.writable.getWriter(); 102 writer.write('a'); 103 writer.close(); 104 105 return Promise.all([ 106 reader.read().then(result1 => { 107 assert_equals(result1.value, 'x', 'the first chunk read is the first one enqueued in flush'); 108 assert_equals(result1.done, false, 'the first chunk read is the first one enqueued in flush'); 109 110 return reader.read().then(result2 => { 111 assert_equals(result2.value, 'y', 'the second chunk read is the second one enqueued in flush'); 112 assert_equals(result2.done, false, 'the second chunk read is the second one enqueued in flush'); 113 }); 114 }), 115 reader.closed.then(() => { 116 assert_true(true, 'readable reader becomes closed'); 117 }) 118 ]); 119}, 'TransformStream flush gets a chance to enqueue more into the readable, and can then async close'); 120 121const error1 = new Error('error1'); 122error1.name = 'error1'; 123 124promise_test(t => { 125 const ts = new TransformStream({ 126 flush(controller) { 127 controller.error(error1); 128 } 129 }); 130 return promise_rejects_exactly(t, error1, ts.writable.getWriter().close(), 'close() should reject'); 131}, 'error() during flush should cause writer.close() to reject'); 132