/** * 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') }) }) })