feat: renew mvp

This commit is contained in:
skytek_xinliang
2026-05-04 17:36:36 +08:00
parent 5fe3ba771e
commit 65b72b82cb
21 changed files with 1036 additions and 1177 deletions
+42 -19
View File
@@ -10,11 +10,9 @@ import { promisify } from 'node:util'
const exec = promisify(execFile)
const cli = new URL('../src/cli.js', import.meta.url).pathname
test('CLI runs scan, plan, run, diff, and verify against one prototype', async () => {
test('CLI runs doctor and scan against one prototype', async () => {
const cwd = await mkdtemp(join(tmpdir(), 'ht-e2e-'))
await mkdir(join(cwd, 'packages/prototype'), { recursive: true })
await mkdir(join(cwd, 'packages/web/src'), { recursive: true })
await mkdir(join(cwd, 'packages/api'), { recursive: true })
await writeFile(join(cwd, 'packages/prototype/index.html'), `
<main>
<h1>Customer Portal</h1>
@@ -25,24 +23,49 @@ test('CLI runs scan, plan, run, diff, and verify against one prototype', async (
</form>
</main>
`)
await writeFile(join(cwd, 'packages/web/src/App.vue'), '<template><v-app /></template>')
await writeFile(join(cwd, 'packages/api/openapi.json'), '{"openapi":"3.0.0","paths":{}}')
await writeFile(join(cwd, 'ht.config.js'), `
export default {
plan: { interactiveReview: false },
project: { qualityCommands: {} }
}
`)
for (const command of ['scan', 'plan', 'run', 'diff', 'verify']) {
await exec('node', [cli, command], { cwd })
}
const doctor = await exec('node', [cli, 'doctor'], { cwd })
await exec('node', [cli, 'scan'], { cwd })
const component = await readFile(join(cwd, 'packages/result/index/main-1.vue'), 'utf8')
const report = JSON.parse(await readFile(join(cwd, '.ht/verify/verification-report.json'), 'utf8'))
const contract = await readFile(join(cwd, '.ht/spec/index.ui-contract.md'), 'utf8')
const spec = JSON.parse(await readFile(join(cwd, '.ht/spec/index.spec.json'), 'utf8'))
const validation = JSON.parse(await readFile(join(cwd, '.ht/spec/index.validation.json'), 'utf8'))
const appMap = JSON.parse(await readFile(join(cwd, '.ht/app-map.json'), 'utf8'))
assert.match(component, /Customer Portal/)
assert.match(component, /v-text-field/)
assert.equal(report.domChecks.status, 'passed')
assert.match(doctor.stdout, /ok prototype directory/)
assert.match(contract, /Customer Portal/)
assert.equal(spec.pageContract.title, null)
assert.deepEqual(spec.pageContract.forms[0].fields[0], {
name: 'email',
label: 'Email',
type: 'input',
required: true
})
assert.equal(validation.requiresHumanReview, false)
assert.equal(appMap.routes[0].prototype, 'index.html')
assert.equal(appMap.routes[0].kind, 'feature-page')
assert.equal(appMap.routes[0].layout, 'template-app')
})
test('CLI help only exposes MVP commands', async () => {
const result = await exec('node', [cli, 'help'])
assert.match(result.stdout, /doctor/)
assert.match(result.stdout, /scan/)
assert.doesNotMatch(result.stdout, /plan/)
assert.doesNotMatch(result.stdout, /run/)
assert.doesNotMatch(result.stdout, /diff/)
assert.doesNotMatch(result.stdout, /verify/)
})
test('CLI rejects removed pipeline commands', async () => {
await assert.rejects(
exec('node', [cli, 'plan']),
(error) => {
assert.equal(error.code, 1)
assert.match(error.stdout, /doctor/)
assert.match(error.stdout, /scan/)
return true
}
)
})