Files
crawler-plugin/frontend-vue/tests/dead-code-cleanup.test.ts
T
huangzd1997 e248b6e43a feat(web): 前端 SPA 化 + 工具页任务面板统一与历史批量删除
- SPA 化:22 个 MPA html 入口与 *-main.ts 合并为 index.html + vue-router(URL 无 .html 后缀),
  页面跳转全部 router-link,/new_web_source/xxx.html 旧路径归一为 /xxx
- 任务面板统一:共享 TaskCenterPanel/TaskItemCard/TaskStatCards/HistoryTaskLayer,
  16 个工具页右侧统一为统计卡 + 当前任务 + 历史任务弹层(任务ID/开始/结束/状态必展示)
- 历史记录支持单条删除 + 批量勾选删除(确认框/全选/失败提示)
- Java 7 模块(dedupe/convert/split/productrisk/shopmatch/pricetrack/deletebrand)
  history 接口补齐任务时间字段(VO+Service,复用 biz_file_task 列)
- 图片工作台/API 层(brand/permission/user)既有未提交改动一并提交
2026-09-08 10:02:55 +08:00

106 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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])
// SPA2026-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/')
})
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, '应检出本次提交的变更')
const frontendTouched = changed.some((file) => file.startsWith('frontend-vue/'))
if (!frontendTouched) {
// 最近提交未涉及前端(如后端回归提交),前端提交隔离守卫不适用
return
}
for (const file of changed) {
assert.ok(
file.startsWith('frontend-vue/'),
`前端提交变更应仅限 frontend-vue 目录,越界: ${file}`,
)
}
})