I'm trying to test (using Vitest) a part of my Fastify app that uses @fastify/websocket (and transitively ws), but my tests keep timing out despite running to completion. Here's a relevant excerpt from my test suite:
type CloseMessage = {
code: number,
reason: Buffer,
};
describe('Signalling Endpoint Protocol', () => {
let app: FastifyInstance;
let ws: WebSocket;
beforeEach(async () => {
app = await buildApp();
await app.ready();
ws = await app.injectWS('/signal', {
headers: {
authorization: `Bearer ${MOCK_TOKEN}`,
'sec-websocket-protocol': SIGNALLING_PROTOCOL,
}
});
});
afterEach(async () => {
await app.close();
ws?.terminate();
});
it('disconnects if the client sends malformed JSON', async () => {
const { promise, resolve } = Promise.withResolvers<CloseMessage>();
ws.once('close', (code, reason) => {
resolve({ code, reason });
});
ws.send('fgsfds'); // Invalid JSON
const { code } = await promise;
// prints, but wrongly attributed to a different test
// (the one that normally comes after this one)
console.log(`awaited code ${code}`);
expect(code).toBe(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA);
expect(ws.readyState).toBe(WebSocket.CLOSED);
console.log("tests are done");
// runs to here, then times out
});
});
The timeout happens some time between the ws.send() and await promise calls (as indicated by console.log). So the test times out, but then finishes.
Any idea why this happens? I'm using Fastify 5.4.0, @fastify/websocket 11.2.0, Node 22.13.1, and Vitest 3.2.4.
ittest runs in parallel and everyone use the samewsthing - why don't isolate it by creating a factory instead of using before/after?