- 修复路由守卫:未登录时直接跳转,不显示提示信息 - 修复API拦截器:401错误直接跳转,无需确认 - 移除不必要的ElMessageBox确认框 - 优化Token过期处理逻辑 - 修复文件管理API引入路径和URL前缀 - 修复调拨/回收管理API端点不匹配问题 - 修复通知管理API方法不匹配问题 - 统一系统配置API路径为单数形式 影响文件: - src/router/index.ts - src/api/request.ts - src/api/file.ts - src/api/index.ts 测试状态: - 前端构建通过 - 所有API路径已验证 - 登录流程测试通过 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
304 lines
8.1 KiB
TypeScript
304 lines
8.1 KiB
TypeScript
/**
|
|
* useAsset Composable测试
|
|
*
|
|
* 测试内容:
|
|
* - 资产列表获取
|
|
* - 资产详情获取
|
|
* - 资产创建
|
|
* - 资产更新
|
|
* - 资产删除
|
|
* - 错误处理
|
|
*/
|
|
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { useAsset } from '@/composables/useAsset'
|
|
import * as assetApi from '@/api/assets'
|
|
|
|
// Mock API模块
|
|
vi.mock('@/api/assets', () => ({
|
|
getAssetList: vi.fn(),
|
|
getAssetById: vi.fn(),
|
|
createAsset: vi.fn(),
|
|
updateAsset: vi.fn(),
|
|
deleteAsset: vi.fn(),
|
|
importAssets: vi.fn()
|
|
}))
|
|
|
|
describe('useAsset Composable', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
describe('fetchAssets', () => {
|
|
it('应该成功获取资产列表', async () => {
|
|
const mockData = {
|
|
items: [
|
|
{
|
|
id: 1,
|
|
assetCode: 'ASSET-20250124-0001',
|
|
assetName: '联想台式机',
|
|
status: 'in_use'
|
|
}
|
|
],
|
|
total: 1,
|
|
page: 1,
|
|
pageSize: 20
|
|
}
|
|
|
|
vi.mocked(assetApi.getAssetList).mockResolvedValue(mockData)
|
|
|
|
const { fetchAssets, assets, loading } = useAsset()
|
|
await fetchAssets({ page: 1, page_size: 20 })
|
|
|
|
expect(loading.value).toBe(false)
|
|
expect(assets.value).toEqual(mockData.items)
|
|
expect(assetApi.getAssetList).toHaveBeenCalledWith({ page: 1, page_size: 20 })
|
|
})
|
|
|
|
it('应该处理获取资产列表失败', async () => {
|
|
vi.mocked(assetApi.getAssetList).mockRejectedValue(new Error('网络错误'))
|
|
|
|
const { fetchAssets, loading } = useAsset()
|
|
|
|
await expect(fetchAssets({ page: 1 })).rejects.toThrow('网络错误')
|
|
expect(loading.value).toBe(false)
|
|
})
|
|
|
|
it('应该支持搜索参数', async () => {
|
|
vi.mocked(assetApi.getAssetList).mockResolvedValue({ items: [], total: 0 })
|
|
|
|
const { fetchAssets } = useAsset()
|
|
await fetchAssets({
|
|
page: 1,
|
|
page_size: 20,
|
|
keyword: '联想',
|
|
status: 'in_use'
|
|
})
|
|
|
|
expect(assetApi.getAssetList).toHaveBeenCalledWith({
|
|
page: 1,
|
|
page_size: 20,
|
|
keyword: '联想',
|
|
status: 'in_use'
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('fetchAssetById', () => {
|
|
it('应该成功获取资产详情', async () => {
|
|
const mockAsset = {
|
|
id: 1,
|
|
assetCode: 'ASSET-20250124-0001',
|
|
assetName: '联想台式机',
|
|
status: 'in_use'
|
|
}
|
|
|
|
vi.mocked(assetApi.getAssetById).mockResolvedValue(mockAsset)
|
|
|
|
const { fetchAssetById, loading } = useAsset()
|
|
const result = await fetchAssetById(1)
|
|
|
|
expect(loading.value).toBe(false)
|
|
expect(result).toEqual(mockAsset)
|
|
expect(assetApi.getAssetById).toHaveBeenCalledWith(1)
|
|
})
|
|
|
|
it('应该处理资产不存在的情况', async () => {
|
|
vi.mocked(assetApi.getAssetById).mockRejectedValue(new Error('资产不存在'))
|
|
|
|
const { fetchAssetById } = useAsset()
|
|
|
|
await expect(fetchAssetById(999)).rejects.toThrow('资产不存在')
|
|
})
|
|
})
|
|
|
|
describe('createAsset', () => {
|
|
it('应该成功创建资产', async () => {
|
|
const newAsset = {
|
|
assetName: '新资产',
|
|
deviceTypeId: 1,
|
|
organizationId: 1
|
|
}
|
|
|
|
const createdAsset = {
|
|
id: 1,
|
|
assetCode: 'ASSET-20250124-0001',
|
|
...newAsset
|
|
}
|
|
|
|
vi.mocked(assetApi.createAsset).mockResolvedValue(createdAsset)
|
|
|
|
const { createAsset: create, loading } = useAsset()
|
|
const result = await create(newAsset)
|
|
|
|
expect(loading.value).toBe(false)
|
|
expect(result).toEqual(createdAsset)
|
|
expect(assetApi.createAsset).toHaveBeenCalledWith(newAsset)
|
|
})
|
|
|
|
it('应该处理创建失败', async () => {
|
|
const newAsset = {
|
|
assetName: '新资产',
|
|
deviceTypeId: 1,
|
|
organizationId: 1
|
|
}
|
|
|
|
vi.mocked(assetApi.createAsset).mockRejectedValue(new Error('创建失败'))
|
|
|
|
const { createAsset: create } = useAsset()
|
|
|
|
await expect(create(newAsset)).rejects.toThrow('创建失败')
|
|
})
|
|
|
|
it('应该验证必填字段', async () => {
|
|
const invalidAsset = {
|
|
assetName: '', // 空名称
|
|
deviceTypeId: 0, // 无效ID
|
|
organizationId: 1
|
|
}
|
|
|
|
const { createAsset: create } = useAsset()
|
|
|
|
await expect(create(invalidAsset)).rejects.toThrow()
|
|
})
|
|
})
|
|
|
|
describe('updateAsset', () => {
|
|
it('应该成功更新资产', async () => {
|
|
const updateData = {
|
|
assetName: '更新后的名称',
|
|
location: '新位置'
|
|
}
|
|
|
|
const updatedAsset = {
|
|
id: 1,
|
|
assetCode: 'ASSET-20250124-0001',
|
|
...updateData
|
|
}
|
|
|
|
vi.mocked(assetApi.updateAsset).mockResolvedValue(updatedAsset)
|
|
|
|
const { updateAsset: update, loading } = useAsset()
|
|
const result = await update(1, updateData)
|
|
|
|
expect(loading.value).toBe(false)
|
|
expect(result).toEqual(updatedAsset)
|
|
expect(assetApi.updateAsset).toHaveBeenCalledWith(1, updateData)
|
|
})
|
|
|
|
it('应该处理更新不存在的资产', async () => {
|
|
vi.mocked(assetApi.updateAsset).mockRejectedValue(new Error('资产不存在'))
|
|
|
|
const { updateAsset: update } = useAsset()
|
|
|
|
await expect(update(999, { assetName: '新名称' })).rejects.toThrow('资产不存在')
|
|
})
|
|
})
|
|
|
|
describe('deleteAsset', () => {
|
|
it('应该成功删除资产', async () => {
|
|
vi.mocked(assetApi.deleteAsset).mockResolvedValue({})
|
|
|
|
const { deleteAsset: deleteFn, loading } = useAsset()
|
|
await deleteFn(1)
|
|
|
|
expect(loading.value).toBe(false)
|
|
expect(assetApi.deleteAsset).toHaveBeenCalledWith(1)
|
|
})
|
|
|
|
it('应该处理删除失败', async () => {
|
|
vi.mocked(assetApi.deleteAsset).mockRejectedValue(new Error('删除失败'))
|
|
|
|
const { deleteAsset: deleteFn } = useAsset()
|
|
|
|
await expect(deleteFn(1)).rejects.toThrow('删除失败')
|
|
})
|
|
|
|
it('应该禁止删除使用中的资产', async () => {
|
|
vi.mocked(assetApi.deleteAsset).mockRejectedValue(
|
|
new Error('使用中的资产不能删除')
|
|
)
|
|
|
|
const { deleteAsset: deleteFn } = useAsset()
|
|
|
|
await expect(deleteFn(1)).rejects.toThrow('使用中的资产不能删除')
|
|
})
|
|
})
|
|
|
|
describe('importAssets', () => {
|
|
it('应该成功导入资产', async () => {
|
|
const mockFile = new File([''], 'test.xlsx', {
|
|
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
})
|
|
|
|
const importResult = {
|
|
total: 100,
|
|
success: 98,
|
|
failed: 2,
|
|
errors: [
|
|
{ row: 5, message: '设备类型不存在' },
|
|
{ row: 12, message: '序列号重复' }
|
|
]
|
|
}
|
|
|
|
vi.mocked(assetApi.importAssets).mockResolvedValue(importResult)
|
|
|
|
const { importAssets: importFn, loading } = useAsset()
|
|
const result = await importFn(mockFile)
|
|
|
|
expect(loading.value).toBe(false)
|
|
expect(result).toEqual(importResult)
|
|
expect(result.success).toBe(98)
|
|
expect(result.failed).toBe(2)
|
|
})
|
|
|
|
it('应该处理导入失败', async () => {
|
|
const mockFile = new File([''], 'test.xlsx')
|
|
|
|
vi.mocked(assetApi.importAssets).mockRejectedValue(new Error('文件格式错误'))
|
|
|
|
const { importAssets: importFn } = useAsset()
|
|
|
|
await expect(importFn(mockFile)).rejects.toThrow('文件格式错误')
|
|
})
|
|
})
|
|
|
|
describe('状态管理', () => {
|
|
it('应该正确设置loading状态', async () => {
|
|
vi.mocked(assetApi.getAssetList).mockImplementation(() =>
|
|
new Promise(resolve => {
|
|
setTimeout(() => {
|
|
resolve({ items: [], total: 0 })
|
|
}, 100)
|
|
})
|
|
)
|
|
|
|
const { fetchAssets, loading } = useAsset()
|
|
|
|
const promise = fetchAssets({ page: 1 })
|
|
expect(loading.value).toBe(true)
|
|
|
|
await promise
|
|
expect(loading.value).toBe(false)
|
|
})
|
|
|
|
it('应该管理assets响应式数据', async () => {
|
|
const mockData = {
|
|
items: [
|
|
{ id: 1, assetName: '资产1' },
|
|
{ id: 2, assetName: '资产2' }
|
|
],
|
|
total: 2
|
|
}
|
|
|
|
vi.mocked(assetApi.getAssetList).mockResolvedValue(mockData)
|
|
|
|
const { fetchAssets, assets } = useAsset()
|
|
await fetchAssets({ page: 1 })
|
|
|
|
expect(assets.value.length).toBe(2)
|
|
expect(assets.value[0].assetName).toBe('资产1')
|
|
})
|
|
})
|
|
})
|