Skip to content

Commit ee4ca2e

Browse files
committed
fix(WebSocketClientManager): clear inMemoryClients on localStorage removal
1 parent 78c46a0 commit ee4ca2e

File tree

3 files changed

+63
-2
lines changed

3 files changed

+63
-2
lines changed

src/browser/setupWorker/stop/createStop.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { devUtils } from '~/core/utils/internal/devUtils'
2+
import { MSW_WEBSOCKET_CLIENTS_KEY } from '~/core/ws/WebSocketClientManager'
23
import { SetupWorkerInternalContext, StopHandler } from '../glossary'
34
import { printStopMessage } from './utils/printStopMessage'
45

@@ -24,6 +25,9 @@ export const createStop = (
2425
context.isMockingEnabled = false
2526
window.clearInterval(context.keepAliveInterval)
2627

28+
// Clear the WebSocket clients from the shared storage.
29+
localStorage.removeItem(MSW_WEBSOCKET_CLIENTS_KEY)
30+
2731
printStopMessage({ quiet: context.startOptions?.quiet })
2832
}
2933
}

src/core/ws/WebSocketClientManager.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import type {
66
} from '@mswjs/interceptors/WebSocket'
77
import { matchRequestUrl, type Path } from '../utils/matching/matchRequestUrl'
88

9-
const MSW_WEBSOCKET_CLIENTS_KEY = 'msw:ws:clients'
9+
export const MSW_WEBSOCKET_CLIENTS_KEY = 'msw:ws:clients'
1010

1111
export type WebSocketBroadcastChannelMessage =
1212
| {
@@ -42,6 +42,22 @@ export class WebSocketClientManager {
4242
private url: Path,
4343
) {
4444
this.inMemoryClients = new Set()
45+
46+
if (typeof localStorage !== 'undefined') {
47+
// When the worker clears the local storage key in "worker.stop()",
48+
// also clear the in-memory clients map.
49+
localStorage.removeItem = new Proxy(localStorage.removeItem, {
50+
apply: (target, thisArg, args) => {
51+
const [key] = args
52+
53+
if (key === MSW_WEBSOCKET_CLIENTS_KEY) {
54+
this.inMemoryClients.clear()
55+
}
56+
57+
return Reflect.apply(target, thisArg, args)
58+
},
59+
})
60+
}
4561
}
4662

4763
/**
@@ -53,6 +69,8 @@ export class WebSocketClientManager {
5369
if (typeof localStorage !== 'undefined') {
5470
const inMemoryClients = Array.from(this.inMemoryClients)
5571

72+
console.log('get clients()', inMemoryClients, this.getSerializedClients())
73+
5674
return new Set(
5775
inMemoryClients.concat(
5876
this.getSerializedClients()

test/browser/ws-api/ws.clients.browser.test.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { WebSocketLink, ws } from 'msw'
2-
import type { setupWorker } from 'msw/browser'
2+
import type { SetupWorker, setupWorker } from 'msw/browser'
33
import { test, expect } from '../playwright.extend'
44

55
declare global {
@@ -8,6 +8,7 @@ declare global {
88
ws: typeof ws
99
setupWorker: typeof setupWorker
1010
}
11+
worker: SetupWorker
1112
link: WebSocketLink
1213
ws: WebSocket
1314
messages: string[]
@@ -164,3 +165,41 @@ test('broadcasts messages across runtimes', async ({
164165
'hi from two',
165166
])
166167
})
168+
169+
test('clears the list of clients when the worker is stopped', async ({
170+
loadExample,
171+
page,
172+
}) => {
173+
await loadExample(require.resolve('./ws.runtime.js'), {
174+
skipActivation: true,
175+
})
176+
177+
await page.evaluate(async () => {
178+
const { setupWorker, ws } = window.msw
179+
const api = ws.link('wss://example.com')
180+
const worker = setupWorker(api.on('connection', () => {}))
181+
window.link = api
182+
window.worker = worker
183+
await worker.start()
184+
})
185+
186+
await page.evaluate(async () => {
187+
const ws = new WebSocket('wss://example.com')
188+
await new Promise((done) => (ws.onopen = done))
189+
})
190+
191+
// Must return 1 after a single client joined.
192+
expect(
193+
await page.evaluate(() => {
194+
return window.link.clients.size
195+
}),
196+
).toBe(1)
197+
198+
await page.evaluate(() => {
199+
window.worker.stop()
200+
})
201+
202+
// Must return 0.
203+
// The localStorage has been purged, and the in-memory manager clients too.
204+
expect(await page.evaluate(() => window.link.clients.size)).toBe(0)
205+
})

0 commit comments

Comments
 (0)