test: 补充 Phase 3 专项测试并更新测试报告

新增性能基准测试、安全验证、国际化完整性验证等专项测试;
修复 E2E 测试选择器与当前 UI 不匹配问题;
补充多语言 locale 缺失的 key;
更新 Playwright 配置支持跨浏览器测试;
同步更新测试报告与 README 进度章节。

单元测试 408/408 通过,E2E 测试 39/39 通过(4 种浏览器),
专项测试 47/47 通过,整体覆盖率 77.5%。
This commit is contained in:
2026-08-12 20:10:39 +08:00
parent 0f8b29874f
commit 3a428d8977
28 changed files with 1542 additions and 1045 deletions
@@ -0,0 +1,100 @@
import { describe, it, expect } from 'vitest'
import zhCN from '../../locales/zh-CN'
import zhTW from '../../locales/zh-TW'
import en from '../../locales/en'
import ja from '../../locales/ja'
import ko from '../../locales/ko'
import de from '../../locales/de'
import fr from '../../locales/fr'
import es from '../../locales/es'
import pt from '../../locales/pt'
// 递归收集所有键路径
function collectKeys(obj: Record<string, any>, prefix = ''): string[] {
const keys: string[] = []
for (const [key, value] of Object.entries(obj)) {
const fullKey = prefix ? `${prefix}.${key}` : key
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
keys.push(...collectKeys(value, fullKey))
} else {
keys.push(fullKey)
}
}
return keys.sort()
}
// 递归收集键路径及其值,用于比较值是否为空
function collectKeysWithValues(obj: Record<string, any>, prefix = ''): Map<string, string> {
const result = new Map<string, string>()
for (const [key, value] of Object.entries(obj)) {
const fullKey = prefix ? `${prefix}.${key}` : key
if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
const nested = collectKeysWithValues(value, fullKey)
nested.forEach((v, k) => result.set(k, v))
} else {
result.set(fullKey, String(value))
}
}
return result
}
const zhCNKeys = collectKeys(zhCN)
const localeModules = {
'zh-TW': zhTW,
'en': en,
'ja': ja,
'ko': ko,
'de': de,
'fr': fr,
'es': es,
'pt': pt,
} as const
describe('TC-I18N-001~009: 国际化完整性验证', () => {
for (const [locale, module] of Object.entries(localeModules)) {
const localeName = {
'zh-TW': '繁体中文',
'en': '英文',
'ja': '日文',
'ko': '韩文',
'de': '德文',
'fr': '法文',
'es': '西班牙文',
'pt': '葡萄牙文',
}[locale]
describe(`${locale} (${localeName})`, () => {
it(`应包含所有 zh-CN 中的键`, () => {
const localeKeys = collectKeys(module)
const missingKeys = zhCNKeys.filter(k => !localeKeys.includes(k))
if (missingKeys.length > 0) {
console.warn(`[${locale}] 缺少以下键:`, missingKeys)
}
expect(missingKeys).toEqual([])
})
it(`不应包含多余的键`, () => {
const localeKeys = collectKeys(module)
const extraKeys = localeKeys.filter(k => !zhCNKeys.includes(k))
if (extraKeys.length > 0) {
console.warn(`[${locale}] 存在额外键:`, extraKeys)
}
expect(extraKeys).toEqual([])
})
it(`所有键的值不应为空字符串`, () => {
const values = collectKeysWithValues(module)
const emptyValues: string[] = []
values.forEach((value, key) => {
if (value.trim() === '') emptyValues.push(key)
})
expect(emptyValues).toEqual([])
})
it(`应包含正确数量的键 (${zhCNKeys.length} 个)`, () => {
const localeKeys = collectKeys(module)
expect(localeKeys.length).toBe(zhCNKeys.length)
})
})
}
})