269 lines
7.5 KiB
JavaScript
269 lines
7.5 KiB
JavaScript
|
import * as WebSocketLib from 'src/lib/websocket';
|
||
|
|
||
|
describe('src/lib/websocket', () => {
|
||
|
describe('HomeHubWebSocket', () => {
|
||
|
const settings = {
|
||
|
url: '/websocket',
|
||
|
};
|
||
|
|
||
|
it('includes the subscribable mixin', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
|
||
|
// Then
|
||
|
expect(webSocket.__mixins__).toContain('SubscribableMixin');
|
||
|
});
|
||
|
|
||
|
it('includes the event source mixin', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
|
||
|
// Then
|
||
|
expect(webSocket.__mixins__).toContain('EventSourceMixin');
|
||
|
});
|
||
|
|
||
|
describe('constructor', () => {
|
||
|
it('initializes the instance', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
|
||
|
// Then
|
||
|
expect(webSocket.debug).toBe(false);
|
||
|
expect(webSocket.settings).toEqual(settings);
|
||
|
expect(webSocket.socket).toBe(null);
|
||
|
expect(webSocket.reconnectTimeout).toBe(null);
|
||
|
expect(webSocket.reconnectCounter).toEqual(0);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('logDebug', () => {
|
||
|
beforeEach(() => {
|
||
|
spyOn(console, 'log');
|
||
|
});
|
||
|
|
||
|
it('logs a message if debug is true', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(true, settings);
|
||
|
|
||
|
// When
|
||
|
webSocket.logDebug('Testing');
|
||
|
|
||
|
// Then
|
||
|
expect(console.log).toHaveBeenCalledWith('Testing'); // eslint-disable-line no-console
|
||
|
});
|
||
|
|
||
|
it('does not log a message if debug is false', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
|
||
|
// When
|
||
|
webSocket.logDebug('Testing');
|
||
|
|
||
|
// Then
|
||
|
expect(console.log).not.toHaveBeenCalled(); // eslint-disable-line no-console
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('stopReconnect', () => {
|
||
|
beforeEach(() => {
|
||
|
spyOn(window, 'clearTimeout');
|
||
|
});
|
||
|
|
||
|
it('stops the reconnect process', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
webSocket.reconnectTimeout = 123;
|
||
|
webSocket.reconnectCounter = 5;
|
||
|
|
||
|
// When
|
||
|
webSocket.stopReconnect();
|
||
|
|
||
|
// Then
|
||
|
expect(webSocket.reconnectTimeout).toBe(null);
|
||
|
expect(webSocket.reconnectCounter).toEqual(0);
|
||
|
expect(window.clearTimeout).toHaveBeenCalledWith(123);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('startReconnect', () => {
|
||
|
beforeEach(() => {
|
||
|
spyOn(window, 'setTimeout').and.returnValue(123);
|
||
|
});
|
||
|
|
||
|
it('starts the reconnect process', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
webSocket.reconnectCounter = 5;
|
||
|
|
||
|
// When
|
||
|
webSocket.startReconnect();
|
||
|
|
||
|
// Then
|
||
|
expect(webSocket.reconnectCounter).toEqual(6);
|
||
|
expect(webSocket.reconnectTimeout).toEqual(123);
|
||
|
expect(window.setTimeout).toHaveBeenCalledWith(webSocket.start, 1000);
|
||
|
});
|
||
|
|
||
|
it('breaks the reconnect process when retry count reaches limit', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
webSocket.reconnectCounter = 30;
|
||
|
spyOn(webSocket, 'stopReconnect');
|
||
|
|
||
|
// When
|
||
|
let error = null;
|
||
|
try {
|
||
|
webSocket.startReconnect();
|
||
|
} catch (exc) {
|
||
|
error = exc;
|
||
|
}
|
||
|
|
||
|
// Then
|
||
|
expect(error).toBeInstanceOf(Error);
|
||
|
expect(webSocket.stopReconnect).toHaveBeenCalled();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('start', () => {
|
||
|
let fakeWebSocket = null;
|
||
|
|
||
|
beforeEach(() => {
|
||
|
fakeWebSocket = jasmine.createSpyObj(['addEventListener', 'close']);
|
||
|
spyOn(window, 'WebSocket').and.returnValue(fakeWebSocket);
|
||
|
});
|
||
|
|
||
|
it('configures and opens the websocket connection', () => {
|
||
|
// Given
|
||
|
let fullSettings = {
|
||
|
...settings,
|
||
|
protocols: ['spam', 'eggs'],
|
||
|
};
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(
|
||
|
false, fullSettings
|
||
|
);
|
||
|
|
||
|
// When
|
||
|
webSocket.start();
|
||
|
|
||
|
// Then
|
||
|
expect(window.WebSocket).toHaveBeenCalledWith(
|
||
|
fullSettings.url, fullSettings.protocols
|
||
|
);
|
||
|
expect(fakeWebSocket.addEventListener).toHaveBeenCalledWith(
|
||
|
'open', webSocket.onSocketOpen
|
||
|
);
|
||
|
expect(fakeWebSocket.addEventListener).toHaveBeenCalledWith(
|
||
|
'close', webSocket.onSocketClose
|
||
|
);
|
||
|
expect(fakeWebSocket.addEventListener).toHaveBeenCalledWith(
|
||
|
'message', webSocket.onSocketMessage
|
||
|
);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('stop', () => {
|
||
|
let fakeWebSocket = null;
|
||
|
|
||
|
beforeEach(() => {
|
||
|
fakeWebSocket = jasmine.createSpyObj(['addEventListener', 'close']);
|
||
|
});
|
||
|
|
||
|
it('closes the websocket connection', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
webSocket.socket = fakeWebSocket;
|
||
|
|
||
|
// When
|
||
|
webSocket.stop();
|
||
|
|
||
|
// Then
|
||
|
expect(fakeWebSocket.close).toHaveBeenCalled();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('onSocketOpen', () => {
|
||
|
let fakeWebSocket = null;
|
||
|
|
||
|
beforeEach(() => {
|
||
|
fakeWebSocket = jasmine.createSpyObj(['addEventListener', 'close']);
|
||
|
fakeWebSocket.readyState = 1;
|
||
|
});
|
||
|
|
||
|
it('handles the open websocket event', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
webSocket.socket = fakeWebSocket;
|
||
|
spyOn(webSocket, 'logDebug');
|
||
|
spyOn(webSocket, 'stopReconnect');
|
||
|
spyOn(webSocket, 'fireEvent');
|
||
|
|
||
|
// When
|
||
|
webSocket.onSocketOpen();
|
||
|
|
||
|
// Then
|
||
|
expect(webSocket.logDebug).toHaveBeenCalled();
|
||
|
expect(webSocket.stopReconnect).toHaveBeenCalled();
|
||
|
expect(webSocket.fireEvent).toHaveBeenCalledWith('start');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('onSocketClose', () => {
|
||
|
it('handles the open websocket event', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
spyOn(webSocket, 'logDebug');
|
||
|
spyOn(webSocket, 'startReconnect');
|
||
|
spyOn(webSocket, 'fireEvent');
|
||
|
|
||
|
// When
|
||
|
webSocket.onSocketClose({code: 1000});
|
||
|
|
||
|
// Then
|
||
|
expect(webSocket.logDebug).toHaveBeenCalled();
|
||
|
expect(webSocket.startReconnect).toHaveBeenCalled();
|
||
|
expect(webSocket.fireEvent).toHaveBeenCalledWith('stop');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('onSocketMessage', () => {
|
||
|
beforeEach(() => {
|
||
|
spyOn(console, 'error');
|
||
|
});
|
||
|
|
||
|
it('gracefully handles JSON parse error', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
spyOn(webSocket, 'notify');
|
||
|
|
||
|
// When
|
||
|
webSocket.onSocketMessage({data: 'spam'});
|
||
|
|
||
|
// Then
|
||
|
expect(console.error).toHaveBeenCalledWith(
|
||
|
jasmine.any(String), jasmine.any(Error)
|
||
|
);
|
||
|
expect(webSocket.notify).not.toHaveBeenCalled();
|
||
|
});
|
||
|
|
||
|
it('parses the event data and notifies the subscribers', () => {
|
||
|
// Given
|
||
|
const webSocket = new WebSocketLib.HomeHubWebSocket(false, settings);
|
||
|
spyOn(webSocket, 'notify');
|
||
|
|
||
|
const message = {
|
||
|
type: 'TESTING',
|
||
|
data: {
|
||
|
spam: true,
|
||
|
},
|
||
|
};
|
||
|
|
||
|
// When
|
||
|
webSocket.onSocketMessage({data: JSON.stringify(message)});
|
||
|
|
||
|
// Then
|
||
|
expect(webSocket.notify).toHaveBeenCalledWith(message);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|