70 行
3.1 KiB
TypeScript
70 行
3.1 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
const api = vi.hoisted (() => ({ apiGet: vi.fn (), apiPost: vi.fn () }))
|
|
|
|
vi.mock ('@/lib/api', () => ({ ...api,
|
|
isApiError: (error: { isAxiosError?: boolean }) => error.isAxiosError === true }))
|
|
|
|
const user = { id: 1, name: 'Cookie user', role: 'guest', inheritanceCode: 'current-code' }
|
|
const noSession = { isAxiosError: true, response: { status: 401 } }
|
|
|
|
|
|
describe ('Cookie session initialisation', () => {
|
|
beforeEach (() => {
|
|
vi.resetModules ()
|
|
vi.clearAllMocks ()
|
|
api.apiGet.mockReset ()
|
|
api.apiPost.mockReset ()
|
|
localStorage.clear ()
|
|
})
|
|
|
|
it ('keeps Cookie identity and updates an older recovery code', async () => {
|
|
localStorage.setItem ('user_code', 'old-code')
|
|
api.apiGet.mockResolvedValueOnce (user)
|
|
const { initialiseUserSession } = await import ('@/lib/users')
|
|
await expect (initialiseUserSession ()).resolves.toEqual (user)
|
|
expect (api.apiGet).toHaveBeenCalledWith ('/users/me')
|
|
expect (api.apiPost).not.toHaveBeenCalled ()
|
|
expect (localStorage.getItem ('user_code')).toBe ('current-code')
|
|
})
|
|
|
|
it ('restores from storage only after Cookie authentication returns 401', async () => {
|
|
localStorage.setItem ('user_code', 'backup-code')
|
|
api.apiGet.mockRejectedValueOnce (noSession)
|
|
api.apiPost.mockResolvedValueOnce ({ valid: true, user })
|
|
const { initialiseUserSession } = await import ('@/lib/users')
|
|
await expect (initialiseUserSession ()).resolves.toEqual (user)
|
|
expect (api.apiPost).toHaveBeenCalledExactlyOnceWith (
|
|
'/users/verify', { code: 'backup-code', restore: true })
|
|
})
|
|
|
|
it ('creates an account after a recovery code is rejected', async () => {
|
|
localStorage.setItem ('user_code', 'expired-code')
|
|
api.apiGet.mockRejectedValueOnce (noSession)
|
|
api.apiPost.mockResolvedValueOnce ({ valid: false })
|
|
api.apiPost.mockResolvedValueOnce ({ code: user.inheritanceCode, user })
|
|
const { initialiseUserSession } = await import ('@/lib/users')
|
|
await expect (initialiseUserSession ()).resolves.toEqual (user)
|
|
expect (api.apiPost).toHaveBeenLastCalledWith ('/users')
|
|
})
|
|
|
|
it.each ([403, 503]) ('does not replace a session when the API returns %s', async status => {
|
|
localStorage.setItem ('user_code', 'backup-code')
|
|
const error = { isAxiosError: true, response: { status } }
|
|
api.apiGet.mockRejectedValueOnce (error)
|
|
const { initialiseUserSession } = await import ('@/lib/users')
|
|
await expect (initialiseUserSession ()).rejects.toBe (error)
|
|
expect (api.apiPost).not.toHaveBeenCalled ()
|
|
expect (localStorage.getItem ('user_code')).toBe ('backup-code')
|
|
})
|
|
|
|
it ('shares concurrent initialisation to avoid duplicate account creation', async () => {
|
|
api.apiGet.mockRejectedValueOnce (noSession)
|
|
api.apiPost.mockResolvedValueOnce ({ code: user.inheritanceCode, user })
|
|
const { initialiseUserSession } = await import ('@/lib/users')
|
|
await Promise.all ([initialiseUserSession (), initialiseUserSession ()])
|
|
expect (api.apiGet).toHaveBeenCalledTimes (1)
|
|
expect (api.apiPost).toHaveBeenCalledExactlyOnceWith ('/users')
|
|
})
|
|
})
|