UNPKG

unexpected-stream

Version:

node.js streams plugin for the Unexpected assertion library

358 lines (328 loc) 11.4 kB
const unexpected = require('unexpected'); const pathModule = require('path'); const streamModule = require('stream'); const EventEmitter = require('events').EventEmitter; const fs = require('fs'); const zlib = require('zlib'); const { Base64Encode } = require('base64-stream'); describe('unexpected-stream', () => { const expect = unexpected .clone() .installPlugin(require('../lib/unexpectedStream')); const fooTxtPath = pathModule.resolve(__dirname, '..', 'testdata', 'foo.txt'); expect.output.preferredWidth = 150; expect.addAssertion( '<any> to inspect as <string>', (expect, subject, value) => { expect(expect.inspect(subject).toString(), 'to equal', value); } ); it('should identify a stream-like object with a readable property of true', () => { expect( expect.getType('Stream').identify({ on() {}, readable: true }), 'to be true' ); }); it('should identify a stream-like object with a writable property of true', () => { expect( expect.getType('Stream').identify({ on() {}, writable: true }), 'to be true' ); }); it('should inspect a stream as the constructor name', () => { const stream = new EventEmitter(); stream.readable = true; expect(stream, 'to inspect as', 'EventEmitter'); }); if (parseInt(process.version.match(/v(\d+)\./)[1], 10) < 6) { // In node.js 6+ it comes out as "Constructor", which is actually better it('should inspect a stream as "Stream" if the constructor is anonymous', () => { const Constructor = () => {}; Constructor.prototype.readable = true; Constructor.prototype.on = () => {}; expect(new Constructor(), 'to inspect as', 'Stream'); }); } describe('to yield output satisfying', () => { it('should buffer up the output of a readable stream that outputs buffers', () => expect( fs.createReadStream(fooTxtPath), 'to yield output satisfying', Buffer.from('foobarquux\n', 'utf-8') )); it('should buffer up the output of a readable stream that outputs strings', () => expect( fs.createReadStream(fooTxtPath, { encoding: 'utf-8' }), 'to yield output satisfying', 'to equal', 'foobarquux\n' )); it('fails with a diff', () => expect( expect( fs.createReadStream(fooTxtPath, { encoding: 'utf-8' }), 'to yield output satisfying', 'to equal', 'blah\n' ), 'to be rejected with', "expected ReadStream to yield output satisfying to equal 'blah\\n'\n" + " expected 'foobarquux\\n' to equal 'blah\\n'\n" + '\n' + ' -foobarquux\n' + ' +blah' )); it('should be able to assert the output of the same stream multiple times', () => { const readStream = fs.createReadStream(fooTxtPath, { encoding: 'utf-8' }); return expect.promise .all([ expect( readStream, 'to yield output satisfying', 'to equal', 'foobarquux\n' ), expect( readStream, 'to yield output satisfying', 'to equal', 'foobarquux\n' ), ]) .then(() => expect( readStream, 'to yield output satisfying', 'to equal', 'foobarquux\n' ) ); }); it('should convert to Buffer when a readable stream outputs both Buffer and string chunks', () => { const stream = new EventEmitter(); stream.readable = true; setImmediate(() => { stream.emit('data', 'foo'); stream.emit('data', Buffer.from('bar')); stream.emit('end'); }); return expect( stream, 'to yield output satisfying', Buffer.from('foobar') ); }); }); describe('to yield chunks', () => { it('should produce an array of the raw chunks', () => { const stream = new streamModule.Readable(); let n = 0; stream._read = () => { let chunk = null; if (n < 4) { chunk = `chunk${n}`; n += 1; } setImmediate(() => { stream.push(chunk); }); }; return expect(stream, 'to yield chunks satisfying', [ Buffer.from('chunk0', 'utf-8'), Buffer.from('chunk1', 'utf-8'), Buffer.from('chunk2', 'utf-8'), Buffer.from('chunk3', 'utf-8'), ]); }); }); describe('when piped through assertion', () => { it('should pipe the data through the proxy stream', () => expect( fs.createReadStream(fooTxtPath), 'when piped through', new Base64Encode(), 'to yield output satisfying to equal', 'Zm9vYmFycXV1eAo=' )); it('should pipe the data through multiple proxy streams', () => expect( fs.createReadStream(fooTxtPath), 'when piped through', [zlib.createGzip(), zlib.createGunzip()], 'to yield output satisfying', Buffer.from('foobarquux\n', 'utf-8') )); describe('with a Buffer instance', () => { it('should succeed', () => expect( Buffer.from([ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4b, 0xcb, 0xcf, 0x4f, 0x4a, 0x2c, 0x2a, 0x2c, 0x2d, 0xad, 0xe0, 0x02, 0x00, 0xc8, 0x99, 0x6f, 0x44, 0x0b, 0x00, 0x00, 0x00, ]), 'when piped through', zlib.createGunzip(), 'to yield output satisfying', Buffer.from('foobarquux\n', 'utf-8') )); it('fails with a diff', () => expect( expect( Buffer.from([ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4b, 0xcb, 0xcf, 0x4f, 0x4a, 0x2c, 0x2a, 0x2c, 0x2d, 0xad, 0xe0, 0x02, 0x00, 0xc8, 0x99, 0x6f, 0x44, 0x0b, 0x00, 0x00, 0x00, ]), 'when piped through', zlib.createGunzip(), 'to yield output satisfying', Buffer.from('foobarqux', 'utf-8') ), 'to be rejected with', 'expected Buffer.from([0x1F, 0x8B, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x4B, 0xCB, 0xCF, 0x4F, 0x4A, 0x2C /* 15 more */ ])\n' + 'when piped through Gunzip to yield output satisfying Buffer.from([0x66, 0x6F, 0x6F, 0x62, 0x61, 0x72, 0x71, 0x75, 0x78])\n' + ' expected Gunzip to yield output satisfying Buffer.from([0x66, 0x6F, 0x6F, 0x62, 0x61, 0x72, 0x71, 0x75, 0x78])\n' + ' expected Buffer.from([0x66, 0x6F, 0x6F, 0x62, 0x61, 0x72, 0x71, 0x75, 0x75, 0x78, 0x0A])\n' + ' to equal Buffer.from([0x66, 0x6F, 0x6F, 0x62, 0x61, 0x72, 0x71, 0x75, 0x78])\n' + '\n' + ' -66 6F 6F 62 61 72 71 75 75 78 0A │foobarquux.│\n' + ' +66 6F 6F 62 61 72 71 75 78 │foobarqux│' )); }); describe('with a string', () => { it('should succeed', () => expect( 'foobarquux\n', 'when piped through', new Base64Encode(), 'to yield output satisfying to equal', 'Zm9vYmFycXV1eAo=' )); }); describe('with an array of strings', () => { it('should succeed', () => expect( ['foo', 'bar', 'quux\n'], 'when piped through', new Base64Encode(), 'to yield output satisfying to equal', 'Zm9vYmFycXV1eAo=' )); it('fails with a diff', () => expect( expect( ['f', 'oo'], 'when piped through', new Base64Encode(), 'to yield output satisfying to equal', 'blah' ), 'to be rejected with', "expected [ 'f', 'oo' ] when piped through Base64Encode to yield output satisfying to equal 'blah'\n" + " expected Base64Encode to yield output satisfying to equal 'blah'\n" + " expected 'Zm9v' to equal 'blah'\n" + '\n' + ' -Zm9v\n' + ' +blah' )); }); describe('with an array of Buffer instances', () => { it('should succeed', () => expect( [ Buffer.from('foo', 'utf-8'), Buffer.from('bar', 'utf-8'), Buffer.from('quux\n', 'utf-8'), ], 'when piped through', new Base64Encode(), 'to yield output satisfying to equal', 'Zm9vYmFycXV1eAo=' )); }); it('should provide the target stream as the fulfillment value', () => expect( fs.createReadStream(fooTxtPath), 'piped through', zlib.createGzip() ).then((targetStream) => { expect(targetStream, 'to be a', require('zlib').Gzip); })); }); describe('to error assertion', () => { describe('when the stream errors', () => { it('should provide the error as the fulfillment value', () => { const stream = new EventEmitter(); const err = new Error('ugh'); stream.readable = stream.writable = true; setImmediate(() => { stream.emit('error', err); }); stream.end = () => {}; return expect(expect(stream, 'to error'), 'to be fulfilled with', err); }); }); describe('when the stream succeeds', () => { it('should fail', () => { const stream = new EventEmitter(); stream.readable = stream.writable = true; setImmediate(() => { stream.emit('data', 'foo'); stream.emit('end'); }); return expect( () => expect(stream, 'to error'), 'to error with', 'Stream was supposed to fail, but ended correctly' ); }); }); }); describe('to error with', () => { describe('when the stream errors', () => { it('should succeed', () => { const stream = new EventEmitter(); const err = new Error('ugh'); stream.readable = stream.writable = true; setImmediate(() => { stream.emit('error', err); }); stream.end = () => {}; expect(stream, 'to error with', err); }); it('should fail with a diff', () => { const stream = new EventEmitter(); const err = new Error('ugh'); stream.readable = stream.writable = true; setImmediate(() => { stream.emit('error', err); }); stream.end = () => {}; return expect( () => expect(stream, 'to error with', 'blabla'), 'to error with', "expected EventEmitter to error with 'blabla'\n" + " expected Error('ugh') to satisfy 'blabla'\n" + '\n' + ' -ugh\n' + ' +blabla' ); }); }); describe('when the stream succeeds', () => { it('should fail', () => { const stream = new EventEmitter(); stream.readable = stream.writable = true; setImmediate(() => { stream.emit('data', 'foo'); stream.emit('end'); }); return expect( () => expect(stream, 'to error with', 'foo'), 'to error with', 'Stream was supposed to fail, but ended correctly' ); }); }); }); });