Unit testing of websocket application by sinon.js - javascript

I have tried to do unit testing for a web socket application using sinon.js,
One of the users on github of sinon, did this, but I am not able to understand how it does help to unit test websocket applications for validating the received data which was sent to fake server.
var dummySocket = { send : sinon.spy()};
sinon.stub(window, 'WebSocket').returns(dummySocket);
dummySocket = new WebSocket('ws://html5rocks.websocket.org/echo');
dummySocket.onopen();
dummySocket.onmessage(JSON.stringify({ hello : 'from server' }));
// You can assert whether your code sent something to the server like this:
sinon.assert.calledWith(dummySocket.send, '{"the client":"says hi"}');
My questions are
How can I receive the same data from fake server which have been sent to server earlier.
How can I send data to fake server by using send method of fake socket object(eg:- socket.send())?
How can I get data from server on dummySocket.onmessage = function (msg){}
With sinon.js, I could not get the any process to create fake websocket object like for fake XMLHttpRequest and server by using respectively useFakeXMLHttpRequest() and fakeServer.create()
Is there any process to achieve this on sinon.js?

Normally, you would do ws = sinon.createStubInstance(WebSocket), but this isn't possible since properties on the WebSocket.prototype throw exceptions when reading them. There are two ways around this.
You could add a useFakeWebSocket to sinon to overwrite WebSocket. This would be similar to what useFakeXMLHttpRequest does to XMLHttpRequest.
Duck type out a WebSocket object by iterating over the prototype.
beforeEach(function () {
var ws = {};
for (var prop in WebSocket.prototype) {
ws[prop] = function () {}; // some properties aren't functions.
}
});
If you wanted to implement a mock echo WebSocket server so that you can test your event handlers, you could do that with this:
var ws;
beforeEach(function () {
ws = {
send: function (msg) {
this.onmessage({ data: msg });
},
onmessage: function (e) {
// stub
}
};
});
it('should echo', function () {
var spy = sinon.spy(ws, 'onmessage');
ws.send('this is a test');
assertEquals(spy.args[0][0].data, 'this is a test');
});
I hope this is what you're looking for.

Related

(javascript) Unable to return value received in Socket.on(event)

Basically I have a client side code that sends data to the server, the server responds with data which calls a socket.on(event) in the client side code. Within the function that is immediately run I can log the received data but I cannot return it to outside for the life of me.
function receive_data(){
socket.off('Sent_data_to_client').on('Sent_data_to_client',(player_info));
console.log(player_info)
}
If i try to log player_info it tells me it is undefined "Uncaught (in promise) ReferenceError: player_info is not defined". I want to return player_info as the result of the receive_data function but it is undefined.
I am new to javascript and Socket.Io as a whole, i apologise for any obvious mistakes made.
Sockets in JS doesnt work like this. Have a specifics events.
https://nodejs.org/api/net.html#new-netsocketoptions
This is the Node JS documentation, but it doesn't matter because Node JS is based on "V8 engine", that is, it's the same.
As you can see in the documentation it indicates that there are a series of events that the socket can handle, among them the 'data', calling a callback function where you implement the necessary logic for your code.
In this case, for example:
const net = require('net');
const socket = new net.Socket();
// Open a socket connection with example.com
socket.connect(80, 'example.com', () => {
console.log('Connected');
});
socket.on('data', (data) => {
console.log(`Recived: ${data}`);
});
socket.on('error', (error) => {
console.log(`Error: ${error}`);
});
You should change the function definition to accept an argument, which will be the data that the server sends.
function receive_data(){
socket.off('Sent_data_to_client').on('Sent_data_to_client', function(player_info) {
console.log(player_info);
return player_info;
});
}

SignalR callback does not trigger in JQuery UI widget

I am trying to create a JQuery UI widget that receives realtime updates from a server using SignalR (2.2.0). Invoking a method on the server works just fine, however invoking a client callback from the server does not trigger on the client.
I have enabled logging on the client as is suggested here: SignalR Troubleshooting and I can see in the console that the connection is setup just fine but the client method is never invoked. There is no error message of any kind. I have also defined the client method on the hub proxy before starting the connection like so:
_bindClientCallbacks: function () {
theHub.client.broadCastToClient = function (message) {
twr.log(message);
};
}
and afterwards I start the hub connection like so:
_startSignalRClient: function () {
$.connection.hub.logging = true;
$.connection.hub.start()
.done(function () {
twr.log("Connected to SignalR hub, id=" + $.connection.hub.id);
})
.fail(function () {
});
}
These methods are called in the '_create()' function in the JQuery widget like so:
_create: function () {
theHub = $.connection.DataImportHub;
this._bindClientCallbacks();
this._startSignalRClient();
}
This works fine and I can get a valid connection with an id. I can also call a server method from the client. But when I try to invoke the broadCastToClient method on the client from the server like so:
public void BroadCastToClient(string userId, string message)
{
var hubContext = GlobalHost.ConnectionManager.GetHubContext<DataImportHub>();
foreach (var connectionId in _connections.GetConnections(userId))
{
hubContext.Clients.Client(connectionId).broadCastToClient(message);
}
}
Nothing happens on the client.. even though the server does find a valid connection that corresponds to the connection id I got on the client.
What am I missing here?
Just found out the solution by reading this post. Apparently having a custom SignalR dependency resolver setup in the Owin startup class breaks javascript callbacks. Moving the dependency resolver setup code to Application_Start in Global.asax does the trick. Why this happens really is beyond me...
Bad DI setup in Startup.cs
app.Map("/signalr", map =>
{
var hubConfiguration = new HubConfiguration
{
Resolver = new NinjectSignalRDependencyResolver(new StandardKernel())
};
map.RunSignalR(hubConfiguration);
});
Good DI setup in Global.asax
protected void Application_Start()
{
GlobalHost.DependencyResolver = new NinjectSignalRDependencyResolver(new StandardKernel());
}

Handling WebSocket connections in Jasmine tests

I have my test.login.js:
it('calls login when there\'s a username present', () => {
React.findDOMNode(LoginElement.refs.username).value = 'foo';
TestUtils.Simulate.submit(form);
expect(LoginElement.state.errored).toEqual(false);
});
By submitting the form, it calls a login method:
login() {
let typedUsername = React.findDOMNode(this.refs.username).value;
if (!typedUsername) {
return this.setState({
errored: true
});
}
// we don't actually send the request from here, but set the username on the AuthModel and call the `login` method below
AuthModel.set('username', typedUsername);
AuthModel.login();
},
So I'm trying to test the functionality of Login.jsx, not AuthModel.js, however by calling AuthModel.login(), it sends a message over a WebSocket. However, the issue is that in my actual app, I don't load anything until the WebSocket has connected (I fire an event to then render the React app), however in my Jasmine test, I don't wait for this event, so I receive:
ERROR: null, DOMException{stack: 'Error: Failed to execute 'send' on 'WebSocket': Still in CONNECTING state.
And my test fails, which, it shouldn't fail because it's encapsulated functionality does what I want it to. It just errors further up the dependency tree.
What is my best approach for either working around this, or to mitigate the WebSocket trying to connect in my test env? (I'm extremely new to testing, so these concepts are very alien to me right now)
I won't pretend to know a lot about this, but can't you dependency inject AuthModel so how and then mock it in your tests? Sorry this isn't a complete answer it's just what my first instinct would be.
If you need a library to assist this, angular/di (from angular2) is pretty great.
You could mock / stub the server request using Sinon JS. - http://sinonjs.org/
If you just want to know that Auth.login makes a request to the server, use sinon.stub (http://sinonjs.org/docs/#stubs), e.g.
var stub = sinon.stub($, 'ajax');
//Do something that calls $.ajax
//Check stub was called and arguments of first call:
console.log(stub.called)
console.log(stub.args[0])
stub.restore();
If your code requires a response, use sinon's fake server (http://sinonjs.org/docs/#server):
var server = sinon.fakeServer.create(),
myResults = [1, 2, 3];
//Set-up server response with correct selected tags
server.respondWith('POST', url, [200, {
'Content-Type': 'application/json'
},
JSON.stringify({
response: myResults
})
]);
//Do something which posts to the server...
sendToServer('abc').done(function(results) {
console.log('checking for results ', results);
})
server.restore();
You can get a lot more complicated with the server responses - using functions, etc. to handle multiple request types, e.g.
function initServer(respondOk) {
var server = sinon.fakeServer.create();
server.respondWith('POST', /.*\/endpoint\/.*/, function(request) {
var header = { 'Content-Type': 'application/json' };
if(!respondOk) {
var response = JSON.stringify([{
'error_code': '500',
'message': 'Internal server error'
}]);
request.respond(500, header, response);
} else {
var code = 200,
resources = JSON.parse(request.requestBody),
result = JSON.stringify({ customer: resources });
request.respond(code, header, result);
}
});
return server;
});

Websockets in python and js

I am currently creating a website and I'm totally confused about Websockets.
I have some data in a database that is shown on my website. Now every once in a while there are new entries in the database, which should be shown on the website without reloading it, now I thought this could somehow be achieved using websockets.
I'm using web.py as framework for my website, and I use AngularJS.
In my app.py, I recieve the database entries and return them as JSON.
In js I want to receive the JSON message and save it in the $scope, which then gets "printed" on the website using AngularJS and I created a client side WebSocket for it like this:
var app = angular.module('web');
app.factory('runservice', function() {
var service = {};
service.connect = function() {
if(service.ws) { return; }
var ws = new WebSocket('wss://localhost:8080');
ws.onopen = function() {
service.callback("Success");
};
ws.onerror = function(evt) {
service.callback("Error: " + evt.data);
}
ws.onmessage = function(message) {
service.callback(message.data);
};
service.ws = ws;
}
service.subscribe = function(callback) {
service.callback = callback;
}
return service;
});
app.controller('runController', function($scope, runservice) {
runservice.connect();
runservice.subscribe(function(message) {
var data = JSON.parse(message);
$scope.runs = data;
});
});
Now, do I need a server side socket in my app.py or something else? If so, can anyone provide an example how I'd achieve this in web.py?
You definitely need to have websocket code on your server, or else your client isn't keeping a connection alive with your server and vice versa.
If your wish is to make use of realtime websockets, then this package for your web.py application server https://github.com/songdi/webpy-socketio will be very useful, as will this for you angular client application https://github.com/btford/angular-socket-io
Another option would be to simply long poll your server. AKA make asynchronous requests every ~10 seconds or so to your application and retrieve only the newest entries.
I hope this is of some help!

Call specific functions with Websockets?

I'm trying to deploy an app with Heroku but I guess they don't allow use of Socket.IO so I have to use basic WebSockets. How do I send data to specific functions e.g.
With sockets it would be:
// Server
socket.on('testFunction', function(data) {
console.log(data);
});
// Client
socket.emit('testFunction', 'Hello!');
But with Websockets from what I've googled all I can find is
// Server
ws.onmessage = function(data) {};
// Client
ws.send('This is a string, what do I do with myself');
Any information would be great. Thanks!
See here for some documentation and examples.
Here are some rough equivalents to your Socket.IO examples:
// Server
ws.onmessage = function(event) {
var msg = JSON.parse(event.data);
switch(msg.type) {
case "testFunction":
console.log(msg.text);
break;
}
};
// Client
ws.send(JSON.stringify({type: "testFunction", text: "Hello!"}));
The solution to your problem depends on your server side code.
The way i solved the function calling problem, is by sending my data to server as an object( stringified), containing controller and action properties.
e.g in pseudo code
var request = {controller: "users", action: "login", params: {username: "loginuser", password: "333"} };
socket.emit(JSON.stringify( request) );
and on server side i get the controller value, and instantiate a new controller based on it...eg new users_controller(), and call the action on that controller with the params sent from emit.
Of course you need to test if controllers and actions exists, handle errors etc.

Categories

Resources