84 lines
3.1 KiB
TypeScript
84 lines
3.1 KiB
TypeScript
jest.mock('../src/features/devices/device-service', () => ({
|
|
unregisterCurrentDevice: jest.fn(),
|
|
}))
|
|
jest.mock('../src/features/notifications/notification-service', () => ({
|
|
detachPushRegistrationForLogout: jest.fn(),
|
|
}))
|
|
jest.mock('../src/lib/native-config', () => ({
|
|
getMobileRuntimeConfig: () => ({ installationId: 'installation' }),
|
|
}))
|
|
jest.mock('../src/lib/logout', () => ({
|
|
signOutWithLocalFallback: jest.fn(),
|
|
}))
|
|
|
|
import {
|
|
performAccountLogout,
|
|
type AccountLogoutOperations,
|
|
} from '../src/lib/account-exit'
|
|
|
|
const USER_ID = '11111111-1111-4111-8111-111111111111'
|
|
const DEVICE_ID = '22222222-2222-4222-8222-222222222222'
|
|
|
|
describe('explicit account logout ordering', () => {
|
|
it('detaches push and unregisters the device before auth/session purge', async () => {
|
|
const order: string[] = []
|
|
const purgeLocalSession = jest.fn(async () => { order.push('purge') })
|
|
const operations: AccountLogoutOperations = {
|
|
detachPush: jest.fn(async () => { order.push('detach-push') }),
|
|
unregisterDevice: jest.fn(async () => { order.push('unregister-device') }),
|
|
installationId: () => 'installation-id',
|
|
signOut: jest.fn(async (purge) => {
|
|
order.push('sign-out')
|
|
await purge()
|
|
return { remoteRevocationConfirmed: true }
|
|
}),
|
|
}
|
|
|
|
await expect(performAccountLogout({
|
|
userId: USER_ID,
|
|
deviceId: DEVICE_ID,
|
|
purgeLocalSession,
|
|
}, operations)).resolves.toEqual({ remoteRevocationConfirmed: true })
|
|
|
|
expect(order).toEqual(['detach-push', 'unregister-device', 'sign-out', 'purge'])
|
|
expect(operations.detachPush).toHaveBeenCalledWith(USER_ID, DEVICE_ID)
|
|
expect(operations.unregisterDevice).toHaveBeenCalledWith(USER_ID, 'installation-id')
|
|
})
|
|
|
|
it('continues to local privacy cleanup when server device unregister is offline', async () => {
|
|
const purgeLocalSession = jest.fn(async () => undefined)
|
|
const operations: AccountLogoutOperations = {
|
|
detachPush: jest.fn(async () => undefined),
|
|
unregisterDevice: jest.fn(async () => { throw new Error('private network detail') }),
|
|
installationId: () => 'installation-id',
|
|
signOut: jest.fn(async (purge) => {
|
|
await purge()
|
|
return { remoteRevocationConfirmed: false }
|
|
}),
|
|
}
|
|
|
|
await expect(performAccountLogout({
|
|
userId: USER_ID,
|
|
deviceId: null,
|
|
purgeLocalSession,
|
|
}, operations)).resolves.toEqual({ remoteRevocationConfirmed: false })
|
|
expect(purgeLocalSession).toHaveBeenCalledTimes(1)
|
|
})
|
|
|
|
it('does not attempt auth logout before required push detach succeeds', async () => {
|
|
const operations: AccountLogoutOperations = {
|
|
detachPush: jest.fn(async () => { throw new Error('detach failed') }),
|
|
unregisterDevice: jest.fn(),
|
|
installationId: () => 'installation-id',
|
|
signOut: jest.fn(),
|
|
}
|
|
|
|
await expect(performAccountLogout({
|
|
userId: USER_ID,
|
|
deviceId: DEVICE_ID,
|
|
purgeLocalSession: jest.fn(),
|
|
}, operations)).rejects.toThrow('detach failed')
|
|
expect(operations.unregisterDevice).not.toHaveBeenCalled()
|
|
expect(operations.signOut).not.toHaveBeenCalled()
|
|
})
|
|
})
|