Files
Imhotep/packages/imhotep-cli/src/init.test.ts
T

132 lines
5.9 KiB
TypeScript

// RED phase: Test that scaffolding produces working projects
import assert from 'node:assert';
import { test, describe } from 'node:test';
import { mkdtempSync, existsSync, readFileSync, rmSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { initProject } from './init.js';
import { getPresetNames, getPreset } from './presets/index.js';
describe('imhotep init', () => {
test('react-playwright preset creates expected files', () => {
const targetDir = mkdtempSync(join(tmpdir(), 'imhotep-init-test-'));
try {
initProject({ preset: 'react', targetDir });
// Verify all expected files exist
assert.ok(existsSync(join(targetDir, 'imhotep.config.js')), 'config file should exist');
assert.ok(existsSync(join(targetDir, 'tests', 'example.test.ts')), 'test file should exist');
assert.ok(existsSync(join(targetDir, 'fixtures', 'example.html')), 'fixture file should exist');
assert.ok(existsSync(join(targetDir, 'package.json')), 'package.json should exist');
assert.ok(existsSync(join(targetDir, 'README.md')), 'README should exist');
// Verify config has render target
const config = readFileSync(join(targetDir, 'imhotep.config.js'), 'utf-8');
assert.ok(config.includes('render'), 'config should mention render target');
// Verify test file has assertions
const testFile = readFileSync(join(targetDir, 'tests', 'example.test.ts'), 'utf-8');
assert.ok(testFile.includes('expect'), 'test should have assertions');
// Verify package.json has test scripts
const pkg = JSON.parse(readFileSync(join(targetDir, 'package.json'), 'utf-8'));
assert.ok(pkg.scripts.test, 'package.json should have test script');
assert.ok(pkg.scripts['test:ci'], 'package.json should have ci script');
} finally {
rmSync(targetDir, { recursive: true, force: true });
}
});
test('vue preset creates expected files', () => {
const targetDir = mkdtempSync(join(tmpdir(), 'imhotep-init-test-'));
try {
initProject({ preset: 'vue', targetDir });
assert.ok(existsSync(join(targetDir, 'imhotep.config.js')), 'config file should exist');
assert.ok(existsSync(join(targetDir, 'tests', 'example.test.ts')), 'test file should exist');
assert.ok(existsSync(join(targetDir, 'fixtures', 'example.html')), 'fixture file should exist');
assert.ok(existsSync(join(targetDir, 'package.json')), 'package.json should exist');
assert.ok(existsSync(join(targetDir, 'README.md')), 'README should exist');
const config = readFileSync(join(targetDir, 'imhotep.config.js'), 'utf-8');
assert.ok(config.includes('render'), 'config should mention render target');
} finally {
rmSync(targetDir, { recursive: true, force: true });
}
});
test('storybook preset creates expected files', () => {
const targetDir = mkdtempSync(join(tmpdir(), 'imhotep-init-test-'));
try {
initProject({ preset: 'storybook', targetDir });
assert.ok(existsSync(join(targetDir, 'imhotep.config.js')), 'config file should exist');
assert.ok(existsSync(join(targetDir, 'tests', 'example.test.ts')), 'test file should exist');
assert.ok(existsSync(join(targetDir, 'fixtures', 'example.html')), 'fixture file should exist');
assert.ok(existsSync(join(targetDir, 'package.json')), 'package.json should exist');
assert.ok(existsSync(join(targetDir, 'README.md')), 'README should exist');
const config = readFileSync(join(targetDir, 'imhotep.config.js'), 'utf-8');
assert.ok(config.includes('render'), 'config should mention render target');
} finally {
rmSync(targetDir, { recursive: true, force: true });
}
});
test('throws on unknown preset', () => {
const targetDir = mkdtempSync(join(tmpdir(), 'imhotep-init-test-'));
try {
assert.throws(() => {
initProject({ preset: 'unknown-preset', targetDir });
}, /Unknown preset/);
} finally {
rmSync(targetDir, { recursive: true, force: true });
}
});
test('scaffolded react tests have passing assertions syntax', () => {
const targetDir = mkdtempSync(join(tmpdir(), 'imhotep-init-test-'));
try {
initProject({ preset: 'react', targetDir });
const testFile = readFileSync(join(targetDir, 'tests', 'example.test.ts'), 'utf-8');
assert.ok(testFile.includes('const ui = await imhotep(page);'), 'template should await imhotep(page)');
assert.ok(testFile.includes('await ui.checkAll();'), 'template should evaluate batched assertions with checkAll()');
} finally {
rmSync(targetDir, { recursive: true, force: true });
}
});
test('all presets use publish-safe dependency ranges (no workspace protocol)', () => {
for (const name of getPresetNames()) {
const preset = getPreset(name);
const pkg = preset.packageJson;
for (const [dep, version] of Object.entries(pkg.devDependencies ?? {})) {
assert.ok(typeof version === 'string', `dependency ${dep} in ${name} should be a string`);
assert.ok(!version.startsWith('workspace:'), `${name} must not use workspace protocol for ${dep}`);
}
}
});
test('new framework presets scaffold expected files', () => {
const extraPresets = ['next', 'nuxt', 'remix', 'astro'];
for (const preset of extraPresets) {
const targetDir = mkdtempSync(join(tmpdir(), 'imhotep-init-test-'));
try {
initProject({ preset, targetDir });
assert.ok(existsSync(join(targetDir, 'imhotep.config.js')), `${preset} config should exist`);
assert.ok(existsSync(join(targetDir, 'tests', 'example.test.ts')), `${preset} test should exist`);
assert.ok(existsSync(join(targetDir, 'fixtures', 'example.html')), `${preset} fixture should exist`);
} finally {
rmSync(targetDir, { recursive: true, force: true });
}
}
});
});