Files
agentic-dev/turbo/generators/__tests__/feature.e2e.test.ts
Danijel Martinek f77e6ea881 chore(template): clean-slate template snapshot from bb4a0c7
Curated, product-agnostic snapshot of the post-story-04 tree: demo
content deleted, auth-only reference feature, web-next shell, all gates
green. Product-specific docs, ADRs 027-029, PRDs/epics/archive, editor
library traces, and product naming are curated out; generic template
repairs (coverage provider devDeps, root test:coverage script, live
lint fixes, root-only release-please) are kept. See TEMPLATE.md for
provenance, curation list, and usage.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
2026-07-12 20:40:54 +02:00

77 lines
2.7 KiB
TypeScript

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 `<gen:job-tasks>` 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"),
});
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<string, string> };
expect(pkgJson.exports["./cms"]).toBe("./src/integrations/cms/index.ts");
},
);
});