import { describe, it, expect, onTestFinished } from "vitest"; import { mkdtempSync, rmSync, cpSync, existsSync, readFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { execSync } from "node:child_process"; import { join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; // Repo root is 2 levels up from turbo/generators/__tests__ const REPO_ROOT = resolve( fileURLToPath(import.meta.url), "..", "..", "..", "..", ); /** * Generator-composition e2e: scaffold a feature, then run `gen job` against * the freshly-scaffolded feature. * * The `core-package` e2e tests verify each generator's output in isolation * (byte-identical snapshots). This one verifies generators run *in sequence*: * `gen job` asserts the consumer feature's `integrations/cms/index.ts` carries * a `` anchor, so this test fails loudly if the `feature` * template ever stops emitting that barrel — the regression that shipped once. */ describe("e2e: feature generator composition", () => { it( "scaffolds a feature that `gen job` can extend", { timeout: 180_000 }, () => { const tmp = mkdtempSync(join(tmpdir(), "e2e-feature-")); // Remove the temp clone when the test finishes so sequential runs // don't accumulate and fill disk. onTestFinished(() => rmSync(tmp, { recursive: true, force: true })); cpSync(REPO_ROOT, tmp, { recursive: true, filter: (src) => !src.includes("node_modules") && !src.includes(".turbo") && !src.includes(".pnpm-store") && // Build outputs are large and irrelevant to the scaffold — cloning // dist/.next fills the tmp dir and slows every e2e run. !src.includes("/dist") && !src.includes("/.next"), }); execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { stdio: "ignore", }); execSync( `cd ${tmp} && pnpm turbo gen feature --args demo-feature Widget widgets`, { stdio: "ignore" }, ); // Regression guard: `gen job` throws at its anchor assertion if the // feature template did not emit src/integrations/cms/index.ts. execSync( `cd ${tmp} && pnpm turbo gen job --args demo-feature send-demo-email void`, { stdio: "ignore" }, ); const featureRoot = join(tmp, "packages", "demo-feature"); const cmsIndex = join(featureRoot, "src/integrations/cms/index.ts"); expect(existsSync(cmsIndex)).toBe(true); expect(readFileSync(cmsIndex, "utf8")).toContain( 'export { sendDemoEmailTask } from "./jobs/send-demo-email.task"', ); expect( existsSync(join(featureRoot, "src/jobs/send-demo-email.job.ts")), ).toBe(true); const pkgJson = JSON.parse( readFileSync(join(featureRoot, "package.json"), "utf8"), ) as { exports: Record }; expect(pkgJson.exports["./cms"]).toBe("./src/integrations/cms/index.ts"); }, ); });