Currently, I am attempting to simulate the native WebSocket in a jasmine test for Angular. I have successfully spied on the constructor and `send` function, but I am struggling to figure out how to fake a call of `onmessage`.
The WebSocket has been extracted to an Angular constant named `webSocket`.
This is what my test setup looks like:
describe('Data Service', function () {
var dataService,
$interval,
ws;
beforeEach(function () {
module('core', function ($provide) {
ws = jasmine.createSpy('constructor');
ws.receiveMessage = function (message) {
this.onmessage(message);
};
$provide.constant('webSocket', ws);
});
inject(function (_dataService_, _$interval_) {
dataService = _dataService_;
$interval = _$interval_;
});
});
it("should call subscribers when a message is received", function () {
var callback = jasmine.createSpy('onMessage callback');
function message(type) {
return {
data: {
type: type,
data: 'data'
}
};
}
// Subscribe to messages via the exposed function.
// Subscribe to one of them twice to test that all subscribers are called and not just the first one.
dataService.onMessage(21, callback);
dataService.onMessage(21, callback);
dataService.onMessage(22, callback);
dataService.onMessage(23, callback);
// Pick 3 numbers that are valid data types to test.
ws.receiveMessage(message(21));
ws.receiveMessage(message(22));
ws.receiveMessage(message(23));
expect(callback.calls.count()).toBe(4);
expect(callback.calls.allArgs()).toBe([message(21).data, message(21).data, message(22).data, message(23).data]);
});
});
This is the code snippet that I am working with:
angular.module('core', []).constant('webSocket', WebSocket);
angular.module('core').factory('dataService', function ($interval, webSocket) {
function openSocket() {
sock = new webSocket('ws://localhost:9988');
sock.onmessage = function (message) {
var json = JSON.parse(message.data);
onMessageSubscribers[json.type].forEach(function (sub) {
sub(json);
});
};
}
function onMessage(type, func) {
onMessageSubscribers[type].push(func);
}
openSocket();
return {
onMessage: onMessage
};
});
The array `onMessageSubscribers` contains the correct types as keys, but this is irrelevant to the issue at hand.
When running the test, I encounter the following error:
TypeError: 'undefined' is not a function (evaluating 'this.onmessage(message)')
`onmessage` seems to be defined by the angular code that executes before the test, however, I suspect there might be something related to how a constructed object differs from a regular object in JavaScript, which I do not have much experience with.
I have experimented with various approaches, such as calling `ws.prototype.onmessage` or simply `ws.onmessage`.
If I insert a `console.log(sock.onmessage);` in `dataService` at the appropriate location, and another log before invoking `onmessage` in the tests:
function (message) { ... }
undefined
How can I trigger a call to onmessage or any other WebSocket event?