From 2073579ecfe4e8a1d5d37aa7f0a43b53bb57cd02 Mon Sep 17 00:00:00 2001 From: MartinCupela <32706194+MartinCupela@users.noreply.github.com> Date: Tue, 3 Oct 2023 16:09:43 +0200 Subject: [PATCH] fix: queue channel WS events until the channel is initialized (#1179) --- src/channel.ts | 25 +++++++++++++ src/events.ts | 25 +++++++++++++ test/unit/channel.js | 74 ++++++++++++++++++++++++++++++++++++-- test/unit/channel_state.js | 1 + 4 files changed, 123 insertions(+), 2 deletions(-) diff --git a/src/channel.ts b/src/channel.ts index 75d4de99c..7ea62de55 100644 --- a/src/channel.ts +++ b/src/channel.ts @@ -89,6 +89,12 @@ export class Channel[]; /** * constructor - Create a channel @@ -132,6 +138,7 @@ export class Channel) { const channel = this; + + if (!this._isInitialized()) { + this.wsEventQueue.push(event); + return; + } + this._client.logger( 'info', `channel:_handleChannelEvent - Received event of type { ${event.type} } on ${this.cid}`, @@ -1442,6 +1456,10 @@ export class Channel { + eventTypes.forEach((type) => { + channel._handleChannelEvent({ type }); + }); + }; + + it('buffers WS events when uninitialized', () => { + channel.initialized = false; + channel.offlineMode = false; + + receiveAllChannelEvents(channel); + + expect(channel.wsEventQueue).to.have.length(eventTypes.length); + }); + + it('does not buffer WS events when in offline mode', () => { + channel.initialized = false; + channel.offlineMode = true; + + receiveAllChannelEvents(channel); + + expect(channel.wsEventQueue).to.be.empty; + }); + + it('does not buffer WS events with server-side client', () => { + client = new StreamChat('apiKey', 'secret'); + client.user = user; + client.userID = user.id; + channel = client.channel('messaging', 'id'); + channel.initialized = false; + channel.offlineMode = false; + + receiveAllChannelEvents(channel); + + expect(channel.wsEventQueue).to.be.empty; + }); + + it('does not buffer WS events on initialized channel', () => { + channel.initialized = true; + + receiveAllChannelEvents(channel); + + expect(channel.wsEventQueue).to.be.empty; + }); + + it('buffers WS events and channel.watch() flushes upon channel initialization', async () => { + channel.initialized = false; + sinon.stub(client, 'doAxiosRequest').resolves({ channel: generateChannel(), members: [] }); + + receiveAllChannelEvents(channel); + + expect(channel.wsEventQueue).to.have.length(eventTypes.length); + await channel.watch(); + expect(channel.wsEventQueue).to.be.empty; + client.doAxiosRequest.restore(); + }); + + it('buffers WS events and channel.query() does not flush the queue', async () => { + channel.initialized = false; + sinon.stub(client, 'doAxiosRequest').resolves({ channel: generateChannel(), members: [] }); + + receiveAllChannelEvents(channel); + + expect(channel.wsEventQueue).to.have.length(eventTypes.length); + await channel.query(); + expect(channel.wsEventQueue).to.have.length(eventTypes.length); + client.doAxiosRequest.restore(); + }); }); describe('Channels - Constructor', function () { diff --git a/test/unit/channel_state.js b/test/unit/channel_state.js index 5e7dc7b2b..171471abf 100644 --- a/test/unit/channel_state.js +++ b/test/unit/channel_state.js @@ -645,6 +645,7 @@ describe('ChannelState clean', () => { client.userID = 'observer'; channel = new Channel(client, 'live', 'stream', {}); client.activeChannels[channel.cid] = channel; + channel.initialized = true; }); it('should remove any stale typing events with either string or Date received_at', async () => {