在 OP 的代码中,
socket.on('connect', function(done) {
console.log('worked...');
done();
});
done 应用于错误的回调。它应该从 socket.on 回调中移除并添加到 Mocha 的 it 块回调中:
it('First (hopefully useful) test', function (done) {
var socket = io.connect('http://localhost:3001');
socket.on('connect', function () {
console.log('worked...');
done();
});
});
一个完整的例子
现有答案很好,但没有显示最终正在测试的服务器。这是带有console.logs 的完整版本,用于说明正在发生的事情。解释如下。
src/server.js:
const express = require("express");
const createServer = (port=3000) => {
const app = express();
const http = require("http").Server(app);
const io = require("socket.io")(http);
io.on("connection", socket => {
console.log("[server] user connected");
socket.on("message", msg => {
console.log(`[server] received '${msg}'`);
socket.emit("message", msg);
});
socket.on("disconnect", () => {
console.log("[server] user disconnected");
});
});
http.listen(port, () =>
console.log(`[server] listening on port ${port}`)
);
return {
close: () => http.close(() =>
console.log("[server] closed")
)
};
};
module.exports = {createServer};
test/server.test.js:
const {expect} = require("chai");
const io = require("socket.io-client");
const {createServer} = require("../src/server");
const socketUrl = "http://localhost:3000";
describe("server", function () {
this.timeout(3000);
let server;
let sockets;
beforeEach(() => {
sockets = [];
server = createServer();
});
afterEach(() => {
sockets.forEach(e => e.disconnect())
server.close();
});
const makeSocket = (id=0) => {
const socket = io.connect(socketUrl, {
"reconnection delay": 0,
"reopen delay": 0,
"force new connection": true,
transports: ["websocket"],
});
socket.on("connect", () => {
console.log(`[client ${id}] connected`);
});
socket.on("disconnect", () => {
console.log(`[client ${id}] disconnected`);
});
sockets.push(socket);
return socket;
};
it("should echo a message to a client", done => {
const socket = makeSocket();
socket.emit("message", "hello world");
socket.on("message", msg => {
console.log(`[client] received '${msg}'`);
expect(msg).to.equal("hello world");
done();
});
});
it("should echo messages to multiple clients", () => {
const sockets = [...Array(5)].map((_, i) => makeSocket(i));
return Promise.all(sockets.map((socket, id) =>
new Promise((resolve, reject) => {
const msgs = [..."abcd"].map(e => e + id);
msgs.slice().forEach(e => socket.emit("message", e));
socket.on("message", msg => {
console.log(`[client ${id}] received '${msg}'`);
expect(msg).to.equal(msgs.shift());
if (msgs.length === 0) {
resolve();
}
});
})
));
});
});
总之,服务器导出一个函数,允许从头开始创建服务器应用程序,允许每个 it 块是幂等的,并避免服务器状态在测试之间传递(假设服务器上没有持久性)。创建应用程序会返回一个带有close 函数的对象。 socket.disconnect() 必须在每个测试中为每个套接字调用以避免超时。
鉴于这些要求,测试套件遵循以下每次测试设置/拆卸工作流程:
let server;
let sockets;
beforeEach(() => {
sockets = [];
server = createServer();
});
afterEach(() => {
sockets.forEach(e => e.disconnect())
server.close();
});
makeSocket 是一个可选的帮助器,用于减少连接和断开套接字客户端的重复样板。它确实会对sockets 数组产生副作用,以便稍后进行清理,但这是从it 块的角度来看的实现细节。测试块不应触及server 或sockets 变量,尽管其他工作流程可能取决于需要。关键要点是测试用例幂等性并在每个测试用例后关闭所有连接。
客户端上socket.connect 对象上的选项可让您选择套接字的传输和行为。 "force new connection": true 为每个套接字创建一个新的Manager,而不是重用现有的,transports: ["websocket"] 立即从长轮询升级到 WS 协议。
使用it("should ... ", done => { /* tests */ }); 并在回调中完成所有工作后调用done() 或返回一个promise(并省略it 回调的done 参数)。上面的示例显示了这两种方法。
在这篇文章中使用:
-
node: 12.19.0
-
chai:4.2.0
-
express:4.16.4
-
mocha:5.2.0
-
socket.io:2.2.0
-
socket.io-client:2.2.0