Files
client-web/src/api/crossTabRefresh.test.mjs
T
2026-08-07 14:47:00 +08:00

79 lines
2.6 KiB
JavaScript

import assert from 'node:assert/strict'
import test from 'node:test'
import { coordinateCrossTabRefresh } from './crossTabRefresh.ts'
test('reuses tokens rotated by another browser tab while waiting for the refresh lock', async () => {
let currentRefreshToken = 'refresh-old'
let refreshCalls = 0
const originalNavigator = globalThis.navigator
Object.defineProperty(globalThis, 'navigator', {
configurable: true,
value: {
locks: {
async request(_name, callback) {
currentRefreshToken = 'refresh-new'
return callback()
},
},
},
})
try {
const result = await coordinateCrossTabRefresh({
lockName: 'client-refresh',
observedRefreshToken: 'refresh-old',
currentRefreshToken: () => currentRefreshToken,
reuseCurrentSession: async () => 'access-new',
refresh: async () => {
refreshCalls += 1
return 'unexpected'
},
})
assert.equal(result, 'access-new')
assert.equal(refreshCalls, 0)
} finally {
Object.defineProperty(globalThis, 'navigator', { configurable: true, value: originalNavigator })
}
})
test('refreshes normally when this tab owns the current refresh token', async () => {
const originalNavigator = globalThis.navigator
Object.defineProperty(globalThis, 'navigator', {
configurable: true,
value: { locks: { request: async (_name, callback) => callback() } },
})
try {
const result = await coordinateCrossTabRefresh({
lockName: 'client-refresh',
observedRefreshToken: 'refresh-old',
currentRefreshToken: () => 'refresh-old',
reuseCurrentSession: async () => 'unexpected',
refresh: async (refreshToken) => `access-for-${refreshToken}`,
})
assert.equal(result, 'access-for-refresh-old')
} finally {
Object.defineProperty(globalThis, 'navigator', { configurable: true, value: originalNavigator })
}
})
test('does not wait for rotation after the shared session was removed', async () => {
const originalNavigator = globalThis.navigator
const refreshError = new Error('session removed')
Object.defineProperty(globalThis, 'navigator', { configurable: true, value: {} })
try {
await assert.rejects(coordinateCrossTabRefresh({
lockName: 'client-refresh',
observedRefreshToken: 'refresh-old',
currentRefreshToken: () => '',
reuseCurrentSession: async () => 'unexpected',
refresh: async () => { throw refreshError },
}), refreshError)
} finally {
Object.defineProperty(globalThis, 'navigator', { configurable: true, value: originalNavigator })
}
})