UNPKG

@teamwork/websocket-json-stream

Version:

Expose WebSockets with JSON as an object stream.

259 lines (236 loc) 11.1 kB
const assert = require('chai').assert const http = require('http') const WebSocket = require('ws') const WebSocketJSONStream = require('..') const testCloseStatus = require('./close-status') const handler = (done, code) => (...args) => { try { code(...args) done() } catch (e) { done(e) } } describe('WebSocketJSONStream', function () { beforeEach(function (done) { this.httpServer = http.createServer() this.wsServer = new WebSocket.Server({ server: this.httpServer }) this.httpServer.listen(() => { const address = this.httpServer.address() this.url = `http://${address.address}:${address.port}` this.connect(({ clientWebSocket, serverWebSocket }) => { this.clientStream = new WebSocketJSONStream(this.clientWebSocket = clientWebSocket) this.serverStream = new WebSocketJSONStream(this.serverWebSocket = serverWebSocket) done() }) }) this.connect = function (callback) { const clientWebSocket = new WebSocket(this.url) this.wsServer.once('connection', serverWebSocket => { clientWebSocket.once('open', () => callback({ clientWebSocket, serverWebSocket })) }) } }) afterEach(function (done) { this.wsServer.close() this.httpServer.close(done) }) it('should send and receive messages', function (done) { const serverSentData = [ { a: 1 }, { b: 2 } ] const clientSentData = [ { y: -1 }, { z: -2 } ] const serverReceivedData = [] const clientReceivedData = [] this.serverStream.on('data', data => serverReceivedData.push(data)) this.clientStream.on('data', data => clientReceivedData.push(data)) this.clientStream.on('close', handler(done, () => { assert.deepEqual(serverReceivedData, clientSentData) assert.deepEqual(clientReceivedData, serverSentData) })) serverSentData.forEach(data => this.serverStream.write(data)) clientSentData.forEach(data => this.clientStream.write(data)) this.clientStream.end() }) it('should get clientStream close on clientStream.end()', function (done) { this.clientStream.on('close', () => done()) this.clientStream.end() }) it('should get clientStream close on serverStream.end()', function (done) { this.clientStream.on('close', () => done()) this.serverStream.end() }) it('should get serverStream close on clientStream.end()', function (done) { this.serverStream.on('close', () => done()) this.clientStream.end() }) it('should get serverStream close on serverStream.end()', function (done) { this.serverStream.on('close', () => done()) this.serverStream.end() }) it('should get clientStream close on clientStream.destroy()', function (done) { this.clientStream.on('close', () => done()) this.clientStream.destroy() }) it('should get clientStream close on serverStream.destroy()', function (done) { this.clientStream.on('close', () => done()) this.serverStream.destroy() }) it('should get serverStream close on clientStream.destroy()', function (done) { this.serverStream.on('close', () => done()) this.clientStream.destroy() }) it('should get serverStream close on serverStream.destroy()', function (done) { this.serverStream.on('close', () => done()) this.serverStream.destroy() }) it('should get clientStream finish on clientStream.end()', function (done) { this.clientStream.on('finish', () => done()) this.clientStream.end() }) it('should get serverStream finish on serverStream.end()', function (done) { this.serverStream.on('finish', () => done()) this.serverStream.end() }) it('should get clientStream error on clientStream.write invalid data (Symbol)', function (done) { this.clientStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.clientStream.write(Symbol('Test')) }) it('should get serverStream error on serverStream.write invalid data (Symbol)', function (done) { this.serverStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.serverStream.write(Symbol('Test')) }) it('should get clientStream error on clientStream.write invalid data (cyclic data)', function (done) { const data = {} data.a = data this.clientStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.clientStream.write(data) }) it('should get serverStream error on serverStream.write invalid data (cyclic data)', function (done) { const data = {} data.a = data this.serverStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.serverStream.write(data) }) it('should get clientStream error on serverWebSocket.send invalid data', function (done) { this.clientStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.serverWebSocket.send('qwerty') }) it('should get serverStream error on clientWebSocket.send invalid data', function (done) { this.serverStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.clientWebSocket.send('qwerty') }) it('should get clientStream error on clientStream.write after end', function (done) { this.clientStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.clientStream.end() this.clientStream.write({}) }) it('should get serverStream error on serverStream.write after end', function (done) { this.serverStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.serverStream.end() this.serverStream.write({}) }) it('should get clientStream error on clientStream.write, if clientWebSocket is closed', function (done) { this.clientWebSocket.on('close', () => { this.clientStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.clientStream.write({}) }) this.clientWebSocket.close() }) it('should get serverStream error on serverStream.write, if serverWebSocket is closed', function (done) { this.serverWebSocket.on('close', () => { this.serverStream.once('error', handler(done, e => assert.instanceOf(e, Error))) this.serverStream.write({}) }) this.serverWebSocket.close() }) it('should get clientStream error when clientWebSocket sends JSON-encoded null', function (done) { this.clientStream.on('error', handler(done, e => assert.instanceOf(e, Error))) this.serverWebSocket.send('null') }) it('should get clientStream error when clientWebSocket sends JSON-encoded undefined', function (done) { this.clientStream.on('error', handler(done, e => assert.instanceOf(e, Error))) this.serverWebSocket.send('undefined') }) it('clientStream.destroy when clientWebSocket.readyState === WebSocket.CONNECTING', function (done) { const clientWebSocket = new WebSocket(this.url) const clientStream = new WebSocketJSONStream(clientWebSocket) clientStream.once('close', () => done()) clientStream.destroy() }) it('clientStream.destroy when clientWebSocket.readyState === WebSocket.CONNECTING and gets error', function (done) { const clientWebSocket = new WebSocket('http://invalid-url:0') const clientStream = new WebSocketJSONStream(clientWebSocket) clientWebSocket.on('error', () => null) // ignore invalid-url error clientStream.on('close', () => done()) clientStream.destroy() }) it('clientStream.destroy when clientWebSocket.readyState === WebSocket.OPEN', function (done) { const clientWebSocket = new WebSocket(this.url) const clientStream = new WebSocketJSONStream(clientWebSocket) clientWebSocket.on('close', () => done()) clientWebSocket.on('open', () => clientStream.destroy()) }) it('clientStream.destroy when clientWebSocket.readyState === WebSocket.CLOSING', function (done) { const clientWebSocket = new WebSocket(this.url) const clientStream = new WebSocketJSONStream(clientWebSocket) clientWebSocket.on('close', () => done()) clientWebSocket.on('open', () => { clientWebSocket.close() clientStream.destroy() }) }) it('clientStream.destroy when clientWebSocket.readyState === WebSocket.CLOSED', function (done) { const clientWebSocket = new WebSocket(this.url) clientWebSocket.on('close', () => { new WebSocketJSONStream(clientWebSocket).destroy() done() }) clientWebSocket.on('open', () => clientWebSocket.close()) }) it('write when clientWebSocket.readyState === WebSocket.CONNECTING', function (done) { const clientWebSocket = new WebSocket(this.url) const clientStream = new WebSocketJSONStream(clientWebSocket) let opened = false clientWebSocket.on('open', () => { opened = true }) clientStream.write({}, handler(done, error => { assert.ok(error == null) assert.ok(opened) })) }) it('write when clientWebSocket.readyState === WebSocket.CONNECTING and gets error', function (done) { const clientWebSocket = new WebSocket('http://invalid-url:0') const clientStream = new WebSocketJSONStream(clientWebSocket) let closed = false clientStream.on('error', error => { assert.ok(error instanceof Error) assert.equal(error.name, 'Error [ERR_CLOSED]') assert.equal(error.message, 'WebSocket CLOSING or CLOSED.') }) clientWebSocket.on('error', () => null) // ignore invalid-url error clientWebSocket.on('close', () => { closed = true }) clientStream.write({}, handler(done, error => { assert.ok(error instanceof Error) assert.equal(error.name, 'Error [ERR_CLOSED]') assert.equal(error.message, 'WebSocket CLOSING or CLOSED.') assert.ok(closed) })) }) it('write when clientWebSocket.readyState === WebSocket.CLOSING', function (done) { this.clientWebSocket.close() this.clientStream.on('error', error => { assert.ok(error instanceof Error) assert.equal(error.name, 'Error [ERR_CLOSED]') assert.equal(error.message, 'WebSocket CLOSING or CLOSED.') }) this.clientStream.write({}, handler(done, error => { assert.ok(error instanceof Error) assert.equal(error.name, 'Error [ERR_CLOSED]') assert.equal(error.message, 'WebSocket CLOSING or CLOSED.') })) }) testCloseStatus() })