// Clone this Gist repo, install the packages with `npm install`, then run the test with `node --test`. The test should hang. import { it, afterEach, describe, beforeEach } from 'node:test'; import Fastify from 'fastify'; import fastifyPlugin from 'fastify-plugin'; import fastifyWebSocket from '@fastify/websocket'; import WebSocket from 'ws'; /** @param {FastifyInstance} fastify */ async function plugin(fastify) { fastify.addHook('onClose', async (instance) => { for (const client of instance.websocketServer.clients) { client.close(WebSocketStatus.GOING_AWAY); } }); await fastify.register(fastifyWebSocket, { options: { clientTracking: true } }); fastify.get('/signal', { websocket: true, preHandler: [ /* some handlers for authentication and validation (can post if relevant) */ ], }, async (socket, request) => { socket.on('message', async (data) => { try { console.log("Got a message"); const message = JSON.parse(data.toString()); console.log(message); } catch (error) { if (error instanceof SyntaxError) { // If the message isn't valid JSON... socket.close(1007, 'Invalid JSON format'); return; } } }); }); } const signalling = fastifyPlugin(plugin, { name: 'signalling', fastify: '5.x' }); /** @returns {Promise} */ async function buildApp() { const fastify = Fastify(); await fastify.register(signalling); return fastify; } describe('Signalling Endpoint Protocol', async () => { /** @type {FastifyInstance} */ let app; /** @type {WebSocket} */ let ws; beforeEach(async () => { app = await buildApp(); await app.ready(); ws = await app.injectWS('/signal'); }); afterEach(async () => { ws?.terminate(); await app.close(); }); it.only('disconnects if the client sends malformed JSON', async (t) => { /** * @type {{promise: Promise, resolve: (value?: WebSocketStatus | PromiseLike) => void, reject: (reason?: any) => void}} */ const {promise, resolve, reject} = Promise.withResolvers(); ws.once('close', resolve); ws.once('error', reject); ws.send('fgsfds', (error) => { if (error) { console.error("Error sending malformed JSON:", error); reject(error); } else { console.log("Malformed JSON sent successfully"); } }); t.assert.equal(await promise, 1007); // invalid frame payload data // hang begins here // execution continues here after the test times out await t.waitFor(() => ws.readyState); }); });