From 27754b213fe4be3f7a918a0881700cf91825048e Mon Sep 17 00:00:00 2001 From: enisdenjo Date: Wed, 20 Oct 2021 16:34:21 +0200 Subject: [PATCH] fix(client): Report close error even if `Complete` message followed Closes #245 --- src/__tests__/client.ts | 61 ++++++++++++++++++++++++++++++++++++++++- src/client.ts | 1 + 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/__tests__/client.ts b/src/__tests__/client.ts index dc3b4592..40ce10e3 100644 --- a/src/__tests__/client.ts +++ b/src/__tests__/client.ts @@ -12,7 +12,7 @@ import { stringifyMessage, SubscribePayload, } from '../common'; -import { startWSTServer as startTServer } from './utils'; +import { startRawServer, startWSTServer as startTServer } from './utils'; import { ExecutionResult } from 'graphql'; // silence console.error calls for nicer tests overview @@ -480,6 +480,65 @@ it('should close socket with error on malformed request', async (done) => { ); }); +it('should report close error even if complete message followed', async (done) => { + expect.assertions(4); + + const { url, server } = await startRawServer(); + + server.on('connection', (socket) => { + socket.on('message', (data) => { + const msg = parseMessage(String(data)); + + // acknowledge conneciton + if (msg.type === MessageType.ConnectionInit) + socket.send(stringifyMessage({ type: MessageType.ConnectionAck })); + + // respond with a malformed error message and a complete + if (msg.type === MessageType.Subscribe) { + socket.send( + JSON.stringify({ + id: msg.id, + type: MessageType.Error, + payload: 'malformed', + }), + ); + socket.send( + stringifyMessage({ id: msg.id, type: MessageType.Complete }), + ); + } + }); + }); + + const client = createClient({ + url, + lazy: false, + retryAttempts: 0, + onNonLazyError: noop, + on: { + closed: (err) => { + expect((err as CloseEvent).code).toBe(CloseCode.BadRequest); + expect((err as CloseEvent).reason).toBe('Invalid message'); + }, + }, + }); + + client.subscribe( + { + query: 'notaquery', + }, + { + next: noop, + error: (err) => { + expect((err as CloseEvent).code).toBe(CloseCode.BadRequest); + expect((err as CloseEvent).reason).toBe('Invalid message'); + client.dispose(); + done(); + }, + complete: noop, + }, + ); +}); + describe('ping/pong', () => { it('should respond with a pong to a ping', async () => { expect.assertions(1); diff --git a/src/client.ts b/src/client.ts index fc215a62..c8cc7c53 100644 --- a/src/client.ts +++ b/src/client.ts @@ -693,6 +693,7 @@ export function createClient(options: ClientOptions): Client { ), ]); } catch (err) { + socket.onmessage = null; // stop reading messages as soon as reading breaks once socket.close( CloseCode.BadRequest, err instanceof Error ? err.message : new Error(err).message,