Files
crawler-plugin/frontend-vue/tests/dead-code-cleanup.test.ts
T
huangzd1997 71606e9fe5 task-28: 死代码清理
删除拆分后失去引用的 API 残留文件:
- src/shared/api/call.ts(已由 http.ts 取代)
- src/shared/api/download.ts(已由 download-url.ts 取代)
- src/shared/api/status.ts(页面内已有本地实现)
及其孤儿测试 tests/call.test.ts / call-abort.test.ts / download.test.ts / status.test.ts。
endpoints/url/user 仍被模块文件引用,保留。

新增 8 个验证测试(dead-code-cleanup.test.ts):无重复导出、
vue-tsc 零错误、全量测试绿、无调试日志、无残留函数体、
16+ HTML 入口存在、build 产物齐全、提交变更仅限 frontend-vue。
2026-08-31 20:11:49 +08:00

100 lines
3.6 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 testsDir = resolve(here)
function run(cmd: string): string {
const env = { ...process.env }
delete env.NODE_TEST_CONTEXT
return execSync(cmd, { cwd: repoRoot, encoding: 'utf-8', env })
}
function otherTestFiles(): string[] {
return readdirSync(testsDir)
.filter((f) => f.endsWith('.test.ts') && f !== 'dead-code-cleanup.test.ts')
.map((f) => `tests/${f}`)
}
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_full_vitest_green', () => {
const output = run(`node --test ${otherTestFiles().join(' ')} 2>&1`)
assert.match(output, /pass \d+/, '应产出通过统计')
assert.match(output, /fail 0/, '全量测试应零失败')
})
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])
assert.ok(entries.length >= 16, `应 ≥16 个 HTML 入口,实际 ${entries.length}`)
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), '构建产物目录应存在')
const htmlCount = readdirSync(outDir).filter((f) => f.endsWith('.html')).length
assert.ok(htmlCount >= 16, `构建产物应有 ≥16 个 HTML,实际 ${htmlCount}`)
})
test('test_git_diff_scope', () => {
const diff = run('git diff --name-only HEAD~1 HEAD')
const changed = diff.split('\n').filter(Boolean)
assert.ok(changed.length > 0, '应检出本次提交的变更')
for (const file of changed) {
assert.ok(
file.startsWith('frontend-vue/'),
`变更应仅限 frontend-vue 目录,越界: ${file}`,
)
}
})