/** * cele2e scaffold — generate a new e2e test file from template. */ import { existsSync, mkdirSync, writeFileSync } from 'node:fs'; import { join } from 'node:path'; const green = '\x1b[32m'; const dim = '\x1b[2m'; const reset = '\x1b[0m'; interface ScaffoldOptions { testsPath: string; name: string; } function toTitleCase(kebab: string): string { return kebab .split('-') .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) .join(' '); } function generateTestTemplate(name: string): string { const title = toTitleCase(name); return `/** * ${title} E2E Test * * Tests that ${title} deploys and operates correctly through Celilo's infrastructure. * * Run: cele2e run ${name} * Run (reuse): cele2e run --reuse ${name} */ import { afterAll, describe, expect } from 'bun:test'; import { createStages, network, progress, reconnectNetwork } from '@celilo/e2e'; import type { NetworkHandle } from '@celilo/e2e/types'; const REUSE = process.argv.includes('--reuse'); const PROJECT_NAME = 'celilo-e2e-${name}'; describe('${name}', () => { const { stage } = createStages(); let net: NetworkHandle; afterAll(async () => { await net?.stop(); }); stage('start network', async () => { if (REUSE) { net = await reconnectNetwork(PROJECT_NAME); return; } net = await network({ projectName: PROJECT_NAME }) .dmz({ 'machine-1': '10.226.10.10' }) // .app({ 'app-1': '10.226.20.10' }) .start(); }, 120_000); // Each stage runs as its own bun test with its own timeout. If a stage fails // or times out, the later stages skip with a 'Skipped: ...' reason naming // the cause, instead of running against a half-built fixture. stage('deploy', async () => { progress('importing module', 'module imported'); await net.celilo('module import /path/to/module.netapp'); progress.done(); progress('deploying', 'deployed'); await net.celilo('module deploy my-module'); progress.done(); }, 300_000); stage('verify', async () => { // TODO: add verification steps // const result = await net.exec('machine-1', 'curl -s http://localhost'); // expect(result.exitCode).toBe(0); }, 60_000); }); `; } export function runScaffold(options: ScaffoldOptions): void { const { testsPath, name } = options; mkdirSync(testsPath, { recursive: true }); const outPath = join(testsPath, `${name}.test.ts`); if (existsSync(outPath)) { console.error(`Error: ${outPath} already exists`); process.exit(1); } writeFileSync(outPath, generateTestTemplate(name)); console.log(`${green}✔${reset} Created ${outPath}`); console.log(`\n${dim}Run it with:\n cele2e run ${name}${reset}`); }