Files
crawler-plugin/admin-frontend-vue/tests/task-1.test.ts
T
huangzd1997 ec7d56d566 task-1(壳层/路由): 冻结独立后台工程工作区边界契约与基线测试
admin-frontend-vue/src/config/workspace.ts 提供可编程边界校验(独立包名、
必需清单/源码目录、客户端耦合 token 扫描、可操作缺失消息),供后续壳层
任务与验收脚本复用;tests/task-1.test.ts 以 8 用例锁定依赖/构建/测试/边界。
2026-09-05 14:43:51 +08:00

133 lines
5.2 KiB
TypeScript

import test from 'node:test'
import assert from 'node:assert/strict'
import { mkdtempSync, rmSync, mkdirSync, writeFileSync, readFileSync, existsSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import {
ADMIN_SOURCE_DIRS,
collectBoundaryViolations,
FORBIDDEN_COUPLING_TOKENS,
readWorkspacePackage,
REQUIRED_MANIFEST_FILES,
resolveWorkspaceRoot,
STANDALONE_PACKAGE_NAME,
walk,
} from '../src/config/workspace.ts'
function tempRoot(): string {
return mkdtempSync(join(tmpdir(), 'admin-workspace-'))
}
test('test_task_001_project_baseline_normal_primary_path', () => {
// 正常主路径:独立工程从自身根目录完成一次边界校验,输出无违规。
const root = resolveWorkspaceRoot()
const violations = collectBoundaryViolations(root)
assert.deepEqual(violations, [], `工作区边界违规: ${violations.join('; ')}`)
const pkg = readWorkspacePackage(root)
assert.equal(pkg.name, STANDALONE_PACKAGE_NAME)
for (const dep of ['vue', 'vue-router', 'pinia', 'element-plus']) {
assert.ok(pkg.dependencies[dep], `缺少依赖 ${dep}`)
}
})
test('test_task_001_project_baseline_normal_variant_input', () => {
// 正常变体:构建、开发、测试三套命令形态都指向独立后台工程。
const { scripts } = readWorkspacePackage()
assert.match(scripts.build, /vue-tsc --noEmit/)
assert.match(scripts.build, /vite build/)
assert.match(scripts.dev, /vite/)
assert.match(scripts.dev, /5174/)
assert.match(scripts.test, /node --test/)
assert.match(scripts.test, /tests\/\*\.test\.ts/)
})
test('test_task_001_project_baseline_normal_repeated_operation_is_idempotent', () => {
// 正常重复:重复校验不改变结果、不产生不稳定状态。
const first = collectBoundaryViolations()
const second = collectBoundaryViolations()
assert.deepEqual(second, first, '重复校验结果应稳定一致')
const pkgA = readWorkspacePackage()
const pkgB = readWorkspacePackage()
assert.equal(pkgA.name, pkgB.name)
assert.deepEqual(pkgA.dependencies, pkgB.dependencies)
})
test('test_task_001_project_baseline_boundary_empty_input', () => {
// 边界空值:允许的源码目录集合完整存在;扫描可容忍空目录不崩溃。
const root = resolveWorkspaceRoot()
for (const dir of ADMIN_SOURCE_DIRS) {
assert.equal(existsSync(join(root, dir)), true, `缺少允许源码目录 ${dir}`)
}
const empty = tempRoot()
try {
mkdirSync(join(empty, 'src'))
assert.deepEqual(walk(empty), [], '空目录扫描应返回空结果且不抛异常')
} finally {
rmSync(empty, { recursive: true, force: true })
}
})
test('test_task_001_project_baseline_boundary_single_item', () => {
// 边界单元素:单一 SPA 入口与单一挂载点。
const root = resolveWorkspaceRoot()
const html = readFileSync(join(root, 'index.html'), 'utf8')
assert.match(html, /id="app"/)
assert.match(html, /\/src\/main\.ts/)
const main = readFileSync(join(root, 'src/main.ts'), 'utf8')
assert.match(main, /\.mount\('#app'\)/)
})
test('test_task_001_project_baseline_boundary_limit_or_missing_field', () => {
// 边界上限/缺字段:严格类型与 ESM 模块边界等关键字段必须存在。
const root = resolveWorkspaceRoot()
const tsconfig = readFileSync(join(root, 'tsconfig.json'), 'utf8')
assert.match(tsconfig, /"strict":\s*true/)
assert.match(tsconfig, /"moduleResolution":\s*"Bundler"/)
const pkg = readWorkspacePackage(root)
assert.equal(pkg.private, true)
assert.ok(pkg.scripts.test, '缺少 test 命令字段')
assert.ok(REQUIRED_MANIFEST_FILES.length >= 5, '清单字段不能为空')
})
test('test_task_001_project_baseline_invalid_input_rejected', () => {
// 异常输入:任何文件引用客户端耦合 token 都应被边界校验拒绝。
const root = tempRoot()
try {
for (const token of FORBIDDEN_COUPLING_TOKENS) {
mkdirSync(join(root, 'src'), { recursive: true })
writeFileSync(join(root, 'src', 'bad.ts'), `// 越界引用\nconst t = '${token}'\n`)
const violations = collectBoundaryViolations(root)
assert.ok(
violations.some((v) => v.includes(`引用了客户端耦合 token "${token}"`)),
`token ${token} 应被识别为越界: ${violations.join('; ')}`,
)
rmSync(join(root, 'src', 'bad.ts'))
}
} finally {
rmSync(root, { recursive: true, force: true })
}
})
test('test_task_001_project_baseline_dependency_failure_returns_actionable_message', () => {
// 依赖失败:根目录定位失败与清单缺失时返回可操作错误。
const root = tempRoot()
try {
const missing = join(root, 'no-package')
mkdirSync(missing)
assert.throws(
() => resolveWorkspaceRoot(missing),
(error: Error) => error.message.includes('package.json'),
)
const emptyDir = join(root, 'flat')
mkdirSync(emptyDir)
writeFileSync(join(emptyDir, 'package.json'), '{}')
const violations = collectBoundaryViolations(emptyDir)
assert.ok(
violations.some((v) => v.includes('缺少必需清单文件 src/main.ts')),
`依赖缺失应返回可操作清单消息: ${violations.join('; ')}`,
)
} finally {
rmSync(root, { recursive: true, force: true })
}
})