From 350062cf6b2c3363ecf250e9fbadff5bb5b24b85 Mon Sep 17 00:00:00 2001 From: Adler Faulkner Date: Tue, 18 Jul 2023 16:17:54 -0400 Subject: [PATCH] feat(websockets): integration test for websockets --- .../WebSocketServerConfigurator.ts | 1 - test/integration/WebSockets.test.ts | 63 +++++++++++++++++++ test/integration/config/websocket-server.json | 46 ++++++++++++++ test/util/Util.ts | 1 + 4 files changed, 110 insertions(+), 1 deletion(-) create mode 100644 test/integration/WebSockets.test.ts create mode 100644 test/integration/config/websocket-server.json diff --git a/src/server/configurator/WebSocketServerConfigurator.ts b/src/server/configurator/WebSocketServerConfigurator.ts index 2790eea..3cf040c 100644 --- a/src/server/configurator/WebSocketServerConfigurator.ts +++ b/src/server/configurator/WebSocketServerConfigurator.ts @@ -24,7 +24,6 @@ export class WebSocketServerConfigurator extends ServerConfigurator { } public async handle(server: Server): Promise { - // Create WebSocket server const webSocketServer = new WebSocketServer({ noServer: true }); server.on('upgrade', (upgradeRequest: IncomingMessage, socket: Socket, head: Buffer): void => { webSocketServer.handleUpgrade(upgradeRequest, socket, head, async(webSocket: WebSocket): Promise => { diff --git a/test/integration/WebSockets.test.ts b/test/integration/WebSockets.test.ts new file mode 100644 index 0000000..12808aa --- /dev/null +++ b/test/integration/WebSockets.test.ts @@ -0,0 +1,63 @@ +/* eslint-disable @typescript-eslint/naming-convention */ +import { WebSocket } from 'ws'; +import { WebSocketHandler } from '../../src/http/handler/WebSocketHandler'; +import type { WebSocketHandlerInput } from '../../src/http/handler/WebSocketHandler'; +import type { App } from '../../src/init/App'; +import { getPort } from '../util/Util'; +import { + getDefaultVariables, + getTestConfigPath, + instantiateFromConfig, +} from './Config'; + +const port = getPort('WebSockets'); +const baseUrl = `http://localhost:${port}`; +const message = 'Hello there!'; + +class SimpleWebSocketHandler extends WebSocketHandler { + public async handle(input: WebSocketHandlerInput): Promise { + input.webSocket.send(message); + } +} + +describe('A http server with websocket endpoint handlers', (): void => { + let app: App; + + beforeAll(async(): Promise => { + const instances = await instantiateFromConfig( + 'urn:solid-on-rails:test:Instances', + getTestConfigPath('websocket-server.json'), + { + ...getDefaultVariables(port, baseUrl), + 'urn:solid-on-rails:default:ExampleWebSocketHandler': new SimpleWebSocketHandler(), + }, + ) as Record; + ({ app } = instances); + await app.start(); + }); + + afterAll(async(): Promise => { + await app.stop(); + }); + + it('handles websocket connections.', async(): Promise => { + let parsedMessage: string | undefined; + await new Promise((resolve, reject): void => { + const webSocket = new WebSocket(`ws://localhost:${port}/websocket-path`); + webSocket.on('message', (data): void => { + if (typeof data === 'string') { + parsedMessage = data; + } else if (data instanceof Buffer) { + parsedMessage = data.toString(); + } + webSocket.close(); + resolve(); + }); + webSocket.on('error', (error): void => { + reject(error); + }); + }); + + expect(parsedMessage).toEqual(message); + }); +}); diff --git a/test/integration/config/websocket-server.json b/test/integration/config/websocket-server.json new file mode 100644 index 0000000..b6609d6 --- /dev/null +++ b/test/integration/config/websocket-server.json @@ -0,0 +1,46 @@ +{ + "@context": "https://linkedsoftwaredependencies.org/bundles/npm/@comake/solid-on-rails/^0.0.0/components/context.jsonld", + "import": [ + "files-sor:config/app/main/default.json", + "files-sor:config/app/initialize/default.json", + "files-sor:config/app/finalize/default.json", + "files-sor:config/app/variables/default.json", + "files-sor:config/app/path/default.json", + "files-sor:config/http/static/default.json", + "files-sor:config/http/error-handler.json", + "files-sor:config/server/server-factory/default.json", + "files-sor:config/storage/key-value/memory.json", + "files-sor:config/util/variables/default.json", + "files-sor:config/util/logging/winston.json" + ], + "@graph": [ + { + "comment": "Attempt to resolve requests first as static assets, then as normal routes.", + "@id": "urn:solid-on-rails:default:HttpHandler", + "@type": "SequenceHandler", + "handlers": [ + { "@id": "urn:solid-on-rails:default:StaticAssetHandler" } + ] + }, + { + "@id": "urn:solid-on-rails:default:WebSocketHandler", + "WaterfallHandler:_handlers": [ + { "@id": "urn:solid-on-rails:default:ExampleWebSocketHandler" } + ] + }, + { + "@id": "urn:solid-on-rails:default:ExampleWebSocketHandler", + "@type": "Variable" + }, + { + "@id": "urn:solid-on-rails:test:Instances", + "@type": "RecordObject", + "RecordObject:_record": [ + { + "RecordObject:_record_key": "app", + "RecordObject:_record_value": { "@id": "urn:solid-on-rails:default:App" } + } + ] + } + ] +} diff --git a/test/util/Util.ts b/test/util/Util.ts index c9aa30a..989c834 100644 --- a/test/util/Util.ts +++ b/test/util/Util.ts @@ -8,6 +8,7 @@ const portNames = [ 'Job', 'Middleware', 'Migration', + 'WebSockets', // Unit 'BaseServerFactory', ] as const;