96 lines
3.6 KiB
JavaScript
96 lines
3.6 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { execFile } from 'node:child_process'
|
|
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
import { join } from 'node:path'
|
|
import { tmpdir } from 'node:os'
|
|
import { mkdtemp } from 'node:fs/promises'
|
|
import { promisify } from 'node:util'
|
|
|
|
const exec = promisify(execFile)
|
|
const cli = new URL('../src/cli.js', import.meta.url).pathname
|
|
|
|
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 writeFile(join(cwd, 'packages/prototype/index.html'), `
|
|
<main>
|
|
<h1>Customer Portal</h1>
|
|
<form>
|
|
<label>Email</label>
|
|
<input name="email" required>
|
|
<button>Submit</button>
|
|
</form>
|
|
</main>
|
|
`)
|
|
await writeFile(join(cwd, 'packages/prototype/portal.md'), `
|
|
# Portal Guide
|
|
|
|
| 雛型檔 | 舊 JSP 來源 | 功能 |
|
|
| --- | --- | --- |
|
|
| [\`index.html\`](index.html) | \`legacy/index.jsp\` | Customer portal entry |
|
|
`)
|
|
await mkdir(join(cwd, '.playwright'), { recursive: true })
|
|
await writeFile(join(cwd, '.playwright/cli.config.json'), JSON.stringify({
|
|
browser: {
|
|
browserName: 'chromium'
|
|
}
|
|
}, null, 2))
|
|
|
|
const doctor = await exec('node', [cli, 'doctor'], { cwd })
|
|
await exec('node', [cli, 'scan'], { cwd })
|
|
|
|
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(doctor.stdout, /ok prototype directory/)
|
|
assert.equal(spec.pageContract.title, null)
|
|
assert.equal(spec.bddContract.feature, 'Customer portal entry')
|
|
assert.equal(spec.bddContract.scenarios[0].type, 'application-submit')
|
|
assert.match(spec.captureArtifacts.domSummary, /\.ht\/cache\/prototype\/index\/dom-summary\.json$/)
|
|
assert.match(spec.captureArtifacts.accessibilityTree, /\.ht\/cache\/prototype\/index\/accessibility-tree\.json$/)
|
|
assert.equal(Array.isArray(spec.browserEvidence.externalResourceFailures), true)
|
|
assert.deepEqual(pick(spec.pageContract.forms[0].fields[0], ['name', 'label', 'type', 'required']), {
|
|
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')
|
|
assert.equal(appMap.routes[0].recommendedTemplate, undefined)
|
|
assert.equal(appMap.routes[0].evidence.recommendedTemplate, undefined)
|
|
assert.equal(appMap.routes[0].guide.legacyJsp, 'legacy/index.jsp')
|
|
assert.equal(appMap.routes[0].guide.description, 'Customer portal entry')
|
|
})
|
|
|
|
function pick(object, keys) {
|
|
return Object.fromEntries(keys.map((key) => [key, object[key]]))
|
|
}
|
|
|
|
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
|
|
}
|
|
)
|
|
})
|