import type { Server } from 'http'; import fetch from 'cross-fetch'; import WebSocket from 'ws'; import type { HttpServerFactory } from '../../src/server/HttpServerFactory'; import { instantiateFromConfig } from '../configs/Util'; const port = 6001; const serverUrl = `http://localhost:${port}/`; const headers = { forwarded: 'host=example.pod;proto=https' }; describe('A server with the Solid WebSockets API behind a proxy', (): void => { let server: Server; beforeAll(async(): Promise => { const factory = await instantiateFromConfig( 'urn:solid-server:default:ServerFactory', 'websockets.json', { 'urn:solid-server:default:variable:port': port, 'urn:solid-server:default:variable:baseUrl': 'https://example.pod/', }, ) as HttpServerFactory; server = factory.startServer(port); }); afterAll(async(): Promise => { await new Promise((resolve, reject): void => { server.close((error): void => error ? reject(error) : resolve()); }); }); it('returns a 200.', async(): Promise => { const response = await fetch(serverUrl, { headers }); expect(response.status).toBe(200); }); it('sets the Updates-Via header.', async(): Promise => { const response = await fetch(serverUrl, { headers }); expect(response.headers.get('Updates-Via')).toBe('wss://example.pod/'); }); it('exposes the Updates-Via header via CORS.', async(): Promise => { const response = await fetch(serverUrl, { headers }); expect(response.headers.get('Access-Control-Expose-Headers')!.split(',')) .toContain('Updates-Via'); }); describe('when a WebSocket client connects', (): void => { let client: WebSocket; const messages = new Array(); beforeAll(async(): Promise => { client = new WebSocket(`ws://localhost:${port}`, [ 'solid/0.1.0-alpha' ], { headers }); client.on('message', (message: string): any => messages.push(message)); await new Promise((resolve): any => client.on('open', resolve)); }); afterAll((): void => { client.close(); }); afterEach((): void => { messages.length = 0; }); it('sends the protocol version.', (): void => { expect(messages).toEqual([ 'protocol solid/0.1.0-alpha', 'warning Unstandardized protocol version, proceed with care', ]); }); describe('when the client subscribes to a resource', (): void => { beforeAll(async(): Promise => { client.send(`sub https://example.pod/my-resource`); await new Promise((resolve): any => client.once('message', resolve)); }); it('acknowledges the subscription.', async(): Promise => { expect(messages).toEqual([ `ack https://example.pod/my-resource` ]); }); it('notifies the client of resource updates.', async(): Promise => { await fetch(`${serverUrl}my-resource`, { method: 'PUT', headers: { ...headers, 'content-type': 'application/json', }, body: '{}', }); expect(messages).toEqual([ `pub https://example.pod/my-resource` ]); }); }); }); });