feat(store): authSlice 扩展 userInfo 并持久化 token
This commit is contained in:
parent
884a7b8343
commit
c65d179333
|
|
@ -1,30 +1,39 @@
|
||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||||
import { storage } from '@/utils/storage'
|
import { storage } from '@/utils/storage'
|
||||||
|
// import type 避免运行时循环依赖:store → api/auth → http/client → store
|
||||||
|
import type { WxUserInfo } from '@/api/auth'
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
token: string | null
|
token: string | null
|
||||||
userId: string | null
|
userId: string | null
|
||||||
|
userInfo: WxUserInfo | null // 登录返回的完整用户信息(spec D6)
|
||||||
}
|
}
|
||||||
|
|
||||||
const STORAGE_KEY = 'auth_token'
|
const STORAGE_KEY = 'auth_token'
|
||||||
|
|
||||||
const initialState: State = {
|
// initialState 用惰性函数:保证 reducer(undefined) 时才读取 storage,
|
||||||
|
// 使测试里 beforeEach 清空 mock 后再初始化能拿到正确的干净状态
|
||||||
|
const initialState = (): State => ({
|
||||||
token: storage.get<string>(STORAGE_KEY),
|
token: storage.get<string>(STORAGE_KEY),
|
||||||
userId: null
|
userId: null,
|
||||||
}
|
userInfo: null
|
||||||
|
})
|
||||||
|
|
||||||
const slice = createSlice({
|
const slice = createSlice({
|
||||||
name: 'auth',
|
name: 'auth',
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
setAuth(state, action: PayloadAction<{ token: string; userId: string }>) {
|
// token 落盘持久化;userInfo 只入内存,冷启动由后续接口拉取,避免缓存过期数据(spec D6)
|
||||||
|
setAuth(state, action: PayloadAction<{ token: string; userInfo: WxUserInfo }>) {
|
||||||
state.token = action.payload.token
|
state.token = action.payload.token
|
||||||
state.userId = action.payload.userId
|
state.userId = action.payload.userInfo.userId
|
||||||
|
state.userInfo = action.payload.userInfo
|
||||||
storage.set(STORAGE_KEY, action.payload.token)
|
storage.set(STORAGE_KEY, action.payload.token)
|
||||||
},
|
},
|
||||||
clearAuth(state) {
|
clearAuth(state) {
|
||||||
state.token = null
|
state.token = null
|
||||||
state.userId = null
|
state.userId = null
|
||||||
|
state.userInfo = null
|
||||||
storage.remove(STORAGE_KEY)
|
storage.remove(STORAGE_KEY)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
||||||
|
|
||||||
|
// 内存 Map 模拟 Taro storage(同 tests/unit/family/family.spec.ts 模式)
|
||||||
|
const mem = 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 reducer, { setAuth, clearAuth } from '@/store/authSlice'
|
||||||
|
import type { WxUserInfo } from '@/api/auth'
|
||||||
|
|
||||||
|
const userInfo: WxUserInfo = {
|
||||||
|
userId: 'u-100',
|
||||||
|
userType: 1,
|
||||||
|
avatar: 'https://example.com/a.png',
|
||||||
|
nickName: '张大爷',
|
||||||
|
mobile: '13800000000',
|
||||||
|
gender: 1,
|
||||||
|
region: '深圳市南山区',
|
||||||
|
loginFrom: 'miniapp'
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
mem.clear()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('authSlice', () => {
|
||||||
|
it('setAuth 写入 token/userId/userInfo,token 落盘', () => {
|
||||||
|
let state = reducer(undefined, { type: 'init' })
|
||||||
|
state = reducer(state, setAuth({ token: 'tk-1', userInfo }))
|
||||||
|
expect(state.token).toBe('tk-1')
|
||||||
|
expect(state.userId).toBe('u-100')
|
||||||
|
expect(state.userInfo).toEqual(userInfo)
|
||||||
|
expect(mem.get('auth_token')).toBe('tk-1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('setAuth 后 clearAuth 全部清空并移除持久化 token', () => {
|
||||||
|
let state = reducer(undefined, { type: 'init' })
|
||||||
|
state = reducer(state, setAuth({ token: 'tk-1', userInfo }))
|
||||||
|
state = reducer(state, clearAuth())
|
||||||
|
expect(state.token).toBeNull()
|
||||||
|
expect(state.userId).toBeNull()
|
||||||
|
expect(state.userInfo).toBeNull()
|
||||||
|
expect(mem.has('auth_token')).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('初始态从 storage 恢复 token', () => {
|
||||||
|
mem.set('auth_token', 'tk-saved')
|
||||||
|
const state = reducer(undefined, { type: 'init' })
|
||||||
|
expect(state.token).toBe('tk-saved')
|
||||||
|
expect(state.userInfo).toBeNull()
|
||||||
|
})
|
||||||
|
})
|
||||||
Loading…
Reference in New Issue