- 修复路由守卫:未登录时直接跳转,不显示提示信息 - 修复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>
191 lines
4.0 KiB
TypeScript
191 lines
4.0 KiB
TypeScript
/**
|
|
* Vitest 测试环境设置
|
|
*
|
|
* 配置全局测试环境和工具
|
|
*/
|
|
|
|
import { vi } from 'vitest'
|
|
|
|
// Mock window.matchMedia
|
|
Object.defineProperty(window, 'matchMedia', {
|
|
writable: true,
|
|
value: vi.fn().mockImplementation(query => ({
|
|
matches: false,
|
|
media: query,
|
|
onchange: null,
|
|
addListener: vi.fn(), // Deprecated
|
|
removeListener: vi.fn(), // Deprecated
|
|
addEventListener: vi.fn(),
|
|
removeEventListener: vi.fn(),
|
|
dispatchEvent: vi.fn(),
|
|
})),
|
|
})
|
|
|
|
// Mock IntersectionObserver
|
|
global.IntersectionObserver = class IntersectionObserver {
|
|
constructor() {}
|
|
disconnect() {}
|
|
observe() {}
|
|
takeRecords() {
|
|
return []
|
|
}
|
|
unobserve() {}
|
|
} as any
|
|
|
|
// Mock ResizeObserver
|
|
global.ResizeObserver = class ResizeObserver {
|
|
constructor() {}
|
|
disconnect() {}
|
|
observe() {}
|
|
unobserve() {}
|
|
} as any
|
|
|
|
// Mock localStorage
|
|
const localStorageMock = {
|
|
getItem: (key: string) => null,
|
|
setItem: (key: string, value: string) => {},
|
|
removeItem: (key: string) => {},
|
|
clear: () => {},
|
|
}
|
|
|
|
Object.defineProperty(window, 'localStorage', {
|
|
value: localStorageMock,
|
|
})
|
|
|
|
// Mock sessionStorage
|
|
const sessionStorageMock = {
|
|
getItem: (key: string) => null,
|
|
setItem: (key: string, value: string) => {},
|
|
removeItem: (key: string) => {},
|
|
clear: () => {},
|
|
}
|
|
|
|
Object.defineProperty(window, 'sessionStorage', {
|
|
value: sessionStorageMock,
|
|
})
|
|
|
|
// Mock requestAnimationFrame
|
|
global.requestAnimationFrame = (callback: FrameRequestCallback) => {
|
|
return setTimeout(callback, 16) as unknown as number
|
|
}
|
|
|
|
global.cancelAnimationFrame = (id: number) => {
|
|
clearTimeout(id)
|
|
}
|
|
|
|
// Mock console方法以减少测试输出
|
|
global.console = {
|
|
...console,
|
|
// Uncomment to ignore console logs during tests
|
|
// log: vi.fn(),
|
|
// debug: vi.fn(),
|
|
// info: vi.fn(),
|
|
// warn: vi.fn(),
|
|
// error: vi.fn(),
|
|
}
|
|
|
|
// 设置全局错误处理
|
|
window.addEventListener('error', event => {
|
|
console.error('Global error:', event.error)
|
|
})
|
|
|
|
// 设置未处理的Promise rejection
|
|
window.addEventListener('unhandledrejection', event => {
|
|
console.error('Unhandled promise rejection:', event.reason)
|
|
})
|
|
|
|
// Mock URL.createObjectURL和URL.revokeObjectURL
|
|
global.URL.createObjectURL = vi.fn(() => 'mock-url')
|
|
global.URL.revokeObjectURL = vi.fn()
|
|
|
|
// Mock navigator
|
|
Object.defineProperty(window.navigator, 'userAgent', {
|
|
value: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
|
|
writable: true,
|
|
})
|
|
|
|
// Mock scrollTo
|
|
window.scrollTo = vi.fn()
|
|
|
|
// Mock getComputedStyle
|
|
window.getComputedStyle = vi.fn(() => ({
|
|
getPropertyValue: (property: string) => {
|
|
const styles: Record<string, string> = {
|
|
display: 'block',
|
|
width: '100px',
|
|
height: '100px',
|
|
}
|
|
return styles[property] || ''
|
|
},
|
|
}))
|
|
|
|
// Mock DOMRect
|
|
global.DOMRect = class DOMRect {
|
|
constructor(
|
|
public x = 0,
|
|
public y = 0,
|
|
public width = 0,
|
|
public height = 0,
|
|
) {}
|
|
|
|
toJSON() {
|
|
return {
|
|
x: this.x,
|
|
y: this.y,
|
|
top: this.y,
|
|
left: this.x,
|
|
bottom: this.y + this.height,
|
|
right: this.x + this.width,
|
|
width: this.width,
|
|
height: this.height,
|
|
}
|
|
}
|
|
|
|
static fromRect(rect?: DOMRectInit): DOMRect {
|
|
return new DOMRect(rect?.x, rect?.y, rect?.width, rect?.height)
|
|
}
|
|
} as any
|
|
|
|
// Element.prototype.getBoundingClientRect mock
|
|
Element.prototype.getBoundingClientRect = new DOMRect(0, 0, 0, 0) as any
|
|
|
|
// 每个测试前清理
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
})
|
|
|
|
// 导出测试工具
|
|
export const TestUtils = {
|
|
/**
|
|
* 等待组件更新
|
|
*/
|
|
async flushPromises(): Promise<void> {
|
|
return new Promise(resolve => setTimeout(resolve, 0))
|
|
},
|
|
|
|
/**
|
|
* 创建Mock响应
|
|
*/
|
|
createMockResponse<T>(data: T, status = 200): Response {
|
|
return {
|
|
ok: status >= 200 && status < 300,
|
|
status,
|
|
statusText: status === 200 ? 'OK' : 'Error',
|
|
json: async () => data,
|
|
data,
|
|
} as any
|
|
},
|
|
|
|
/**
|
|
* 创建Mock API响应
|
|
*/
|
|
createMockApiResponse<T>(data: T, code = 200, message = 'success') {
|
|
return {
|
|
code,
|
|
message,
|
|
data,
|
|
timestamp: Date.now(),
|
|
}
|
|
},
|
|
}
|