test/test.js
var assert = require('assert');
var sinon = require('sinon');
if(typeof WebSocket === 'undefined') {
var ws = require('ws');
global.WebSocket = ws; // Supply WebSocket global for node.js-based tests
}
var PersistentWS = require('..');
var nodeJS = process && process.versions && process.versions.node;
var websocket;
if(nodeJS) {
websocket = require('websocket');
var wsServer = new ws.Server({host: '127.0.0.1', port: 8080});
wsServer.on('connection', function(connection) {
connection.on('message', function(message) {
connection.send(message);
});
});
}
var constants = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
var properties = ['binaryType', 'bufferedAmount', 'extensions', 'protocol', 'readyState', 'url'];
var pws = {};
suite('Default values', function() {
before(function() {
pws = new PersistentWS('ws://localhost:8080/');
});
test('.verbose should default to false', function() {
assert.strictEqual(pws.verbose, false);
});
test('.initialRetryTime should default to 5000', function() {
assert.strictEqual(pws.initialRetryTime, 5000);
});
test('.maxRetryTime should default to null', function() {
assert.strictEqual(pws.maxRetryTime, null);
});
test('.persistence should default to true', function() {
assert.strictEqual(pws.persistence, true);
});
});
suite('WebSocket API', function() {
test('Should connect to host using browser WebSocket syntax', function(done) {
pws = new PersistentWS('ws://localhost:8080/');
pws.addEventListener('open', function() {
done();
});
});
test('Should be able to send message to server', function(done) {
pws = new PersistentWS('ws://localhost:8080/');
pws.addEventListener('open', function() {
pws.addEventListener('message', function(m) {
assert.strictEqual(m.data, 'foo');
done();
});
pws.send('foo');
});
});
test('Options.verbose should set .verbose', function() {
sinon.stub(console, 'log');
pws = new PersistentWS('ws://localhost:8080/', undefined, {verbose: true});
assert.strictEqual(pws.verbose, true);
pws.verbose = false;
console.log.restore();
});
test('Options.initialRetryTime should set .initialRetryTime', function() {
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100});
assert.strictEqual(pws.initialRetryTime, 100);
});
test('Options.maxRetryTime should set .maxRetryTime', function() {
pws = new PersistentWS('ws://localhost:8080/', undefined, {maxRetryTime: 10000});
assert.strictEqual(pws.maxRetryTime, 10000);
});
test('Options.persistence should set .persistence', function() {
pws = new PersistentWS('ws://localhost:8080/', undefined, {persistence: false});
assert.strictEqual(pws.persistence, false);
});
test('Options.logger should set .logger', function() {
var aLogger = function() {}
pws = new PersistentWS('ws://localhost:8080/', undefined, {logger: aLogger});
assert.strictEqual(pws.logger, aLogger);
});
test('Constructor should have WebSocket\'s constants', function() {
constants.forEach(function(v) {
assert.strictEqual(PersistentWS[v], WebSocket[v]);
});
});
test('Instances should have WebSocket\'s constants', function() {
constants.forEach(function(v) {
assert.strictEqual(pws[v], WebSocket[v]);
});
});
test('.socket should provide access to the raw WebSocket', function() {
assert.strictEqual(pws.socket.constructor, WebSocket);
});
test('Lookups on standard WebSocket properties should be passed through to .socket', function(done) {
pws = new PersistentWS('ws://localhost:8080/');
// Check all the properties are the same...
properties.forEach(function(v) {
assert.strictEqual(pws[v], pws.socket[v]);
});
pws.addEventListener('open', function() {
// ...and check again after opening
properties.forEach(function(v) {
assert.strictEqual(pws[v], pws.socket[v]);
});
done();
});
});
test('.binaryType should be settable to either \'blob\' or \'arraybuffer\'', function() {
pws.binaryType = 'blob';
assert.strictEqual(pws.binaryType, 'blob');
assert.strictEqual(pws.socket.binaryType, 'blob');
pws.binaryType = 'arraybuffer';
assert.strictEqual(pws.binaryType, 'arraybuffer');
assert.strictEqual(pws.socket.binaryType, 'arraybuffer');
});
test('.on[event] properties should be settable to functions', function() {
var events = ['onclose', 'onerror', 'onmessage', 'onopen'];
events.forEach(function(v) {
var aFunction = function() {}
pws[v] = aFunction;
assert.strictEqual(pws[v], aFunction);
});
});
test('Should automatically reconnect after connection is cut', function(done) {
this.slow(250);
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100});
pws.onopen = function() {
pws.close();
pws.onopen = function() {
done();
}
}
});
test('If .persistence is false, should not automatically reconnect', function(done) {
this.slow(600);
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100, persistence: false});
var hasReconnected = false;
pws.addEventListener('open', function() {
pws.close();
pws.addEventListener('open', function() {
hasReconnected = true;
});
});
setTimeout(function() {
assert.strictEqual(hasReconnected, false);
done();
}, 250);
});
test('Writable properties should be transferred to new .socket after reconnecting', function(done) {
this.slow(250);
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100});
var binaryType = pws.binaryType = 'arraybuffer';
pws.onopen = function() {
pws.onopen = function() {
assert.strictEqual(pws.socket.binaryType, binaryType);
done();
}
pws.close();
}
});
test('Event listeners registered with .onopen should be called with an event argument', function(done) {
pws = new PersistentWS('ws://localhost:8080/');
pws.onopen = function(e) {
assert.strictEqual(typeof e, 'object');
done();
}
});
test('Event listeners registered with .onmessage should be called with an event argument', function(done) {
pws = new PersistentWS('ws://localhost:8080/');
pws.onmessage = function(e) {
assert.strictEqual(typeof e, 'object');
done();
}
pws.addEventListener('open', function() {
pws.send('foo');
});
});
test('Event listeners registered with .onclose should be called with an event argument', function(done) {
pws = new PersistentWS('ws://localhost:8080/');
pws.onclose = function(e) {
assert.strictEqual(typeof e, 'object');
done();
}
pws.addEventListener('open', function() {
pws.persistence = false;
pws.close();
});
});
test('Event listeners registered with .onerror should be called with an error argument', function(done) {
pws = new PersistentWS('ws://localhost:1234/');
pws.onerror = function(e) {
assert.strictEqual(typeof e, 'object');
done();
}
});
test('Event listeners registered with .on[event] should fire after reconnecting', function(done) {
this.slow(250);
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100});
pws.onmessage = function() {
done();
}
pws.onopen = function() {
pws.close();
pws.onopen = function() {
// Has just reconnected
pws.send('foo');
}
}
});
test('Event listeners registered with .addEventListener should fire', function(done) {
pws = new PersistentWS('ws://localhost:8080/');
pws.addEventListener('open', function() {
done();
});
});
test('Should be able to add multiple listeners with .addEventListener', function(done) {
this.slow(250);
pws = new PersistentWS('ws://localhost:8080/');
var listenerOne = new sinon.spy();
var listenerTwo = new sinon.spy();
pws.addEventListener('open', listenerOne);
pws.addEventListener('open', listenerTwo);
setTimeout(function() {
assert.strictEqual(listenerOne.calledOnce, true);
assert.strictEqual(listenerTwo.calledOnce, true);
done();
}, 100);
});
test('Event listeners registered with .addEventListener should still fire after reconnecting', function(done) {
this.slow(250);
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100});
pws.addEventListener('message', function() {
done();
});
pws.onopen = function() {
pws.close();
pws.onopen = function() {
// Has just reconnected
pws.send('foo');
}
}
});
test('Event listeners removed with .removeEventListener should not fire', function(done) {
// Swap to WebSocket library that supports .removeEventListener()
if(nodeJS) {
global.WebSocket = websocket.w3cwebsocket;
}
this.slow(250);
pws = new PersistentWS('ws://localhost:8080/');
var listener = new sinon.spy();
pws.addEventListener('open', listener);
pws.removeEventListener('open', listener);
setTimeout(function() {
assert.strictEqual(listener.called, false);
done();
}, 100);
// Swap WebSocket library back
if(nodeJS) {
global.WebSocket = ws;
}
});
test('Event listeners removed with .removeEventListener should not fire after reconnecting', function(done) {
// Swap to WebSocket library that supports .removeEventListener()
if(nodeJS) {
global.WebSocket = websocket.w3cwebsocket;
}
this.slow(500);
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100});
var listener = new sinon.spy();
pws.addEventListener('open', listener);
pws.removeEventListener('open', listener);
pws.onopen = function() {
pws.close();
pws.onopen = function() {
// Has just reconnected
setTimeout(function() {
assert.strictEqual(listener.called, false);
done();
}, 100);
}
}
// Swap WebSocket library back
if(nodeJS) {
global.WebSocket = ws;
}
});
test('Should talk to console if .verbose is set', function() {
var spy = new sinon.stub(console, 'log');
pws = new PersistentWS('ws://localhost:8080/', undefined, {verbose: true});
assert.strictEqual(spy.called, true);
pws.verbose = false;
console.log.restore();
});
test('Should not talk to console if .verbose is not set', function() {
var spy = new sinon.stub(console, 'log');
pws = new PersistentWS('ws://localhost:8080/');
assert.strictEqual(spy.called, false);
console.log.restore();
});
});
suite('Logging', function() {
test('If .verbose is false, no logging should be done', function(done) {
this.slow(250);
sinon.stub(console, 'log');
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100});
pws.onopen = function() {
pws.close();
pws.onopen = function() {
assert.strictEqual(console.log.called, false);
console.log.restore();
done();
}
}
});
test('If .verbose is true, default .logger should call console.log()', function(done) {
this.slow(250);
sinon.stub(console, 'log');
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100, verbose: true});
pws.onopen = function() {
pws.close();
pws.onopen = function() {
assert.strictEqual(console.log.called, true);
console.log.restore();
done();
}
}
});
test('If .verbose is true with a custom .logger, all logs should go through .logger', function(done) {
this.slow(250);
sinon.stub(console, 'log');
var aLogger = sinon.spy();
pws = new PersistentWS('ws://localhost:8080/', undefined, {initialRetryTime: 100, verbose: true, logger: aLogger});
pws.onopen = function() {
pws.close();
pws.onopen = function() {
assert.strictEqual(console.log.called, false);
assert.strictEqual(aLogger.called, true);
console.log.restore();
done();
}
}
});
});