121 lines
4.3 KiB
JavaScript
121 lines
4.3 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import fs from 'node:fs'
|
|
import os from 'node:os'
|
|
import path from 'node:path'
|
|
import { execSync } from 'node:child_process'
|
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
|
|
const __filename = fileURLToPath(import.meta.url)
|
|
const __dirname = path.dirname(__filename)
|
|
const repoRoot = path.resolve(__dirname, '..')
|
|
|
|
const tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'imhotep-external-smoke-'))
|
|
const projectDir = path.join(tmp, 'project')
|
|
fs.mkdirSync(projectDir, { recursive: true })
|
|
|
|
const localDeps = {
|
|
imhotep: path.join(repoRoot, 'packages/imhotep'),
|
|
'imhotep-playwright': path.join(repoRoot, 'packages/imhotep-playwright'),
|
|
'imhotep-core': path.join(repoRoot, 'packages/imhotep-core'),
|
|
'imhotep-dsl': path.join(repoRoot, 'packages/imhotep-dsl'),
|
|
'imhotep-extractor': path.join(repoRoot, 'packages/imhotep-extractor'),
|
|
'imhotep-geometry': path.join(repoRoot, 'packages/imhotep-geometry'),
|
|
'imhotep-cdp': path.join(repoRoot, 'packages/imhotep-cdp'),
|
|
'imhotep-reporter': path.join(repoRoot, 'packages/imhotep-reporter'),
|
|
'imhotep-solver': path.join(repoRoot, 'packages/imhotep-solver'),
|
|
'imhotep-state': path.join(repoRoot, 'packages/imhotep-state'),
|
|
'imhotep-topology': path.join(repoRoot, 'packages/imhotep-topology'),
|
|
}
|
|
|
|
const pkg = {
|
|
name: 'imhotep-external-smoke',
|
|
version: '1.0.0',
|
|
type: 'module',
|
|
private: true,
|
|
dependencies: Object.fromEntries(
|
|
Object.entries(localDeps).map(([name, depPath]) => [name, `file:${depPath}`]),
|
|
),
|
|
devDependencies: {
|
|
'@playwright/test': '^1.59.1',
|
|
playwright: '^1.59.1',
|
|
},
|
|
}
|
|
|
|
fs.writeFileSync(path.join(projectDir, 'package.json'), JSON.stringify(pkg, null, 2))
|
|
|
|
const fixtureDir = path.join(projectDir, 'fixtures')
|
|
fs.mkdirSync(fixtureDir, { recursive: true })
|
|
fs.writeFileSync(
|
|
path.join(fixtureDir, 'smoke.html'),
|
|
`<!doctype html>
|
|
<html lang="en"><head><meta charset="UTF-8"><title>smoke</title>
|
|
<style>
|
|
.wrap { display:flex; gap: 16px; align-items:center; }
|
|
.left,.right { width: 100px; height: 44px; }
|
|
.toolbar { display:flex; gap: 8px; }
|
|
.toolbar button { min-width: 44px; min-height: 44px; }
|
|
</style></head>
|
|
<body>
|
|
<div class="wrap">
|
|
<div class="left" data-testid="left"></div>
|
|
<div class="right" data-testid="right"></div>
|
|
</div>
|
|
<div class="toolbar" data-testid="toolbar">
|
|
<button data-testid="a">A</button>
|
|
<button data-testid="b">B</button>
|
|
</div>
|
|
</body></html>`,
|
|
)
|
|
|
|
execSync('npm install --no-audit --no-fund', { cwd: projectDir, stdio: 'inherit' })
|
|
|
|
const smokeScript = path.join(projectDir, 'smoke.mjs')
|
|
fs.writeFileSync(
|
|
smokeScript,
|
|
`import assert from 'node:assert/strict'
|
|
import { chromium } from 'playwright'
|
|
import { imhotep, imhotepFixture, enumeratedDomain, touchTarget, toolbarAlignment } from 'imhotep'
|
|
import { pathToFileURL } from 'node:url'
|
|
import path from 'node:path'
|
|
|
|
const browser = await chromium.launch({ headless: true })
|
|
const page = await browser.newPage({ viewport: { width: 1200, height: 800 } })
|
|
const fixturePath = path.resolve('fixtures/smoke.html')
|
|
await page.goto(pathToFileURL(fixturePath).href)
|
|
|
|
const ui = await imhotep(page, { deterministic: true, seed: 42 })
|
|
ui.expect('[data-testid="left"]').to.be.leftOf('[data-testid="right"]', { minGap: 8 })
|
|
touchTarget(ui, '[data-testid="a"]')
|
|
toolbarAlignment(ui, ['[data-testid="a"]', '[data-testid="b"]'])
|
|
|
|
const result = await ui.checkAll({ includeNormalized: true })
|
|
assert.equal(typeof result.schemaVersion, 'string')
|
|
assert.ok(Array.isArray(result.normalizedContracts))
|
|
|
|
ui.spec("a is leftOf b")
|
|
const parseLlm = await ui.checkAll({ format: 'llm' })
|
|
const parsePayload = JSON.parse(parseLlm)
|
|
assert.equal(parsePayload.passed, false)
|
|
assert.ok(parsePayload.failingClauses.length > 0)
|
|
|
|
const fixture = imhotepFixture('smoke.html', { fixturesDir: './fixtures', env: { deterministic: true, seed: 7 } })
|
|
const run = await fixture.exhaustivelyForAllInputs(
|
|
page,
|
|
enumeratedDomain([{ variant: 'ok' }]),
|
|
async (scene) => {
|
|
scene.expect('[data-testid="left"]').to.be.leftOf('[data-testid="right"]', { minGap: 8 })
|
|
},
|
|
{ reportMode: 'compact' },
|
|
)
|
|
assert.equal(run.mode, 'enumerated-determinate')
|
|
assert.ok('minimalFailingCase' in run || run.passed)
|
|
|
|
await browser.close()
|
|
console.log('external smoke passed')
|
|
`,
|
|
)
|
|
|
|
execSync('node smoke.mjs', { cwd: projectDir, stdio: 'inherit' })
|
|
|
|
console.log(`External smoke succeeded: ${projectDir}`)
|