Reposting this SO question:
I am trying to spy on WebSocket construction with the following code (requirebin):
sinon = require('sinon');
sinon.spy(window, 'WebSocket');
// throws an error (see console)
new window.WebSocket("ws://example.com");
In Chrome it fails with Uncaught TypeError: Failed to construct 'WebSocket': Please use the 'new' operator, this DOM object constructor cannot be called as a function.
In Safari and PhantomJs it fails with TypeError: Attempted to wrap object property WebSocket as function
What am I doing wrong?
Native objects are notoriously unreliable as spying/stubbing targets.
If you're working with a level of indirection like Socket.IO, then I'd recommend targeting that for spying/stubbing. There are examples of how to do this with Sinon.JS.
If you're working closer to the metal, then I'd recommend using a very thin wrapper around the target natives, to allow spying/stubbing.
I created wrapple for this purpose, but it's simple enough to create your own.
// totally making things up here
function WrapWebSocket(){
return window.WebSocket;
}
// in your code
function init(){
var WS = WrapWebSocket();
var ws = new WS();
}
// in your test
var spy = sinon.spy();
sinon.stub(window, 'WrapWebSocket', function(){
return spy;
});
init();
assert(spy.calledWith('someurl');
Thanks for the explanation, now I understand what the problem is.
Wrapple seems like a reasonable workaraound. Thanks again!
Most helpful comment
Native objects are notoriously unreliable as spying/stubbing targets.
If you're working with a level of indirection like Socket.IO, then I'd recommend targeting that for spying/stubbing. There are examples of how to do this with Sinon.JS.
If you're working closer to the metal, then I'd recommend using a very thin wrapper around the target natives, to allow spying/stubbing.
I created wrapple for this purpose, but it's simple enough to create your own.