错误请求列表(/admin/usage 错误 tab、Ops 弹窗、用户端 /usage 错误 tab) 对齐用量明细的交互与信息密度。Squash of: - feat(usage): 错误请求全面对齐用量明细(UI/列序/排序/筛选/列设置/新列) - refactor(usage): 错误表提取共享徽章工具与 IP 批量工具条,后端排序解析归并 SetSort - feat(usage): /admin/usage 错误请求新增分类过滤 - fix(ops): 错误列表 phase=upstream 过滤生效,守卫豁免改为显式 opt-in - fix(ops): 错误列表用户列回退显示已删除 KEY 所有者 - fix(usage): 错误请求状态码排序对齐展示/过滤,筛选项改固定常用码
99 lines
2.7 KiB
TypeScript
99 lines
2.7 KiB
TypeScript
/**
|
|
* Vitest 测试环境设置
|
|
* 提供全局 mock 和测试工具
|
|
*/
|
|
import { config } from '@vue/test-utils'
|
|
import { vi } from 'vitest'
|
|
|
|
function createMemoryStorage(): Storage {
|
|
const values = new Map<string, string>()
|
|
|
|
return {
|
|
get length() {
|
|
return values.size
|
|
},
|
|
clear() {
|
|
values.clear()
|
|
},
|
|
getItem(key: string) {
|
|
return values.has(key) ? values.get(key)! : null
|
|
},
|
|
key(index: number) {
|
|
return Array.from(values.keys())[index] ?? null
|
|
},
|
|
removeItem(key: string) {
|
|
values.delete(key)
|
|
},
|
|
setItem(key: string, value: string) {
|
|
values.set(key, String(value))
|
|
}
|
|
}
|
|
}
|
|
|
|
if (typeof globalThis.localStorage === 'undefined' || typeof globalThis.localStorage.getItem !== 'function') {
|
|
Object.defineProperty(globalThis, 'localStorage', {
|
|
configurable: true,
|
|
value: createMemoryStorage()
|
|
})
|
|
}
|
|
|
|
if (typeof window !== 'undefined' && typeof window.localStorage.getItem !== 'function') {
|
|
Object.defineProperty(window, 'localStorage', {
|
|
configurable: true,
|
|
value: globalThis.localStorage
|
|
})
|
|
}
|
|
|
|
// Mock requestIdleCallback (Safari < 15 不支持)
|
|
if (typeof globalThis.requestIdleCallback === 'undefined') {
|
|
globalThis.requestIdleCallback = ((callback: IdleRequestCallback) => {
|
|
return window.setTimeout(() => callback({ didTimeout: false, timeRemaining: () => 50 }), 1)
|
|
}) as unknown as typeof requestIdleCallback
|
|
}
|
|
|
|
if (typeof globalThis.cancelIdleCallback === 'undefined') {
|
|
globalThis.cancelIdleCallback = ((id: number) => {
|
|
window.clearTimeout(id)
|
|
}) as unknown as typeof cancelIdleCallback
|
|
}
|
|
|
|
// Mock matchMedia (jsdom 未实现;DataTable 等组件依赖它做桌面/移动分支)
|
|
if (typeof window !== 'undefined' && typeof window.matchMedia !== 'function') {
|
|
window.matchMedia = ((query: string) => ({
|
|
matches: true, // 测试默认按桌面视口渲染表格
|
|
media: query,
|
|
onchange: null,
|
|
addListener: vi.fn(),
|
|
removeListener: vi.fn(),
|
|
addEventListener: vi.fn(),
|
|
removeEventListener: vi.fn(),
|
|
dispatchEvent: vi.fn(),
|
|
})) as unknown as typeof window.matchMedia
|
|
}
|
|
|
|
// Mock IntersectionObserver
|
|
class MockIntersectionObserver {
|
|
observe = vi.fn()
|
|
disconnect = vi.fn()
|
|
unobserve = vi.fn()
|
|
}
|
|
|
|
globalThis.IntersectionObserver = MockIntersectionObserver as unknown as typeof IntersectionObserver
|
|
|
|
// Mock ResizeObserver
|
|
class MockResizeObserver {
|
|
observe = vi.fn()
|
|
disconnect = vi.fn()
|
|
unobserve = vi.fn()
|
|
}
|
|
|
|
globalThis.ResizeObserver = MockResizeObserver as unknown as typeof ResizeObserver
|
|
|
|
// Vue Test Utils 全局配置
|
|
config.global.stubs = {
|
|
// 可以在这里添加全局 stub
|
|
}
|
|
|
|
// 设置全局测试超时
|
|
vi.setConfig({ testTimeout: 10000 })
|