SEC_Warehouse/tests/unit/utils/auth.spec.ts

85 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, it, expect, beforeEach, vi } from 'vitest'
// auth.ts 顶层 import Taro,需 mock(拦截器测试本身不触达 Taro API)
vi.mock('@tarojs/taro', () => ({ default: {} }))
// store mock:authState 可变,支持模拟已登录/未登录两种状态
const authState = vi.hoisted(() => ({ token: null as string | null }))
vi.mock('@/store', () => ({
store: {
getState: () => ({ auth: { token: authState.token } })
}
}))
// storage mock:内存 Map,用于验证 store 未恢复时的兜底读取
const mem = vi.hoisted(() => new Map<string, unknown>())
vi.mock('@/utils/storage', () => ({
storage: {
get: <T>(key: string): T | null => (mem.has(key) ? (mem.get(key) as T) : null),
set: <T>(key: string, value: T): void => { mem.set(key, value) },
remove: (key: string): void => { mem.delete(key) }
}
}))
import { authRouteInterceptor } from '@/utils/auth'
import { ROUTES } from '@/constants/routes'
// 构造拦截器链:记录 proceed 收到的参数,返回受控 promise
function makeChain(url?: string) {
const received: unknown[] = []
const chain = {
requestParams: url === undefined ? {} : { url },
proceed(params: unknown) {
received.push(params)
return Promise.resolve('proceeded')
}
}
return { chain, received }
}
beforeEach(() => {
authState.token = null
mem.clear()
})
describe('authRouteInterceptor', () => {
it('未登录访问受保护页:url 被改写为登录页', async () => {
const { chain, received } = makeChain(ROUTES.HOME)
await authRouteInterceptor(chain as never)
expect(received[0]).toMatchObject({ url: ROUTES.LOGIN })
})
it('已登录访问受保护页:原样放行', async () => {
authState.token = 'tk-1'
const { chain, received } = makeChain(ROUTES.DEVICE_ADD)
await authRouteInterceptor(chain as never)
expect(received[0]).toMatchObject({ url: ROUTES.DEVICE_ADD })
})
it('未登录访问登录页:放行(登录页在公开名单)', async () => {
const { chain, received } = makeChain(ROUTES.LOGIN)
await authRouteInterceptor(chain as never)
expect(received[0]).toMatchObject({ url: ROUTES.LOGIN })
})
it('带 query 的受保护页:仅取路径判断,跳登录页不带残留参数', async () => {
const { chain, received } = makeChain(`${ROUTES.FAMILY_DETAIL}?id=3`)
await authRouteInterceptor(chain as never)
expect(received[0]).toMatchObject({ url: ROUTES.LOGIN })
})
it('store 无 token 但 storage 有(冷启动兜底):放行', async () => {
mem.set('auth_token', 'tk-saved')
const { chain, received } = makeChain(ROUTES.HOME)
await authRouteInterceptor(chain as never)
expect(received[0]).toMatchObject({ url: ROUTES.HOME })
})
it('无 url 的 API 调用(toast/login 等,拦截器全局生效):原样放行', async () => {
const { chain, received } = makeChain(undefined)
await authRouteInterceptor(chain as never)
expect(received).toHaveLength(1)
expect(received[0]).toEqual({})
})
})