c81ebb7053
- 根因:polling-backoff-recovery 测试断言失败后跳过 loop.dispose(),残留自续期定时器导致 node --test 子进程永不退出 - dead-code-cleanup:移除套娃用例 test_full_vitest_green(再跑一遍全量套件,放大问题),execSync 加 300s 超时;其余静态断言保留 - package.json:node --test --test-force-exit --test-timeout=180000 - CI workflow 前端测试步骤改为 npm test(与 package.json 单一来源) - 修正 3 处过时期望值(轮询退避/品牌 files+taskType/巡店 delete_conditions) - 验证:本地 666 用例全过,19-24s,无残留进程
79 lines
3.1 KiB
TypeScript
79 lines
3.1 KiB
TypeScript
import { test } from 'node:test'
|
||
import assert from 'node:assert/strict'
|
||
import { execSync } from 'node:child_process'
|
||
import { readFileSync, existsSync, readdirSync } from 'node:fs'
|
||
import { fileURLToPath } from 'node:url'
|
||
import { resolve, dirname } from 'node:path'
|
||
|
||
const here = dirname(fileURLToPath(import.meta.url))
|
||
const repoRoot = resolve(here, '..')
|
||
|
||
/** 子命令一律带超时:卡住时快速失败,不再把整个测试进程树拖死 */
|
||
const CHILD_TIMEOUT_MS = 300_000
|
||
|
||
function run(cmd: string): string {
|
||
const env = { ...process.env }
|
||
delete env.NODE_TEST_CONTEXT
|
||
return execSync(cmd, { cwd: repoRoot, encoding: 'utf-8', env, timeout: CHILD_TIMEOUT_MS })
|
||
}
|
||
|
||
test('test_no_unexported_duplicates', () => {
|
||
const source = readFileSync(resolve(repoRoot, 'src/shared/api/java-modules.ts'), 'utf-8')
|
||
const lines = source.split('\n').filter((line) => line.includes('export * from'))
|
||
const targets = lines
|
||
.map((line) => line.match(/export \* from "\.\/([^"]+)"/)?.[1])
|
||
.filter(Boolean)
|
||
assert.equal(new Set(targets).size, targets.length, '不应有重复的 re-export')
|
||
})
|
||
|
||
test('test_build_typecheck', () => {
|
||
const output = run('npx vue-tsc --noEmit')
|
||
assert.equal(output.trim(), '', `vue-tsc 应零错误,实际: ${output.slice(0, 500)}`)
|
||
})
|
||
|
||
test('test_no_console_debug_left', () => {
|
||
const apiDir = resolve(repoRoot, 'src/shared/api')
|
||
for (const file of readdirSync(apiDir, { recursive: true }) as string[]) {
|
||
if (!file.endsWith('.ts')) continue
|
||
const source = readFileSync(resolve(apiDir, file), 'utf-8')
|
||
assert.ok(
|
||
!/console\.(log|debug)\(/.test(source),
|
||
`${file} 不应残留调试日志`,
|
||
)
|
||
}
|
||
})
|
||
|
||
test('test_no_unused_import', () => {
|
||
const source = readFileSync(resolve(repoRoot, 'src/shared/api/java-modules.ts'), 'utf-8')
|
||
// 聚合器除 re-export 外不应有其它 import/函数体
|
||
const deadMarkers = [
|
||
'function postTaskProgressBatch',
|
||
'const taskProgressResponseCache',
|
||
'function getCurrentUserId',
|
||
'function normalizeTaskIds',
|
||
'function buildTaskProgressRequestKey',
|
||
'async function uploadTempFileToJava',
|
||
'function getJavaDownloadUrl',
|
||
]
|
||
for (const marker of deadMarkers) {
|
||
assert.ok(!source.includes(marker), `java-modules.ts 不应残留: ${marker}`)
|
||
}
|
||
})
|
||
|
||
test('test_entry_points_compile', () => {
|
||
const viteConfig = readFileSync(resolve(repoRoot, 'vite.config.ts'), 'utf-8')
|
||
const entries = [...viteConfig.matchAll(/['"]([^'"]+\.html)['"]/g)].map((m) => m[1])
|
||
// SPA(2026-09-08):单入口 index.html,页面由 vue-router 渲染
|
||
assert.deepEqual(entries, ['index.html'], `应仅 index.html 单入口,实际 ${entries.join(', ')}`)
|
||
for (const entry of entries) {
|
||
assert.ok(existsSync(resolve(repoRoot, entry)), `入口 ${entry} 应存在`)
|
||
}
|
||
})
|
||
|
||
test('test_bundle_build', () => {
|
||
const outDir = resolve(repoRoot, 'new_web_source')
|
||
assert.ok(existsSync(outDir), '构建产物目录应存在')
|
||
assert.ok(existsSync(resolve(outDir, 'index.html')), 'SPA 产物应包含 index.html')
|
||
assert.ok(existsSync(resolve(outDir, 'assets')), 'SPA 产物应包含 assets/')
|
||
})
|