Testing Node.js and WebSockets Modules (Socket.io)

Can anyone provide a durable, dead simple unit test for Node.js using WebSockets (Socket.io)?

I use socket.io for Node.js, and looked at socket.io-client to establish a client connection to the server in the test. However, it seems I am missing something.

In the example below, "worked ..." is never printed.

var io = require('socket.io-client') , assert = require('assert') , expect = require('expect.js'); describe('Suite of unit tests', function() { describe('First (hopefully useful) test', function() { var socket = io.connect('http://localhost:3001'); socket.on('connect', function(done) { console.log('worked...'); done(); }); it('Doing some things with indexOf()', function() { expect([1, 2, 3].indexOf(5)).to.be.equal(-1); expect([1, 2, 3].indexOf(0)).to.be.equal(-1); }); }); }); 

Instead, I just get:

  Suite of unit tests First (hopefully useful) test ✓ Doing some things with indexOf() 1 test complete (26 ms) 

Any suggestions?

+55
unit-testing websocket
Mar 19 '13 at 19:57
source share
4 answers

After further pushing and pushing, I found incredibly useful information at http://blog.foundry376.com/2012/09/connecting-to-a-socket-io-server-from-node-js-unit-tests . In the author’s example, he points to a critical step in setting up socket listeners in “before *” hooks. This example works (assuming the server is listening on socket connections on localhost: 3001, of course)

 var io = require('socket.io-client') , assert = require('assert') , expect = require('expect.js'); describe('Suite of unit tests', function() { var socket; beforeEach(function(done) { // Setup socket = io.connect('http://localhost:3001', { 'reconnection delay' : 0 , 'reopen delay' : 0 , 'force new connection' : true }); socket.on('connect', function() { console.log('worked...'); done(); }); socket.on('disconnect', function() { console.log('disconnected...'); }) }); afterEach(function(done) { // Cleanup if(socket.connected) { console.log('disconnecting...'); socket.disconnect(); } else { // There will not be a connection unless you have done() in beforeEach, socket.on('connect'...) console.log('no connection to break...'); } done(); }); describe('First (hopefully useful) test', function() { it('Doing some things with indexOf()', function(done) { expect([1, 2, 3].indexOf(5)).to.be.equal(-1); expect([1, 2, 3].indexOf(0)).to.be.equal(-1); done(); }); it('Doing something else with indexOf()', function(done) { expect([1, 2, 3].indexOf(5)).to.be.equal(-1); expect([1, 2, 3].indexOf(0)).to.be.equal(-1); done(); }); }); }); 

I found that placing done () in a beforeEach listener, socket.on ('connect' ...) is crucial to establish a connection. For example, if you comment out done () in a listener, add it to one area (just before exiting beforeEach), you will see the message "no connection to break ..." instead of "disconnecting ..". For example:

 beforeEach(function(done) { // Setup socket = io.connect('http://localhost:3001', { 'reconnection delay' : 0 , 'reopen delay' : 0 , 'force new connection' : true }); socket.on('connect', function() { console.log('worked...'); //done(); }); socket.on('disconnect', function() { console.log('disconnected...'); }); done(); }); 

I am new to Mocha, so there may be a very obvious reason to initialize for put done () with the socket scope itself. I hope this little detail saves others on my boots from pulling hair.

For me, the above test (with the correct done () score) outputs:

  Suite of unit tests First (hopefully useful) test ◦ Doing some things with indexOf(): worked... ✓ Doing some things with indexOf() disconnecting... disconnected... ◦ Doing something else with indexOf(): worked... ✓ Doing something else with indexOf() disconnecting... disconnected... 2 tests complete (93 ms) 
+60
Mar 21 '13 at 16:30
source share

Offering an extension of the accepted answer here. Has a basic client connection to the server, useful as a template for other future tests. Use mocha, chai and expect.

 var io = require('socket.io-client') , io_server = require('socket.io').listen(3001); describe('basic socket.io example', function() { var socket; beforeEach(function(done) { // Setup socket = io.connect('http://localhost:3001', { 'reconnection delay' : 0 , 'reopen delay' : 0 , 'force new connection' : true , transports: ['websocket'] }); socket.on('connect', () => { done(); }); socket.on('disconnect', () => { // console.log('disconnected...'); }); }); afterEach((done) => { // Cleanup if(socket.connected) { socket.disconnect(); } io_server.close(); done(); }); it('should communicate', (done) => { // once connected, emit Hello World io_server.emit('echo', 'Hello World'); socket.once('echo', (message) => { // Check that the message matches expect(message).to.equal('Hello World'); done(); }); io_server.on('connection', (socket) => { expect(socket).to.not.be.null; }); }); }); 
+7
May 30 '16 at 4:32
source share

I had this problem: how to do unit test with "socket.io-client" if you do not know how long the server should respond?

I decided to use mocha and chai like this:

 var os = require('os'); var should = require("chai").should(); var socketio_client = require('socket.io-client'); var end_point = 'http://' + os.hostname() + ':8081'; var opts = {forceNew: true}; describe("async test with socket.io", function () { this.timeout(10000); it('Response should be an object', function (done) { setTimeout(function () { var socket_client = socketio_client(end_point, opts); socket_client.emit('event', 'ABCDEF'); socket_client.on('event response', function (data) { data.should.be.an('object'); socket_client.disconnect(); done(); }); socket_client.on('event response error', function (data) { console.error(data); socket_client.disconnect(); done(); }); }, 4000); }); }); 
+2
Feb 25 '16 at 9:00
source share

Check out this template solution, which is based on promises and good practice . With it, you can test all your events on the server, without any problems. You just need to copy the template test and add your own code as needed.

Check out the repository on GitHub for complete source code.

https://github.com/PatMan10/testing_socketIO_server

 const io = require("socket.io-client"); const ev = require("../utils/events"); const logger = require("../utils/logger"); // initSocket returns a promise // success: resolve a new socket object // fail: reject a error const initSocket = () => { return new Promise((resolve, reject) => { // create socket for communication const socket = io("localhost:5000", { "reconnection delay": 0, "reopen delay": 0, "force new connection": true }); // define event handler for sucessfull connection socket.on(ev.CONNECT, () => { logger.info("connected"); resolve(socket); }); // if connection takes longer than 5 seconds throw error setTimeout(() => { reject(new Error("Failed to connect wihtin 5 seconds.")); }, 5000); } ); }; // destroySocket returns a promise // success: resolve true // fail: resolve false const destroySocket = socket => { return new Promise((resolve, reject) => { // check if socket connected if (socket.connected) { // disconnect socket logger.info("disconnecting..."); socket.disconnect(); resolve(true); } else { // not connected logger.info("no connection to break..."); resolve(false); } }); }; describe("test suit: Echo & Bello", () => { test("test: ECHO", async () => { // create socket for communication const socketClient = await initSocket(); // create new promise for server response const serverResponse = new Promise((resolve, reject) => { // define a handler for the test event socketClient.on(ev.res_ECHO, data4Client => { //process data received from server const { message } = data4Client; logger.info("Server says: " + message); // destroy socket after server responds destroySocket(socketClient); // return data for testing resolve(data4Client); }); // if response takes longer than 5 seconds throw error setTimeout(() => { reject(new Error("Failed to get reponse, connection timed out...")); }, 5000); }); // define data 4 server const data4Server = { message: "CLIENT ECHO" }; // emit event with data to server logger.info("Emitting ECHO event"); socketClient.emit(ev.com_ECHO, data4Server); // wait for server to respond const { status, message } = await serverResponse; // check the response data expect(status).toBe(200); expect(message).toBe("SERVER ECHO"); }); test("test BELLO", async () => { const socketClient = await initSocket(); const serverResponse = new Promise((resolve, reject) => { socketClient.on(ev.res_BELLO, data4Client => { const { message } = data4Client; logger.info("Server says: " + message); destroySocket(socketClient); resolve(data4Client); }); setTimeout(() => { reject(new Error("Failed to get reponse, connection timed out...")); }, 5000); }); const data4Server = { message: "CLIENT BELLO" }; logger.info("Emitting BELLO event"); socketClient.emit(ev.com_BELLO, data4Server); const { status, message } = await serverResponse; expect(status).toBe(200); expect(message).toBe("SERVER BELLO"); }); }); 

---- Foot Note ----

Depending on how you configured your server environment, you may encounter an environment conflict between socket.io and socket.io-client running from the same project at the same time. In this case, it would be better to divide the project into a “test client” and a server. Checkout below repo if you get this problem.

https://github.com/PatMan10/testing_socketIO_server_v2

+2
Jan 27 '19 at 16:01
source share



All Articles