| <!DOCTYPE html> |
| <script src='../../resources/testharness.js'></script> |
| <script src='../../resources/testharnessreport.js'></script> |
| <script src='resources/streams-utils.js'></script> |
| <script> |
| // This is updated till https://github.com/whatwg/streams/commit/4ba861e6f60c248060811830e11271c84b439cc3 |
| |
| function writeArrayToStream(array, writableStream) { |
| array.forEach(function(chunk) { writableStream.write(chunk); }) |
| return writableStream.close(); |
| } |
| |
| var test1 = async_test('error argument is given to start method'); |
| test1.step(function() { |
| var error; |
| var ws = new WritableStream({ |
| start: function(error_) { |
| error = error_; |
| } |
| }); |
| |
| // Now error the stream after its construction. |
| var passedError = new Error('horrible things'); |
| error(passedError); |
| assert_equals(ws.state, 'errored'); |
| ws.closed.catch(test1.step_func(function(r) { |
| assert_equals(r, passedError); |
| test1.done(); |
| })); |
| }); |
| |
| var test2 = async_test('Underlying sink\'s write won\'t be called until start finishes'); |
| test2.step(function() { |
| var expectWriteCall = false; |
| |
| var resolveStartPromise; |
| var ws = new WritableStream({ |
| start: function() { |
| return new Promise(test2.step_func(function(resolve) { resolveStartPromise = resolve; })); |
| }, |
| write: function(chunk) { |
| if (expectWriteCall) { |
| assert_equals(chunk, 'a'); |
| test2.done(); |
| } else { |
| assert_unreached('Unexpected write call'); |
| } |
| }, |
| close: function() { |
| assert_unreached('Unexpected close call'); |
| } |
| }); |
| |
| ws.write('a'); |
| assert_equals(ws.state, 'waiting', 'writable stream should be waiting, not ' + ws.state); |
| |
| // Wait and see that write won't be called. |
| setTimeout(test2.step_func(function() { |
| expectWriteCall = true; |
| resolveStartPromise(); |
| }), 200); |
| }); |
| |
| var test3 = async_test('Underlying sink\'s close won\'t be called until start finishes'); |
| test3.step(function() { |
| var expectCloseCall = false; |
| |
| var resolveStartPromise; |
| var ws = new WritableStream({ |
| start: function() { |
| return new Promise(test3.step_func(function(resolve, reject) { resolveStartPromise = resolve; })); |
| }, |
| write: function(chunk) { |
| assert_unreached('Unexpected write call'); |
| }, |
| close: function() { |
| if (expectCloseCall) { |
| test3.done(); |
| } else { |
| assert_unreached('Unexpected close call'); |
| } |
| } |
| }); |
| ws.close('a'); |
| assert_equals(ws.state, 'closing'); |
| |
| // Wait and see that write won't be called. |
| setTimeout(test3.step_func(function() { |
| expectCloseCall = true; |
| resolveStartPromise(); |
| }), 200); |
| }); |
| |
| var test4 = async_test('Fulfillment value of ws.close() call must be undefined even if the underlying sink returns a non-undefined value'); |
| test4.step(function() { |
| var ws = new WritableStream({ |
| close: function() { |
| return 'Hello'; |
| } |
| }); |
| |
| var closePromise = ws.close('a'); |
| closePromise.then(test4.step_func(function(value) { |
| assert_equals(value, undefined, 'fulfillment value must be undefined'); |
| test4.done(); |
| })).catch(test4.step_func(function() { |
| assert_unreached('closePromise is rejected'); |
| })); |
| }); |
| |
| var test5 = async_test('Underlying sink\'s write or close are never invoked if start throws'); |
| test5.step(function() { |
| var passedError = new Error('horrible things'); |
| |
| try { |
| var ws = new WritableStream({ |
| start: function() { |
| throw passedError; |
| }, |
| write: function(chunk) { |
| assert_unreached('Unexpected write call'); |
| }, |
| close: function() { |
| assert_unreached('Unexpected close call'); |
| } |
| }); |
| } catch (e) { |
| assert_equals(e, passedError); |
| test5.done(); |
| } |
| assert_unreached('Constructor didn\'t throw'); |
| }); |
| |
| var test6 = async_test('Underlying sink\'s write or close are never invoked if the promise returned by start is rejected'); |
| test6.step(function() { |
| var ws = new WritableStream({ |
| start: function() { |
| return Promise.reject(); |
| }, |
| write: function(chunk) { |
| assert_unreached('Unexpected write call'); |
| }, |
| close: function() { |
| assert_unreached('Unexpected close call'); |
| } |
| }); |
| |
| // Wait and see that write or close won't be called. |
| setTimeout(test6.step_func(function() { |
| test6.done(); |
| }), 500); |
| }); |
| |
| test(function() { |
| new WritableStream() // WritableStream constructed with no errors. |
| }, 'WritableStream can be constructed with no arguments'); |
| |
| test(function() { |
| var ws = new WritableStream(); |
| |
| assert_equals(typeof ws.write, 'function', 'has a write method'); |
| assert_equals(typeof ws.abort, 'function', 'has an abort method'); |
| assert_equals(typeof ws.close, 'function', 'has a close method'); |
| |
| assert_equals(ws.state, 'writable', 'state starts out writable'); |
| |
| assert_true('ready' in ws, 'has a ready property'); |
| assert_true('then' in ws.ready, 'ready property is a thenable'); |
| assert_true('closed' in ws, 'has a closed property'); |
| assert_true('then' in ws.closed, 'closed property is thenable'); |
| }, 'WritableStream instances have the correct methods and properties'); |
| |
| var test7 = async_test('WritableStream with simple input, processed asynchronously'); |
| test7.step(function() { |
| var storage; |
| var ws = new WritableStream({ |
| start: function() { |
| storage = []; |
| }, |
| |
| write: function(chunk) { |
| return new Promise(test7.step_func(function(resolve) { |
| setTimeout(test7.step_func(function() { |
| storage.push(chunk); |
| resolve(); |
| }), 0); |
| })); |
| }, |
| |
| close: function() { |
| return new Promise(test7.step_func(function(resolve) { setTimeout(test7.step_func(resolve), 0); })); |
| } |
| }); |
| |
| var input = [1, 2, 3, 4, 5]; |
| writeArrayToStream(input, ws).then( |
| test7.step_func(function() { |
| assert_array_equals(storage, input, 'correct data was relayed to underlying sink'); |
| test7.done(); |
| }), |
| test7.step_func(function(r) { assert_unreached(r); }) |
| ); |
| }); |
| |
| var test8 = async_test('WritableStream with simple input, processed synchronously'); |
| test8.step(function() { |
| var storage; |
| var ws = new WritableStream({ |
| start: function() { |
| storage = []; |
| }, |
| |
| write: function(chunk) { |
| storage.push(chunk); |
| }, |
| }); |
| |
| var input = [1, 2, 3, 4, 5]; |
| writeArrayToStream(input, ws).then( |
| test8.step_func(function() { |
| assert_array_equals(storage, input, 'correct data was relayed to underlying sink'); |
| test8.done(); |
| }), |
| test8.step_func(function(r) { assert_unreached(r); }) |
| ); |
| }); |
| |
| var test9 = async_test('WritableStream is writable and ready fulfills immediately if the strategy does not apply backpressure'); |
| test9.step(function() { |
| var ws = new WritableStream({}, { |
| highWaterMark: Infinity, |
| size() { return 0; } |
| }); |
| |
| assert_equals(ws.state, 'writable'); |
| |
| ws.ready.then(test9.step_func(function() { |
| test9.done('ready promise was fulfilled'); |
| })); |
| }); |
| |
| var test10 = async_test('Fulfillment value of ws.write() call must be undefined even if the underlying sink returns a non-undefined value'); |
| test10.step(function() { |
| var ws = new WritableStream({ |
| write: function() { |
| return 'Hello'; |
| } |
| }); |
| |
| var writePromise = ws.write('a'); |
| writePromise.then(test10.step_func(function(value) { |
| assert_equals(value, undefined, 'fulfillment value must be undefined'); |
| test10.done(); |
| })).catch(test10.step_func(function() { assert_unreached('writePromise is rejected'); })); |
| }); |
| </script> |