/** * Tests for the live-insert CLI helper. * Run with: node --test tests/live-insert.test.mjs */ import { describe, it, beforeEach, afterEach } from 'node:test'; import assert from 'node:assert/strict'; import { mkdtempSync, writeFileSync, readFileSync, rmSync } from 'node:fs'; import { join } from 'node:path'; import { tmpdir } from 'node:os'; import { execSync } from 'node:child_process'; import { computeInsertLine, buildInsertWrapperLines, isInsertPosition, } from '../skill/scripts/live-insert.mjs'; describe('isInsertPosition', () => { it('accepts before and after only', () => { assert.equal(isInsertPosition('before'), true); assert.equal(isInsertPosition('after'), true); assert.equal(isInsertPosition('inside'), false); assert.equal(isInsertPosition(''), false); }); }); describe('computeInsertLine', () => { it('returns startLine for before', () => { assert.equal(computeInsertLine(10, 14, 'before'), 10); }); it('returns endLine + 1 for after', () => { assert.equal(computeInsertLine(10, 14, 'after'), 15); }); }); describe('buildInsertWrapperLines', () => { it('produces an insert scaffold without an original variant', () => { const lines = buildInsertWrapperLines({ id: 'abc12345', count: 3, indent: ' ', commentSyntax: { open: '' }, isJsx: false, }); const joined = lines.join('\n'); assert.match(joined, /impeccable-variants-start abc12345/); assert.match(joined, /data-impeccable-variants="abc12345"/); assert.match(joined, /data-impeccable-mode="insert"/); assert.match(joined, /Variants: insert below this line/); assert.doesNotMatch(joined, /data-impeccable-variant="original"/); }); it('keeps marker comments inside the wrapper for JSX', () => { const lines = buildInsertWrapperLines({ id: 'jsx12345', count: 2, indent: ' ', commentSyntax: { open: '{/*', close: '*/}' }, isJsx: true, }); const joined = lines.join('\n'); assert.match(joined, /^\s*
{ let tmp; beforeEach(() => { tmp = mkdtempSync(join(tmpdir(), 'impeccable-insert-test-')); }); afterEach(() => { rmSync(tmp, { recursive: true, force: true }); }); it('splices an insert wrapper after an anchor element in HTML', () => { writeFileSync(join(tmp, 'index.html'), `

Hero

Features

`); const out = execSync( `node skill/scripts/live-insert.mjs --id ins12345 --count 3 --position after --classes "hero" --tag section --file "${join(tmp, 'index.html')}"`, { encoding: 'utf-8' }, ); const result = JSON.parse(out.trim()); assert.equal(result.mode, 'insert'); assert.equal(result.position, 'after'); assert.ok(result.insertLine > 0); const after = readFileSync(join(tmp, 'index.html'), 'utf-8'); assert.match(after, /data-impeccable-mode="insert"/); assert.match(after, /impeccable-variants-start ins12345/); assert.ok(after.indexOf('class="hero"') < after.indexOf('impeccable-variants-start ins12345')); assert.ok(after.indexOf('impeccable-variants-start ins12345') < after.indexOf('class="features"')); assert.doesNotMatch(after, /data-impeccable-variant="original"/); }); it('splices an insert wrapper before an anchor element', () => { writeFileSync(join(tmp, 'page.html'), `
Hero
CTA
`); execSync( `node skill/scripts/live-insert.mjs --id ins99999 --count 2 --position before --classes "cta" --tag section --file "${join(tmp, 'page.html')}"`, { encoding: 'utf-8' }, ); const after = readFileSync(join(tmp, 'page.html'), 'utf-8'); assert.ok(after.indexOf('impeccable-variants-start ins99999') < after.indexOf('class="cta"')); assert.ok(after.indexOf('class="hero"') < after.indexOf('impeccable-variants-start ins99999')); }); it('works in JSX files with inner marker comments', () => { writeFileSync(join(tmp, 'App.jsx'), `export default function App() { return (
Hero
Footer
); }`); const out = execSync( `node skill/scripts/live-insert.mjs --id jsxins01 --count 3 --position after --classes "hero" --tag section --file "${join(tmp, 'App.jsx')}"`, { encoding: 'utf-8' }, ); const result = JSON.parse(out.trim()); assert.equal(result.commentSyntax.open, '{/*'); const after = readFileSync(join(tmp, 'App.jsx'), 'utf-8'); assert.match(after, /data-impeccable-mode="insert"/); assert.match(after, /{\/\* impeccable-variants-start jsxins01 \*\/}/); }); it('exits with error when position is missing', () => { writeFileSync(join(tmp, 'empty.html'), '
x
'); assert.throws( () => execSync( `node skill/scripts/live-insert.mjs --id bad00001 --count 2 --classes x --file "${join(tmp, 'empty.html')}"`, { encoding: 'utf-8', stdio: 'pipe' }, ), (err) => err.status !== 0, ); }); it('exits with error for invalid position', () => { writeFileSync(join(tmp, 'empty.html'), '
x
'); assert.throws( () => execSync( `node skill/scripts/live-insert.mjs --id bad00002 --count 2 --position inside --classes x --file "${join(tmp, 'empty.html')}"`, { encoding: 'utf-8', stdio: 'pipe' }, ), (err) => err.status !== 0, ); }); });