fix: 修复前端登录体验和API调用问题
- 修复路由守卫:未登录时直接跳转,不显示提示信息 - 修复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>
This commit is contained in:
190
tests/setup.ts
Normal file
190
tests/setup.ts
Normal file
@@ -0,0 +1,190 @@
|
||||
/**
|
||||
* 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(),
|
||||
}
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user