test(cli): cover DOM/CSS import
This commit is contained in:
parent
97246a67ce
commit
2c66336c58
186
tests/engine/cli/dom.test.ts
Normal file
186
tests/engine/cli/dom.test.ts
Normal file
|
|
@ -0,0 +1,186 @@
|
|||
import { expect, setDefaultTimeout, test } from 'bun:test'
|
||||
import { mkdtemp } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
|
||||
import { parseFigFile } from '@open-pencil/core/io'
|
||||
import type { SceneNode } from '@open-pencil/core/scene-graph'
|
||||
|
||||
import { cliSourcePath } from '#tests/helpers/paths'
|
||||
|
||||
setDefaultTimeout(30_000)
|
||||
|
||||
const CLI = cliSourcePath('index.ts')
|
||||
|
||||
interface CommandResult {
|
||||
stdout: string
|
||||
stderr: string
|
||||
exitCode: number
|
||||
}
|
||||
|
||||
async function run(args: string[]): Promise<CommandResult> {
|
||||
const proc = Bun.spawn(['bun', CLI, ...args], {
|
||||
stdout: 'pipe',
|
||||
stderr: 'pipe'
|
||||
})
|
||||
const [stdout, stderr] = await Promise.all([
|
||||
new Response(proc.stdout).text(),
|
||||
new Response(proc.stderr).text()
|
||||
])
|
||||
const exitCode = await proc.exited
|
||||
return { stdout: stdout.trim(), stderr: stderr.trim(), exitCode }
|
||||
}
|
||||
|
||||
async function createFixture() {
|
||||
const dir = await mkdtemp(join(tmpdir(), 'open-pencil-dom-cli-'))
|
||||
const htmlPath = join(dir, 'card.html')
|
||||
const cssPath = join(dir, 'card.css')
|
||||
|
||||
await Bun.write(
|
||||
htmlPath,
|
||||
`
|
||||
<article class="card">
|
||||
<h1>DOM/CSS card</h1>
|
||||
<p>Imported from HTML and CSS.</p>
|
||||
</article>
|
||||
`
|
||||
)
|
||||
await Bun.write(
|
||||
cssPath,
|
||||
`
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
width: 240px;
|
||||
padding: 24px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #dddddd;
|
||||
border-radius: 16px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
}
|
||||
`
|
||||
)
|
||||
|
||||
return { dir, htmlPath, cssPath }
|
||||
}
|
||||
|
||||
function findNode(nodes: Iterable<SceneNode>, name: string): SceneNode | undefined {
|
||||
for (const node of nodes) {
|
||||
if (node.name === name) return node
|
||||
}
|
||||
}
|
||||
|
||||
test('dom CLI writes DesignDOM JSON output', async () => {
|
||||
const { htmlPath, cssPath, dir } = await createFixture()
|
||||
const output = join(dir, 'card.json')
|
||||
|
||||
const { stdout, stderr, exitCode } = await run([
|
||||
'dom',
|
||||
htmlPath,
|
||||
'--css',
|
||||
cssPath,
|
||||
'--format',
|
||||
'json',
|
||||
'--output',
|
||||
output,
|
||||
'--json'
|
||||
])
|
||||
|
||||
expect(stderr).toBe('')
|
||||
expect(exitCode).toBe(0)
|
||||
|
||||
const summary = JSON.parse(stdout)
|
||||
expect(summary).toMatchObject({ format: 'json', output, pages: 1, rootElements: 1 })
|
||||
|
||||
const document = JSON.parse(await Bun.file(output).text())
|
||||
expect(document.children[0].tagName).toBe('article')
|
||||
expect(document.children[0].computedStyle.display).toBe('flex')
|
||||
expect(document.children[0].computedStyle.width).toBe('240px')
|
||||
})
|
||||
|
||||
test('dom CLI writes serialized HTML output', async () => {
|
||||
const { htmlPath, cssPath, dir } = await createFixture()
|
||||
const output = join(dir, 'card.out.html')
|
||||
|
||||
const { stderr, exitCode } = await run([
|
||||
'dom',
|
||||
htmlPath,
|
||||
'--css',
|
||||
cssPath,
|
||||
'--format',
|
||||
'html',
|
||||
'--output',
|
||||
output
|
||||
])
|
||||
|
||||
expect(stderr).toBe('')
|
||||
expect(exitCode).toBe(0)
|
||||
|
||||
const html = await Bun.file(output).text()
|
||||
expect(html).toContain('DOM/CSS card')
|
||||
expect(html).toContain('class="card"')
|
||||
})
|
||||
|
||||
test('dom CLI writes a .fig that core IO can import', async () => {
|
||||
const { htmlPath, cssPath, dir } = await createFixture()
|
||||
const output = join(dir, 'card.fig')
|
||||
|
||||
const { stdout, stderr, exitCode } = await run([
|
||||
'dom',
|
||||
htmlPath,
|
||||
'--css',
|
||||
cssPath,
|
||||
'--output',
|
||||
output,
|
||||
'--json'
|
||||
])
|
||||
|
||||
expect(stderr).toBe('')
|
||||
expect(exitCode).toBe(0)
|
||||
expect(JSON.parse(stdout)).toMatchObject({ format: 'fig', output, pages: 1, rootElements: 1 })
|
||||
|
||||
const bytes = new Uint8Array(await Bun.file(output).arrayBuffer())
|
||||
const graph = await parseFigFile(bytes)
|
||||
const nodes = [...graph.nodes.values()]
|
||||
const card = findNode(nodes, 'card')
|
||||
const title = findNode(nodes, 'DOM/CSS card')
|
||||
|
||||
expect(graph.getPages()).toHaveLength(1)
|
||||
expect(card?.type).toBe('FRAME')
|
||||
expect(title?.type).toBe('TEXT')
|
||||
})
|
||||
|
||||
test('dom CLI compiles Tailwind candidates before import', async () => {
|
||||
const dir = await mkdtemp(join(tmpdir(), 'open-pencil-dom-cli-tailwind-'))
|
||||
const htmlPath = join(dir, 'tailwind.html')
|
||||
const output = join(dir, 'tailwind.json')
|
||||
const classes = ['flex', 'flex-col', 'gap-2', 'w-60', 'p-6', 'rounded-xl', 'bg-white']
|
||||
|
||||
await Bun.write(
|
||||
htmlPath,
|
||||
`<article class="${classes.join(' ')}"><h1 class="text-2xl">Tailwind card</h1></article>`
|
||||
)
|
||||
|
||||
const { stdout, stderr, exitCode } = await run([
|
||||
'dom',
|
||||
htmlPath,
|
||||
'--tailwind',
|
||||
classes.join(' '),
|
||||
'--format',
|
||||
'json',
|
||||
'--output',
|
||||
output,
|
||||
'--json'
|
||||
])
|
||||
|
||||
expect(stderr).toBe('')
|
||||
expect(exitCode).toBe(0)
|
||||
expect(JSON.parse(stdout)).toMatchObject({ format: 'json', output })
|
||||
|
||||
const document = JSON.parse(await Bun.file(output).text())
|
||||
expect(document.children[0].computedStyle.display).toBe('flex')
|
||||
expect(document.children[0].computedStyle.width).toBe('240px')
|
||||
})
|
||||
Loading…
Reference in a new issue