done method "ignored" in beforeEach in mochajs test - node.js

I have a unit test for my wrapper around a web socket client. Here is the code to the test:
describe('server', function(){
var server;
beforeEach(function(done) {
server = new Server(function() {
//try to connect to the server on the expected port
var socket = new WebSocket('ws://localhost:8081');
});
server.wss.on('connection', function(client) {
server.wss.close();
done();
});
});
describe('#server', function(){
it('starts a server on a given port', function(done) {
var test = 1;
test.should.be.ok;
});
});
});
the issue that i'm running into is that while done is called properly (if i call done a second time right after the first time, i get an error that it was called twice) it does not seem to have any effect. Namely the test will fail after two second with:
Error: timeout of 2000ms exceeded
I'm kind of new at this, so i probably missed something easy...
Thanks, olivier

As usual, once you post the question you find the answer.
The trick is to call done inside each of the tests too.
describe('server', function(){
var server;
beforeEach(function(done) {
server = new Server(function() {
//try to connect to the server on the expected port
var socket = new WebSocket('ws://localhost:8081');
});
server.wss.on('connection', function(client) {
server.wss.close();
done();
});
});
describe('#server', function(){
it('starts a server on a given port', function(done) {
var test = 1;
test.should.be.ok;
=====> done();
});
});
});

Related

How to write a code to simulate the same as echo server from Websocket.org

i need to create a server based on the same logic as the echo server on websocket.org.
The difference is that the server will not echo exactly what the user typed, but will return a response that varies with the received string.
I've been looking for more than a week and I only found n examples that only explain the client, some of which include an example of a server that does NOT answer wss:// calls.
Everything I found responds only to calls http://192.168.1.1:3000 or https://192.168.1.1:3000, but when I use wss: //192.168.1.1:3000, Firefox says, it was unable to establish a connection with the wss server: //192.168.1.1:3000/.
The client works when I call wss: //echo.websocket.org/.
Where do I find the code for an echo server that responds to wss?
Above I list the code I found on github. The nodejs server code I'm trying is:
const http = require('http');
const ws = require('ws');
const wss = new ws.Server({noServer: true});
console.log("Script has started");
if (!module.parent) {
console.log("Listening on port 3000");
http.createServer(accept).listen(3000);
} else {
exports.accept = accept;
}
function accept(req, res) {
console.log("accept event started");
// all incoming requests must be websockets
if (!req.headers.upgrade || req.headers.upgrade.toLowerCase() != 'websocket') {
console.log("This is no websocket!!! Return");
res.end();
return;
}
// can be Connection: keep-alive, Upgrade
if (!req.headers.connection.match(/\bupgrade\b/i)) {
res.end();
return;
}
console.log("Handle upgrade");
wss.handleUpgrade(req, req.socket, Buffer.alloc(0), onConnect);
}
function onConnect(ws) {
console.log("onConnect event started");
ws.on('message', function (message) {
let name = message.match(/([\p{Alpha}\p{M}\p{Nd}\p{Pc}\p{Join_C}]+)$/gu) || "Guest";
console.log("Send Hello");
ws.send(`Hello from server, ${name}!`);
setTimeout(() => ws.close(1000, "Bye!"), 5000);
});
}
This code, responds "This is no websocket!!! Return" if I call the server with http://192.168.1.1: 3000/
Thank you in advance.
After a while I found the solution:
// Basic Websocket (ws) echo server
const WebSocket = require('ws');
const ws_server = new WebSocket.Server({ port: 81 });
ws_server.on('connection', function connection(ws) {
console.log("A client connected");
ws.on('message', function incoming(message) {
ws.send('Hi, you sent me ' + message);
});
});
This works for my tests.

Testing with Mocha in Node.js

I'm getting really inconsistent behavior in my terminal when console.logging inside of a test I wrote using mocha. We are running a node.js server and running socket.io. Does the console.log not go to the terminal only some of the time for some reason? I'm really confused about this behavior.
➜ tests git:(master) ✗ mocha test-chat-server.js
hello world
echo
✓ echos message (68ms)
On Connect Things Should Happen
✓ initial connection events
disconnected
i'm here
2 passing (93ms)
➜ tests git:(master) ✗ mocha test-chat-server.js
hello world
echo
✓ echos message (61ms)
On Connect Things Should Happen
✓ initial connection events
2 passing (77ms)
The difference between these two times I ran the mocha test are the console.log statements that appears in the first test run (disconnected, i'm here). They do not appear in the second test that I ran.
Edit: posting my test code in response to the comment (thank you!)
var should = require('should');
var socket = require('socket.io-client')('http://localhost:3000');
describe("echo", function () {
var server,
options ={
transports: ['websocket'],
'force new connection': true
};
it("echos message", function (done) {
var client = socket.connect("http://localhost:3000", options);
client.once("connect", function () {
client.once("echo", function (message) {
message.should.equal("Hello World");
client.disconnect();
done();
});
client.emit("echo", "Hello World");
});
done();
});
});
describe("On Connect Things Should Happen", function() {
it('initial connection events', function() {
should.exist(socket);
socket.open();
socket.compress(false).emit('an event', { some: 'data' });
socket.on('error', function() {
console.log('error');
});
socket.connect();
socket.on('disconnect', function(connection) {
console.log('disconnected');
console.log("i'm here");
});
socket.on('connect', function(connection) {
console.log('connected');
});
});
});
You are falling into the classic node async trap. Your "things should happen" test sometimes returns before the disconnect event happens and sometimes not.
You need to handle the done function the same way you do in the "echoes message" test. Punctually, it should like this:
socket.on('disconnect', function(connection) {
console.log('disconnected');
console.log("i'm here");
done()});
In general, I'm not sure how much that test makes handling all those different callbacks.

Socket.io connected but not communicating

I have a very simple configuration in a node server with socket.io installed (a little bit more complex but essentially like this one):
var main = require('express')();
server = require('http').createServer(main);
io = require('socket.io')(server);
io.use(function(socket, next) {
console.log("middleware!");
next();
});
io.on('connection', function (socket) {
console.log('connected...');
socket.on('pong', function (data) {
console.log(data.message);
});
setTimeout(function() {
console.log("Saying hello");
socket.emit('ping', { message: 'Hello from server ' + Date.now() });
}, 1000);
});
server.listen(2080, function onCreateServerMain() {
console.log('Server main is listening on port 2080';
console.log('************************************************************');
});
In the client:
var socketIoScript,
loadSocketTimeout,
trialsToLoadSocketIo = 0,
APP_CFG = {baseUrl : "http://192.168.1.13:2080"};
function loadSocketIo(socketIoIp) {
socketIoScript = document.createElement('script');
socketIoScript.setAttribute('src', socketIoIp);
socketIoScript.setAttribute('onload', 'onSocketLoaded();');
document.head.appendChild(socketIoScript);
}
window.onSocketLoaded = function onSocketLoaded() {
if (typeof(io.connect) === 'function') {
var mSocket,
mIoSocket;
$timeout.cancel(loadSocketTimeout);
mIoSocket = new io.Manager(APP_CFG.baseUrl);
mIoSocket.connect(function(socket) {
console.log('Connected!!');
});
mIoSocket.on('error', function onSocketError(e) {
console.log('WebSocket Error ' + error);
});
mIoSocket.on('ping', function onPingReceived(e) {
console.log('Server emitted ping: ' + e.data);
mSocket.emit('pong', 'hi server!');
});
}
}
~(function onLoadSocketTimeout() {
var nextTimeout;
if (trialsToLoadSocketIo < 10) {
nextTimeout = 5000;
} else if (trialsToLoadSocketIo > 60) {
nextTimeout = 60000;
} else {
nextTimeout = 1000 * trialsToLoadSocketIo;
}
if (socketIoScript) {
document.head.removeChild(socketIoScript);
}
loadSocketIo(APP_CFG.baseUrl + '/socket.io/socket.io.js#' + trialsToLoadSocketIo);
loadSocketTimeout = $timeout(onLoadSocketTimeout, nextTimeout);
trialsToLoadSocketIo += 1;
})();
(I'm doing like this because it's mobile app so it may have not connection). I'm testing it with Brackets and Chrome. Server and client are in the same machine. In the app the script is loaded fine and it connects to the server as I can it see in node log (edit: and this is all what I get in the node console):
Server main is listening on port 2080
************************************************************
middleware!
connected...
Saying hello
Edit: in Chrome console I don't get any message, and any breakpoint stops at on listeners. If I stop node, the console for the Chrome immediately starts logging that it has been disconnected:
GET http://192.168.1.13:2080/socket.io/?EIO=3&transport=polling&t=1413066902601-6 net::ERR_CONNECTION_REFUSED
GET http://192.168.1.13:2080/socket.io/?EIO=3&transport=polling&t=1413066906606-7 net::ERR_CONNECTION_REFUSED
But I can't see any incoming message. In the app I don't receive any incoming message. Is there any reason why I could not communicate in this environment even if socket is successfully connected?
EDIT
No app is receiving events sent from the other side. Logs from node show this, logs from Chrome are empty.
EDIT
In Chrome app I don't receive console.log("Connected!");. But neither I receive ERR_CONNECTION_REFUSED errors: I don't receive anything.
EDIT
I managed to get console.log("Connected!"); in the app by changing Manager options:
mIoSocket = new io.Manager(APP_CFG.baseUrl, { autoConnect: false });
As it was auto connecting and the events were attached after connection was made, "Connected" was never reached. But I'm still not receiving any event in any app.
I had a similar issue were event callbacks on the server were not firing when emitting. My event names were ping and pong. As soon as I renamed these events everything worked.
I suspect the event names ping and pong are reserved by socket.io and so cannot be used.
Ok, so a few things :
First, var mSocket doesn't seem to be initialized, so it may be difficult for it to emit() anything (am I missing something?)
Second, when you do :
socket.on('pong', function (data) {
console.log(data.message);
});
the server expects to receive an object containing a message property, eg : data = {message:'hi server'} In your case, you send a string, so data is 'Hi server !' and your log will say 'undefined'. You should change this bit to :
socket.on('pong', function (data) {
console.log(data);
});
and you have a similar problem the other way around, you send an object : { message: 'Hello from server ' + Date.now() }, and are trying to log a data property which does not exist. Change this bit to :
console.log('Server emitted ping: ' + e.message);
And third , you have to listen for events on the socket, not the 'manager'
Client :
mIoSocket.connect(function(socket) {
console.log('Connected!!');
socket.emit('pong');
socket.on('error', function onSocketError(e) {
console.log('WebSocket Error ' + error);
});
socket.on('ping', function onPingReceived(e) {
console.log('Server emitted ping: ' + e.data);
socket.emit('pong', 'hi server!');
});
});
Server :
io.on('connection', function (socket) {
console.log('connected...');
socket.on('pong', function (data) {
console.log(data);
});
setTimeout(function() {
console.log("Saying hello");
socket.emit('ping', { message: 'Hello from server ' + Date.now() });
}, 1000);
});

Trying to test a Node.js Server process using Mocha

Fairly new to Node.js
Made an app that runs a server process and serve files (does not use express or any frameworks), Now I'm trying to unit test it.
I'm trying to use a mocha test for that... I intended to start my server process and then run requests against it to test the expected results (stats code, body content and the likes)
However it's not working properly, all the request fail to connect to the server... I'm pretty sure that the issue is because node is juts running one process loop, the server is not running "in the background" while the queries run or possibly the server is not running yet (started ASYNC) while the request are being made ?
Anyway I was wondering what was the proper way to test this, I assume that either I need to have the server run in the background (like a forked process) and/or maybe I need to find a way to wait for the server process to be "up" first but not sure how.
Or at least recommendations on testing such server process (with Mocha or other).
Thanks.
Here is example test code (Updated since original question)
var server = new Server302('./fixture/');
var instance;
describe('Tests', function() {
before(function(done) {
instance = http.createServer(function(request, response) {
console.log(request.url);
server.serve(request, response);
}).listen(8000);
instance.on("listening", function() {
console.log("started");
done();
});
});
after(function(done){
instance.close();
console.log("stopped");
done();
});
it("Should fetch test.html", function(done) {
console.log("test1");
http.get("http://localhost:8000/", function(res) {
res.on('data', function(body) {
console.log(body)
expect(body).toEqual("test");
done();
});
})
});
It seem to Execute in order but still fails with a connection error, whereas it works when testing manually with the browser:
started
test1
․․․stopped
✖ 1 of 1 tests failed:
1) Tests Should fetch test.html:
Error: connect ECONNREFUSED
at errnoException (net.js:670:11)
at Object.afterConnect [as oncomplete] (net.js:661:19)
In your before don't call done until you get the "listening" event fired by the server.
before(function(done) {
instance = http.createServer(function(request, response) {
console.log(request.url);
server.serve(request, response);
}).listen(8000);
instance.on("listening", function() {
console.log("started");
done();
});
});
That should ensure your test connections don't start before the server is ready.
See also the documentation for server.listen
Also had to deal with the body coming in chunks, here is the final thing that works, in case that helps somebody else:
var Server302 = require('../lib/server302.js'),
http = require('http'),
assert = require("assert");
var server = new Server302('./fixture/');
var instance;
describe('Tests', function() {
before(function(done) {
instance = http.createServer(function(request, response) {
server.serve(request, response);
}).listen(8100);
instance.on("listening", function() {
done();
});
});
after(function(done) {
instance.close();
done();
});
it("Should fetch test.html", function(done) {
console.log("test1");
var body = "";
http.get({host: "localhost", port:8100, path: "/"}, function(res) {
res.on('data', function(chunk) {
// Note: it might be chunked, so need to read the whole thing.
body += chunk;
});
res.on('end', function() {
assert.ok(body.toString().indexOf("<a href='/dummy.txt'>") !== -1);
assert.equal(res.statusCode, 200);
done();
});
})
});
it("Should fetch dummy.txt", function(done) {
http.get({host: "localhost", port:8100, path: "/dummy.txt"}, function(res) {
res.on('data', function(body) {
assert.equal(res.statusCode, 200);
assert.ok(body.toString().indexOf("test") === 0);
done();
});
});
});
it("Should get 404", function(done) {
http.get({host: "localhost", port:8100, path: "/qwerty"}, function(res) {
assert.equal(res.statusCode, 404);
done();
});
});
});
Using SuperTest
Here is a full and straightforward example using SuperTest and Mocha:
var server = new Server302('./fixture/');
var request = require('supertest');
describe('Tests', function() {
it('Should fetch test.html', function(done) {
request(server)
.get('/')
.expect('test', done);
});
});
SuperTest allows you to:
Request your server using SuperAgent (much easier to use than the low level http agent).
Bound your server to an ephemeral port so there is no need to keep track of ports (you can still do it manually if needed).
Use sugary expect methods that works with Mocha (or any other test framework).

Socket.io not sending a message to all connected sockets

I'm trying out node.js and socket.io. I wan't to use to remove a ping function I have to get updates from my server. Here is an example code of what I'm doing:
var app = require('http').createServer(),
io = require('socket.io').listen(app),
cp = require('child_process');
app.listen(8080);
//I check a global value for all the connected users from the php command line
var t = setInterval(function(){
cp.exec('/usr/bin/php /Users/crear/Projects/MandaFree/symfony api:getRemainingMessages',
function(err, stdout){
if (err) {
io.sockets.emit('error', 'An error ocurred while running child process.');
} else {
io.sockets.emit('change', stdout);
}
console.log('Remaining messages: ' + stdout);
});
}, 3000);
var remaining = io.of('/getRemainingMessages')
.on('connection', function(socket){
socket.on('disconnect', function(){});
});
The Issue here, is that when I call io.sockets.emit() the debug console tells me it is doing something, but it looks like it is not getting to the clients. Because they are doing nothing.
I use to have one interval for every connected client, and when I used socket.emit() it did worked. But it is not the optimal solution.
UPDATE:
Here is my client side code.
var remaining = io.connect('http://127.0.0.1:8080/getRemainingMessages');
remaining.on('change', function(data){
console.log('Remaining messages: ' + data );
$('#count').html(data);
});
remaining.on('error', function(error){
console.log(error);
});
Had a very similar issue couple of days back and looks like socket.io had some changes in the API. I have never worked with symfony and am hoping the issues are the same.
I have a working demo of socket.io sending and receiving a message - uploaded to https://github.com/parj/node-websocket-demo as a reference
Essentially two changes
On Server side - changed socket.on to socket.sockets.on
var socket = io.listen(server);
socket.sockets.on('connection', function(client)
On Client side - URL and port not required as it is autodetected.
var socket = io.connect();
This has been tested using Express 2.5.2 and Socket.io 0.8.7
I have amalgamated your server code with mine, would you be able to try this on the server and my client javascript and client html just to see if it is working?
var socket = io.listen(server);
socket.sockets.on('connection', function(client){
var connected = true;
client.on('message', function(m){
sys.log('Message received: '+m);
});
client.on('disconnect', function(){
connected = false;
});
var t = setInterval(function(){
if (!connected) {
return;
}
cp.exec('/usr/bin/php /Users/crear/Projects/MandaFree/symfony api:getRemainingMessages',
function(err, stdout){
if (err) {
client.send('error : An error ocurred while running child process.');
} else {
client.send('change : ' + stdout);
}
console.log('Remaining messages: ' + stdout);
});
}, 3000);
t();
});

Resources