85 lines
3.0 KiB
TypeScript
85 lines
3.0 KiB
TypeScript
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({})
|
||
})
|
||
})
|