55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
const mockSignOut = jest.fn()
|
|
|
|
jest.mock('../src/lib/supabase', () => ({
|
|
supabase: {
|
|
auth: {
|
|
signOut: (...args: unknown[]) => mockSignOut(...args),
|
|
},
|
|
},
|
|
}))
|
|
|
|
import { signOutWithLocalFallback } from '../src/lib/logout'
|
|
|
|
describe('offline-safe logout boundary', () => {
|
|
beforeEach(() => jest.clearAllMocks())
|
|
|
|
test('confirms remote revocation and still performs the secure local purge', async () => {
|
|
mockSignOut.mockResolvedValue({ error: null })
|
|
const purge = jest.fn(async () => undefined)
|
|
|
|
await expect(signOutWithLocalFallback(purge)).resolves.toEqual({
|
|
remoteRevocationConfirmed: true,
|
|
})
|
|
expect(purge).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
test('logs this device out when the revocation endpoint is offline', async () => {
|
|
mockSignOut.mockResolvedValue({ error: new Error('offline') })
|
|
const purge = jest.fn(async () => undefined)
|
|
|
|
await expect(signOutWithLocalFallback(purge)).resolves.toEqual({
|
|
remoteRevocationConfirmed: false,
|
|
})
|
|
expect(purge).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
test('also purges locally when the auth client throws a transport error', async () => {
|
|
mockSignOut.mockRejectedValue(new Error('network down'))
|
|
const purge = jest.fn(async () => undefined)
|
|
|
|
await expect(signOutWithLocalFallback(purge)).resolves.toEqual({
|
|
remoteRevocationConfirmed: false,
|
|
})
|
|
expect(purge).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
test('never reports logout success if secure local deletion fails', async () => {
|
|
mockSignOut.mockResolvedValue({ error: new Error('offline') })
|
|
const purge = jest.fn(async () => {
|
|
throw new Error('keychain deletion failed')
|
|
})
|
|
|
|
await expect(signOutWithLocalFallback(purge))
|
|
.rejects.toThrow('keychain deletion failed')
|
|
})
|
|
})
|