2014-04-18 15 views
5

Próbuję sprawdzić, czy onmessage jest prawidłową funkcją.Stubbing WebSocket w JavaScript z Jasmine

Tutaj jest test:

describe(".init(address, window)", function() { 
    beforeEach(function() { 
     address = 'ws://test.address'; 
     window = {}; 
     e = { 
     data: {} 
     } 
     spyOn(window, 'WebSocket').and.returnValue(function() {return {onmessage: null}}); 
     spyOn(subject, 'handleMessage'); 
    }); 

    it("should create a WebSocket client which connects to the given address", function() { 
     subject.init(address, window); 
     expect(window.WebSocket).toHaveBeenCalledWith(address); 
    }); 

    it("should have onmessage method overriden with a function which handles message", function() { 
     ws = subject.init(address, window); 
     alert(JSON.stringify(ws)); 
     ws.onmessage(e); 
     expect(subject.handleMessage).toHaveBeenCalledWith(e.data); 
    }); 
    }); 

Oto realizacja:

FL.init = function(address, window) { 
    if ('WebSocket' in window) { 
    var ws = new WebSocket(address); 
    ws.onmessage = function(e) { 
     this.handleMessage(e.data); 
    }; 
    return ws; 
    } 
}; 

Pierwszy test przechodzi. W drugim, ws jest undefined. Dlaczego? Próbowałem w konsoli new function() {return {onmessage: null}} i wygląda na to, że powinno być w porządku.

Odpowiedz

8

Nie jestem do końca pewien, czy udało mi się ustalić, w jaki sposób powinien zachowywać się twój kod, ale jeśli potrzebujesz szpiegować metodę WebSocket konstruktora i stubu .send, aby sfałszować niektóre wiadomości przychodzące, oto jak to osiągnąć.

Aby szpiegować WebSocket, należy zadzwonić pod numer .and.callThrough, a nie returnValue. Jednak to spowodować ze narzeka na brak new słów kluczowych (jak wspomniano w here), więc trzeba udawać konstruktora:

var realWS = WebSocket; 
var WebSocketSpy = spyOn(window, "WebSocket").and.callFake(function(url,protocols){ 
    return new realWS(url,protocols); 
}); 

Aby uczynić szpiega dla wiadomości przychodzących można po prostu zrobić

var onmessageCallbackSpy = jasmine.createSpy('onmessageCallback'); 

można również szpiegować .send metodzie, i podać kilka odpowiedzi szydzili z:

var sendSpy = spyOn(WebSocket.prototype, "send").and.callFake(function(outMsg){ 
    // process/check outgoing message 
    // setTimeout, or call it immediately 
    this.onmessage("mock message goes here"); 
}); 

Ale upewnij się, że używasz WebSocket.prototype, zanim zastąpisz go WebSocketSpy.

Więc pełny przykład roboczych, powinien wyglądać następująco:

it("should spy and callFake WebSocket constructor, and stub prototype methods", function (done) { 
    var realWS= WebSocket; 
    var sendSpy = spyOn(WebSocket.prototype, "send").and.callFake(function(outMsg){ 
     if(outMsg == "outgoing message"){ 
     this.onmessage("incoming mocked message goes here"); 
     } 
    }); 
    // var messageSpy = spyOn(WebSocket.prototype, "onmessage");//.and.returnValue("mock message goes here");  
    var WSSpy = spyOn(window, "WebSocket").and.callFake(function(url,protocols){ 
     return new realWS(url,protocols); 
    }); 
    var onmessageCallbackSpy = jasmine.createSpy('onmessageCallback');  

    // Your code 
    // (function init(url, onmessageCallbackSpy){ 
     var ws = new WebSocket("ws://some/where"); 
     ws.onmessage = onmessageCallbackSpy; 
     // code that results with receiving a message 
     // or mocked send, that calls `.onmessage` immediately 
     ws.send("outgoing message"); 
    // })();  

    expect(WSSpy).toHaveBeenCalledWith("ws://some/where"); 
    expect(onmessageCallbackSpy).toHaveBeenCalledWith("mock message goes here"); 
    done(); 
}); 
3

natknąłem niego próbuje szydzić z websocket dla testów jaśminu. Oto rozwiązanie, które wykorzystuje dość rozbudowane makiety window.WebSocket.

var socketMock; 
var windowMock; 
var address = 'ws://test.address'; 

describe(".init(address, window)", function() { 
    beforeEach(function() { 
    var WebSocket = jasmine.createSpy(); 
    WebSocket.and.callFake(function (url) { 
     socketMock = { 
     url: url, 
     readyState: WebSocket.CONNECTING, 
     send: jasmine.createSpy(), 
     close: jasmine.createSpy().and.callFake(function() { 
      socketMock.readyState = WebSocket.CLOSING; 
     }), 

     // methods to mock the internal behaviour of the real WebSocket 
     _open: function() { 
      socketMock.readyState = WebSocket.OPEN; 
      socketMock.onopen && socketMock.onopen(); 
     }, 
     _message: function (msg) { 
      socketMock.onmessage && socketMock.onmessage({data: msg}); 
     }, 
     _error: function() { 
      socketMock.readyState = WebSocket.CLOSED; 
      socketMock.onerror && socketMock.onerror(); 
     }, 
     _close: function() { 
      socketMock.readyState = WebSocket.CLOSED; 
      socketMock.onclose && socketMock.onclose(); 
     } 
     }; 
     return socketMock; 
    }); 
    WebSocket.CONNECTING = 0; 
    WebSocket.OPEN = 1; 
    WebSocket.CLOSING = 2; 
    WebSocket.CLOSED = 3; 

    windowMock = { 
     WebSocket: WebSocket 
    }; 
    spyOn(subject, 'handleMessage'); 
    }); 

    it("should create a WebSocket client which connects to the given address", function() { 
    subject.init(address, windowMock); 
    expect(windowMock.WebSocket).toHaveBeenCalledWith(address); 
    }); 

    it("should have onmessage method overriden with a function which handles message", function() { 
    var message = 'hello socket'; 
    subject.init(address, window); 

    // pretend the socket connected (optional) 
    socketMock._open(); 

    // pretend the socket got a message 
    socketMock._message(message) 

    expect(subject.handleMessage).toHaveBeenCalledWith(message); 
    }); 
});