Skip to content

Commit

Permalink
fix: purge localStorage on page reload
Browse files Browse the repository at this point in the history
  • Loading branch information
kettanaito committed Apr 15, 2024
1 parent 25da0da commit 4920fd3
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 10 deletions.
6 changes: 6 additions & 0 deletions src/browser/setupWorker/start/createStartHandler.ts
@@ -1,4 +1,5 @@
import { devUtils } from '~/core/utils/internal/devUtils'
import { MSW_WEBSOCKET_CLIENTS_KEY } from '~/core/ws/WebSocketClientManager'
import { getWorkerInstance } from './utils/getWorkerInstance'
import { enableMocking } from './utils/enableMocking'
import { SetupWorkerInternalContext, StartHandler } from '../glossary'
Expand Down Expand Up @@ -71,6 +72,11 @@ Please consider using a custom "serviceWorker.url" option to point to the actual
// Make sure we're always clearing the interval - there are reports that not doing this can
// cause memory leaks in headless browser environments.
window.clearInterval(context.keepAliveInterval)

// Purge persisted clients on page reload.
// WebSocket clients will get new IDs on reload so persisting them
// makes little sense.
localStorage.removeItem(MSW_WEBSOCKET_CLIENTS_KEY)
})

// Check if the active Service Worker has been generated
Expand Down
3 changes: 1 addition & 2 deletions src/core/ws/WebSocketClientManager.ts
Expand Up @@ -43,9 +43,8 @@ export class WebSocketClientManager {
) {
this.inMemoryClients = new Set()

// Purge in-memory clients when the worker stops.
if (typeof localStorage !== 'undefined') {
// When the worker clears the local storage key in "worker.stop()",
// also clear the in-memory clients map.
localStorage.removeItem = new Proxy(localStorage.removeItem, {
apply: (target, thisArg, args) => {
const [key] = args
Expand Down
55 changes: 47 additions & 8 deletions test/browser/ws-api/ws.clients.browser.test.ts
Expand Up @@ -183,23 +183,62 @@ test('clears the list of clients when the worker is stopped', async ({
await worker.start()
})

expect(await page.evaluate(() => window.link.clients.size)).toBe(0)

await page.evaluate(async () => {
const ws = new WebSocket('wss://example.com')
await new Promise((done) => (ws.onopen = done))
})

// Must return 1 after a single client joined.
expect(
await page.evaluate(() => {
return window.link.clients.size
}),
).toBe(1)
// Must return the number of joined clients.
expect(await page.evaluate(() => window.link.clients.size)).toBe(1)

await page.evaluate(() => {
window.worker.stop()
})

// Must return 0.
// The localStorage has been purged, and the in-memory manager clients too.
// Must purge the local storage on reload.
// The worker has been started as a part of the test, not runtime,
// so it will start with empty clients.
expect(await page.evaluate(() => window.link.clients.size)).toBe(0)
})

test('clears the list of clients when the page is reloaded', async ({
loadExample,
page,
}) => {
await loadExample(require.resolve('./ws.runtime.js'), {
skipActivation: true,
})

const enableMocking = async () => {
await page.evaluate(async () => {
const { setupWorker, ws } = window.msw
const api = ws.link('wss://example.com')
const worker = setupWorker(api.on('connection', () => {}))
window.link = api
window.worker = worker
await worker.start()
})
}

await enableMocking(page)

expect(await page.evaluate(() => window.link.clients.size)).toBe(0)

await page.evaluate(async () => {
const ws = new WebSocket('wss://example.com')
await new Promise((done) => (ws.onopen = done))
})

// Must return the number of joined clients.
expect(await page.evaluate(() => window.link.clients.size)).toBe(1)

await page.reload()
await enableMocking()

// Must purge the local storage on reload.
// The worker has been started as a part of the test, not runtime,
// so it will start with empty clients.
expect(await page.evaluate(() => window.link.clients.size)).toBe(0)
})

0 comments on commit 4920fd3

Please sign in to comment.