- 新增 company 请求上下文工具、organization store 与公司切换器 - axios 拦截器为组织级请求写入 X-Organization-ID 并校验上下文版本 - 切换公司用 AbortController 取消旧读请求,丢弃旧响应且不弹提示 - 路由与页面加公司初始化屏障,组织级页面按公司 ID + 版本挂载
242 lines
8.8 KiB
JavaScript
242 lines
8.8 KiB
JavaScript
import { createPinia, setActivePinia } from 'pinia'
|
|
import { beforeEach, describe, expect, test, vi } from 'vitest'
|
|
import { authApi } from '../api/auth'
|
|
import { useOrganizationStore } from './organization'
|
|
import { resetOrganizationContext } from '../utils/organizationContext'
|
|
|
|
vi.mock('../api/auth', () => ({
|
|
authApi: {
|
|
listOrganizations: vi.fn(),
|
|
switchOrganizationContext: vi.fn()
|
|
}
|
|
}))
|
|
|
|
// 模拟某个账号已登录:公司选择按用户 id 分开存储,这里写入对应账号。
|
|
function loginAs(id) {
|
|
localStorage.setItem('wmms_user', JSON.stringify({ id, username: `user${id}` }))
|
|
}
|
|
|
|
function orgList(organizations, defaultOrganizationId) {
|
|
return { data: { organizations, default_organization_id: defaultOrganizationId } }
|
|
}
|
|
|
|
function switchResult(organizationId, warehouse = null) {
|
|
return { data: { organization_id: organizationId, organization: { id: organizationId }, warehouse } }
|
|
}
|
|
|
|
const ACTIVE_WAREHOUSE = {
|
|
id: 10,
|
|
name: '武汉仓',
|
|
status: 'active',
|
|
location: { id: 100, name: 'A库位', status: 'active' }
|
|
}
|
|
|
|
describe('organization store', () => {
|
|
beforeEach(() => {
|
|
localStorage.clear()
|
|
sessionStorage.clear()
|
|
resetOrganizationContext()
|
|
setActivePinia(createPinia())
|
|
authApi.listOrganizations.mockReset()
|
|
authApi.switchOrganizationContext.mockReset()
|
|
})
|
|
|
|
test('默认公司进入并自动选中唯一启用的仓库与库位', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1, name: '北京' }, { id: 2, name: '武汉' }], 2))
|
|
authApi.switchOrganizationContext.mockResolvedValue(switchResult(2, ACTIVE_WAREHOUSE))
|
|
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
|
|
expect(store.organizations.map(o => o.id)).toEqual([1, 2])
|
|
expect(store.currentOrganizationId).toBe(2)
|
|
expect(store.currentWarehouseId).toBe(10)
|
|
expect(store.currentLocationId).toBe(100)
|
|
expect(store.initialized).toBe(true)
|
|
expect(authApi.switchOrganizationContext).toHaveBeenCalledWith(2, 0)
|
|
})
|
|
|
|
test('只展示接口返回的授权公司', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 3, name: '上海' }], 3))
|
|
authApi.switchOrganizationContext.mockResolvedValue(switchResult(3))
|
|
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
|
|
expect(store.organizations.map(o => o.id)).toEqual([3])
|
|
expect(store.currentOrganizationId).toBe(3)
|
|
})
|
|
|
|
test('默认公司失效时保留列表并要求重新选择', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1, name: '北京' }], 99))
|
|
authApi.switchOrganizationContext.mockRejectedValue(new Error('公司不可访问'))
|
|
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
|
|
expect(store.organizations.map(o => o.id)).toEqual([1])
|
|
expect(store.currentOrganizationId).toBeNull()
|
|
expect(store.initialized).toBe(true)
|
|
})
|
|
|
|
test('没有授权公司时进入空状态且不发起校验', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([], null))
|
|
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
|
|
expect(store.organizations).toEqual([])
|
|
expect(store.currentOrganizationId).toBeNull()
|
|
expect(store.currentWarehouseId).toBeNull()
|
|
expect(store.currentLocationId).toBeNull()
|
|
expect(authApi.switchOrganizationContext).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('切换失败时保留旧公司', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1 }, { id: 2 }], 1))
|
|
authApi.switchOrganizationContext.mockResolvedValueOnce(
|
|
switchResult(1, { id: 9, name: '北京仓', status: 'active', location: { id: 90, name: '库位', status: 'active' } })
|
|
)
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
expect(store.currentOrganizationId).toBe(1)
|
|
|
|
authApi.switchOrganizationContext.mockRejectedValueOnce(new Error('公司不可访问'))
|
|
await expect(store.switchOrganization(2)).rejects.toThrow()
|
|
|
|
expect(store.currentOrganizationId).toBe(1)
|
|
expect(store.currentWarehouseId).toBe(9)
|
|
expect(store.currentLocationId).toBe(90)
|
|
expect(store.switching).toBe(false)
|
|
})
|
|
|
|
test('切换成功后提交新公司并递增上下文版本', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1 }, { id: 2 }], 1))
|
|
authApi.switchOrganizationContext.mockResolvedValueOnce(switchResult(1))
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
const versionBefore = store.contextVersion
|
|
|
|
authApi.switchOrganizationContext.mockResolvedValueOnce(switchResult(2, ACTIVE_WAREHOUSE))
|
|
await store.switchOrganization(2)
|
|
|
|
expect(store.currentOrganizationId).toBe(2)
|
|
expect(store.contextVersion).toBeGreaterThan(versionBefore)
|
|
expect(store.currentWarehouseId).toBe(10)
|
|
expect(store.currentLocationId).toBe(100)
|
|
expect(authApi.switchOrganizationContext).toHaveBeenLastCalledWith(2, 1)
|
|
})
|
|
|
|
test('切换到当前公司不重复发起校验', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1 }], 1))
|
|
authApi.switchOrganizationContext.mockResolvedValueOnce(switchResult(1))
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
authApi.switchOrganizationContext.mockClear()
|
|
|
|
await store.switchOrganization(1)
|
|
|
|
expect(authApi.switchOrganizationContext).not.toHaveBeenCalled()
|
|
})
|
|
|
|
test('仓库停用时仓库与库位都为空', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1 }], 1))
|
|
authApi.switchOrganizationContext.mockResolvedValue(switchResult(1, {
|
|
id: 5, name: '停用仓', status: 'inactive', location: { id: 50, name: '库位', status: 'active' }
|
|
}))
|
|
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
|
|
expect(store.currentWarehouseId).toBeNull()
|
|
expect(store.currentLocationId).toBeNull()
|
|
})
|
|
|
|
test('库位缺失或停用时仅库位为空', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1 }], 1))
|
|
authApi.switchOrganizationContext.mockResolvedValue(switchResult(1, {
|
|
id: 5, name: '启用仓', status: 'active', location: null
|
|
}))
|
|
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
|
|
expect(store.currentWarehouseId).toBe(5)
|
|
expect(store.currentLocationId).toBeNull()
|
|
})
|
|
|
|
test('目标公司没有仓库时清空旧公司的仓库与库位', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1 }, { id: 2 }], 1))
|
|
authApi.switchOrganizationContext.mockResolvedValueOnce(switchResult(1, ACTIVE_WAREHOUSE))
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
expect(store.currentWarehouseId).toBe(10)
|
|
|
|
authApi.switchOrganizationContext.mockResolvedValueOnce(switchResult(2, null))
|
|
await store.switchOrganization(2)
|
|
|
|
expect(store.currentOrganizationId).toBe(2)
|
|
expect(store.currentWarehouseId).toBeNull()
|
|
expect(store.currentLocationId).toBeNull()
|
|
})
|
|
|
|
test('不同账号不继承上一账号的公司选择', async () => {
|
|
// 账号 1 上次在本标签页选择了公司 2
|
|
loginAs(1)
|
|
sessionStorage.setItem('wmms_organization_id:1', '2')
|
|
|
|
// 换成账号 2 登录:读到的应是账号 2 的存储(为空),回落到默认公司 1
|
|
loginAs(2)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1 }, { id: 2 }], 1))
|
|
authApi.switchOrganizationContext.mockResolvedValue(switchResult(1))
|
|
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
|
|
expect(store.currentOrganizationId).toBe(1)
|
|
expect(authApi.switchOrganizationContext).toHaveBeenCalledWith(1, 0)
|
|
})
|
|
|
|
test('切换进行中禁止再次切换', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1 }], 1))
|
|
authApi.switchOrganizationContext.mockResolvedValueOnce(switchResult(1))
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
authApi.switchOrganizationContext.mockClear()
|
|
|
|
store.switching = true
|
|
await store.switchOrganization(2)
|
|
|
|
expect(authApi.switchOrganizationContext).not.toHaveBeenCalled()
|
|
expect(store.currentOrganizationId).toBe(1)
|
|
})
|
|
|
|
test('reset 清空公司状态与上下文', async () => {
|
|
loginAs(1)
|
|
authApi.listOrganizations.mockResolvedValue(orgList([{ id: 1 }], 1))
|
|
authApi.switchOrganizationContext.mockResolvedValue(switchResult(1, ACTIVE_WAREHOUSE))
|
|
const store = useOrganizationStore()
|
|
await store.initialize()
|
|
expect(store.currentOrganizationId).toBe(1)
|
|
|
|
store.reset()
|
|
|
|
expect(store.organizations).toEqual([])
|
|
expect(store.currentOrganizationId).toBeNull()
|
|
expect(store.currentWarehouseId).toBeNull()
|
|
expect(store.currentLocationId).toBeNull()
|
|
expect(store.initialized).toBe(false)
|
|
})
|
|
})
|