diff --git a/turbo/generators/__snapshots__/core-package/analytics.snapshot.json b/turbo/generators/__snapshots__/core-package/analytics.snapshot.json new file mode 100644 index 0000000..dfd8c78 --- /dev/null +++ b/turbo/generators/__snapshots__/core-package/analytics.snapshot.json @@ -0,0 +1,30 @@ +[ + { + "path": "AGENTS.md", + "sha256": "c4cb865dc6eb42d8bac7b23cd00938b9de3777b6c4adcfc8e81c149314230209" + }, + { + "path": "eslint.config.js", + "sha256": "64a85c158e386417d855793d256b9c59be38635ce2febcb5a6a15b17f4143745" + }, + { + "path": "package.json", + "sha256": "91591798591061068905b8f4ca55aed284fd749acd3eaa818a25289a33c17cc5" + }, + { + "path": "src/index.ts", + "sha256": "d60ea0ad5b84b5362b3de9ae9efd7e7e8122062f58f6e4cf867a4eb72ba18d4d" + }, + { + "path": "tsconfig.json", + "sha256": "0ed0e183a0842acb42a8c712a9dad0217b4612a9ae17e1f3a3f61b638d204147" + }, + { + "path": "turbo.json", + "sha256": "ae544305202c960399110a31fe976e2c38577956c5aa738989f5d885f156d130" + }, + { + "path": "vitest.config.ts", + "sha256": "cc7a9e6aba7cbe81af665c3e1bf50f535f77a2b950db8ccc62775c7b5d380df7" + } +] diff --git a/turbo/generators/__snapshots__/core-package/consent.snapshot.json b/turbo/generators/__snapshots__/core-package/consent.snapshot.json new file mode 100644 index 0000000..16f5e58 --- /dev/null +++ b/turbo/generators/__snapshots__/core-package/consent.snapshot.json @@ -0,0 +1,30 @@ +[ + { + "path": "AGENTS.md", + "sha256": "a3307770deb2e9a9df9dab056b0044effcd670c554f7c578ddd801106bf3b543" + }, + { + "path": "eslint.config.js", + "sha256": "64a85c158e386417d855793d256b9c59be38635ce2febcb5a6a15b17f4143745" + }, + { + "path": "package.json", + "sha256": "e11fb392c9c97b2998e3cac367a8eacea7f83154d8d7434091a8247cc4bf6a8e" + }, + { + "path": "src/index.ts", + "sha256": "5c3a1b2a7ad29c987cf4ab08f6b6479572842d11565af7b12ecfa99cf0b7d818" + }, + { + "path": "tsconfig.json", + "sha256": "0ed0e183a0842acb42a8c712a9dad0217b4612a9ae17e1f3a3f61b638d204147" + }, + { + "path": "turbo.json", + "sha256": "ae544305202c960399110a31fe976e2c38577956c5aa738989f5d885f156d130" + }, + { + "path": "vitest.config.ts", + "sha256": "cc7a9e6aba7cbe81af665c3e1bf50f535f77a2b950db8ccc62775c7b5d380df7" + } +] diff --git a/turbo/generators/__snapshots__/core-package/dsr.snapshot.json b/turbo/generators/__snapshots__/core-package/dsr.snapshot.json new file mode 100644 index 0000000..d4b24b6 --- /dev/null +++ b/turbo/generators/__snapshots__/core-package/dsr.snapshot.json @@ -0,0 +1,30 @@ +[ + { + "path": "AGENTS.md", + "sha256": "7c8f31314379d35b44cd5cdb71e4726698e169bd5b058457359dd2a35230f183" + }, + { + "path": "eslint.config.js", + "sha256": "64a85c158e386417d855793d256b9c59be38635ce2febcb5a6a15b17f4143745" + }, + { + "path": "package.json", + "sha256": "3df6efaf45ae2c5d9b1a268c9a222db97f2f073a0a0e898a1514c26bb3948396" + }, + { + "path": "src/index.ts", + "sha256": "e9458cd5cacd4f1e574a794baeaee4790737c2481506b4268d965613f6fe744a" + }, + { + "path": "tsconfig.json", + "sha256": "0ed0e183a0842acb42a8c712a9dad0217b4612a9ae17e1f3a3f61b638d204147" + }, + { + "path": "turbo.json", + "sha256": "ae544305202c960399110a31fe976e2c38577956c5aa738989f5d885f156d130" + }, + { + "path": "vitest.config.ts", + "sha256": "cc7a9e6aba7cbe81af665c3e1bf50f535f77a2b950db8ccc62775c7b5d380df7" + } +] diff --git a/turbo/generators/__tests__/core-package-analytics.e2e.test.ts b/turbo/generators/__tests__/core-package-analytics.e2e.test.ts new file mode 100644 index 0000000..bc93a33 --- /dev/null +++ b/turbo/generators/__tests__/core-package-analytics.e2e.test.ts @@ -0,0 +1,49 @@ +import { describe, it, expect, onTestFinished } from "vitest"; +import { mkdtempSync, rmSync, cpSync } 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"; +import { computeSnapshot } from "../lib/snapshot.js"; +import expectedSnapshot from "../__snapshots__/core-package/analytics.snapshot.json" with { type: "json" }; + +// Repo root is 2 levels up from turbo/generators/__tests__ +const REPO_ROOT = resolve( + fileURLToPath(import.meta.url), + "..", + "..", + "..", + "..", +); + +describe("e2e: core-package analytics", () => { + it( + "byte-identical reconstruction matches snapshot", + { timeout: 120_000 }, + () => { + const tmp = mkdtempSync(join(tmpdir(), "e2e-analytics-")); + // Each e2e run clones the repo into the OS temp dir; remove it 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") && + !src.includes("packages/core-analytics"), + }); + + // No other package.json depends on @repo/core-analytics, so no strip + // step is needed — excluding the source dir is sufficient. + execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { + stdio: "ignore", + }); + execSync(`cd ${tmp} && pnpm turbo gen core-package --args analytics`, { + stdio: "ignore", + }); + const result = computeSnapshot(join(tmp, "packages/core-analytics")); + expect(result).toEqual(expectedSnapshot); + }, + ); +}); diff --git a/turbo/generators/__tests__/core-package-audit.e2e.test.ts b/turbo/generators/__tests__/core-package-audit.e2e.test.ts index 8d05136..18af1b1 100644 --- a/turbo/generators/__tests__/core-package-audit.e2e.test.ts +++ b/turbo/generators/__tests__/core-package-audit.e2e.test.ts @@ -1,5 +1,11 @@ -import { describe, it, expect } from "vitest"; -import { mkdtempSync, cpSync, readFileSync, writeFileSync } from "node:fs"; +import { describe, it, expect, onTestFinished } from "vitest"; +import { + mkdtempSync, + rmSync, + cpSync, + readFileSync, + writeFileSync, +} from "node:fs"; import { tmpdir } from "node:os"; import { execSync } from "node:child_process"; import { join, resolve } from "node:path"; @@ -8,7 +14,13 @@ import { computeSnapshot } from "../lib/snapshot.js"; import expectedSnapshot from "../__snapshots__/core-package/audit.snapshot.json" with { type: "json" }; // Repo root is 2 levels up from turbo/generators/__tests__ -const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".."); +const REPO_ROOT = resolve( + fileURLToPath(import.meta.url), + "..", + "..", + "..", + "..", +); /** * Strip "@repo/core-audit" from a package.json file in the tmp tree. @@ -19,7 +31,11 @@ const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".." function stripCoreAuditDep(pkgJsonPath: string): void { const raw = readFileSync(pkgJsonPath, "utf8"); const parsed = JSON.parse(raw) as Record>; - for (const section of ["dependencies", "devDependencies", "peerDependencies"] as const) { + for (const section of [ + "dependencies", + "devDependencies", + "peerDependencies", + ] as const) { if (parsed[section]?.["@repo/core-audit"]) { delete parsed[section]["@repo/core-audit"]; } @@ -28,23 +44,35 @@ function stripCoreAuditDep(pkgJsonPath: string): void { } describe("e2e: core-package audit", () => { - it("byte-identical reconstruction matches snapshot", { timeout: 120_000 }, () => { - const tmp = mkdtempSync(join(tmpdir(), "e2e-audit-")); - cpSync(REPO_ROOT, tmp, { - recursive: true, - filter: (src) => - !src.includes("node_modules") && - !src.includes(".turbo") && - !src.includes("packages/core-audit"), - }); + it( + "byte-identical reconstruction matches snapshot", + { timeout: 120_000 }, + () => { + const tmp = mkdtempSync(join(tmpdir(), "e2e-audit-")); + // Each e2e run clones the repo into the OS temp dir; remove it 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") && + !src.includes("packages/core-audit"), + }); - // Strip @repo/core-audit from apps/web-next/package.json so pnpm install - // succeeds without the package being present (simulating the post-removal state). - stripCoreAuditDep(join(tmp, "apps", "web-next", "package.json")); + // Strip @repo/core-audit from apps/web-next/package.json so pnpm install + // succeeds without the package being present (simulating the post-removal state). + stripCoreAuditDep(join(tmp, "apps", "web-next", "package.json")); - execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { stdio: "ignore" }); - execSync(`cd ${tmp} && pnpm turbo gen core-package --args audit`, { stdio: "ignore" }); - const result = computeSnapshot(join(tmp, "packages/core-audit")); - expect(result).toEqual(expectedSnapshot); - }); + execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { + stdio: "ignore", + }); + execSync(`cd ${tmp} && pnpm turbo gen core-package --args audit`, { + stdio: "ignore", + }); + const result = computeSnapshot(join(tmp, "packages/core-audit")); + expect(result).toEqual(expectedSnapshot); + }, + ); }); diff --git a/turbo/generators/__tests__/core-package-consent.e2e.test.ts b/turbo/generators/__tests__/core-package-consent.e2e.test.ts new file mode 100644 index 0000000..cb51790 --- /dev/null +++ b/turbo/generators/__tests__/core-package-consent.e2e.test.ts @@ -0,0 +1,79 @@ +import { describe, it, expect, onTestFinished } from "vitest"; +import { + mkdtempSync, + rmSync, + cpSync, + readFileSync, + writeFileSync, +} 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"; +import { computeSnapshot } from "../lib/snapshot.js"; +import expectedSnapshot from "../__snapshots__/core-package/consent.snapshot.json" with { type: "json" }; + +// Repo root is 2 levels up from turbo/generators/__tests__ +const REPO_ROOT = resolve( + fileURLToPath(import.meta.url), + "..", + "..", + "..", + "..", +); + +/** + * Strip "@repo/core-consent" from a package.json file in the tmp tree. + * Required when simulating a fresh scaffold: core-consent does not exist yet + * but the snapshot was captured before removal. Other packages in the current + * tree may still list it as a dependency. + */ +function stripCoreConsentDep(pkgJsonPath: string): void { + const raw = readFileSync(pkgJsonPath, "utf8"); + const parsed = JSON.parse(raw) as Record>; + for (const section of [ + "dependencies", + "devDependencies", + "peerDependencies", + ] as const) { + if (parsed[section]?.["@repo/core-consent"]) { + delete parsed[section]["@repo/core-consent"]; + } + } + writeFileSync(pkgJsonPath, JSON.stringify(parsed, null, 2) + "\n"); +} + +describe("e2e: core-package consent", () => { + it( + "byte-identical reconstruction matches snapshot", + { timeout: 120_000 }, + () => { + const tmp = mkdtempSync(join(tmpdir(), "e2e-consent-")); + // Each e2e run clones the repo into the OS temp dir; remove it 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") && + !src.includes("packages/core-consent"), + }); + + // Strip @repo/core-consent from package.json files so pnpm install + // succeeds without the package being present (simulating the post-removal state). + stripCoreConsentDep(join(tmp, "packages", "core-api", "package.json")); + stripCoreConsentDep(join(tmp, "packages", "core-ui", "package.json")); + + execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { + stdio: "ignore", + }); + execSync(`cd ${tmp} && pnpm turbo gen core-package --args consent`, { + stdio: "ignore", + }); + const result = computeSnapshot(join(tmp, "packages/core-consent")); + expect(result).toEqual(expectedSnapshot); + }, + ); +}); diff --git a/turbo/generators/__tests__/core-package-dsr.e2e.test.ts b/turbo/generators/__tests__/core-package-dsr.e2e.test.ts new file mode 100644 index 0000000..75084c4 --- /dev/null +++ b/turbo/generators/__tests__/core-package-dsr.e2e.test.ts @@ -0,0 +1,78 @@ +import { describe, it, expect, onTestFinished } from "vitest"; +import { + mkdtempSync, + rmSync, + cpSync, + readFileSync, + writeFileSync, +} 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"; +import { computeSnapshot } from "../lib/snapshot.js"; +import expectedSnapshot from "../__snapshots__/core-package/dsr.snapshot.json" with { type: "json" }; + +// Repo root is 2 levels up from turbo/generators/__tests__ +const REPO_ROOT = resolve( + fileURLToPath(import.meta.url), + "..", + "..", + "..", + "..", +); + +/** + * Strip "@repo/core-dsr" from a package.json file in the tmp tree. + * Required when simulating a fresh scaffold: core-dsr does not exist yet + * but the snapshot was captured before removal. Other packages in the current + * tree may still list it as a dependency. + */ +function stripCoreDsrDep(pkgJsonPath: string): void { + const raw = readFileSync(pkgJsonPath, "utf8"); + const parsed = JSON.parse(raw) as Record>; + for (const section of [ + "dependencies", + "devDependencies", + "peerDependencies", + ] as const) { + if (parsed[section]?.["@repo/core-dsr"]) { + delete parsed[section]["@repo/core-dsr"]; + } + } + writeFileSync(pkgJsonPath, JSON.stringify(parsed, null, 2) + "\n"); +} + +describe("e2e: core-package dsr", () => { + it( + "byte-identical reconstruction matches snapshot", + { timeout: 120_000 }, + () => { + const tmp = mkdtempSync(join(tmpdir(), "e2e-dsr-")); + // Each e2e run clones the repo into the OS temp dir; remove it 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") && + !src.includes("packages/core-dsr"), + }); + + // Strip @repo/core-dsr from package.json files so pnpm install + // succeeds without the package being present (simulating the post-removal state). + stripCoreDsrDep(join(tmp, "packages", "core-api", "package.json")); + + execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { + stdio: "ignore", + }); + execSync(`cd ${tmp} && pnpm turbo gen core-package --args dsr`, { + stdio: "ignore", + }); + const result = computeSnapshot(join(tmp, "packages/core-dsr")); + expect(result).toEqual(expectedSnapshot); + }, + ); +}); diff --git a/turbo/generators/__tests__/core-package-events.e2e.test.ts b/turbo/generators/__tests__/core-package-events.e2e.test.ts index 8c7fbf0..7587d99 100644 --- a/turbo/generators/__tests__/core-package-events.e2e.test.ts +++ b/turbo/generators/__tests__/core-package-events.e2e.test.ts @@ -1,5 +1,11 @@ -import { describe, it, expect } from "vitest"; -import { mkdtempSync, cpSync, readFileSync, writeFileSync } from "node:fs"; +import { describe, it, expect, onTestFinished } from "vitest"; +import { + mkdtempSync, + rmSync, + cpSync, + readFileSync, + writeFileSync, +} from "node:fs"; import { tmpdir } from "node:os"; import { execSync } from "node:child_process"; import { join, resolve } from "node:path"; @@ -8,7 +14,13 @@ import { computeSnapshot } from "../lib/snapshot.js"; import expectedSnapshot from "../__snapshots__/core-package/events.snapshot.json" with { type: "json" }; // Repo root is 2 levels up from turbo/generators/__tests__ -const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".."); +const REPO_ROOT = resolve( + fileURLToPath(import.meta.url), + "..", + "..", + "..", + "..", +); /** * Strip "@repo/core-events" from a package.json file in the tmp tree. @@ -19,7 +31,11 @@ const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".." function stripCoreEventsDep(pkgJsonPath: string): void { const raw = readFileSync(pkgJsonPath, "utf8"); const parsed = JSON.parse(raw) as Record>; - for (const section of ["dependencies", "devDependencies", "peerDependencies"] as const) { + for (const section of [ + "dependencies", + "devDependencies", + "peerDependencies", + ] as const) { if (parsed[section]?.["@repo/core-events"]) { delete parsed[section]["@repo/core-events"]; } @@ -28,29 +44,47 @@ function stripCoreEventsDep(pkgJsonPath: string): void { } describe("e2e: core-package events", () => { - it("byte-identical reconstruction matches snapshot", { timeout: 120_000 }, () => { - const tmp = mkdtempSync(join(tmpdir(), "e2e-events-")); - cpSync(REPO_ROOT, tmp, { - recursive: true, - filter: (src) => - !src.includes("node_modules") && - !src.includes(".turbo") && - !src.includes("packages/core-events"), - }); + it( + "byte-identical reconstruction matches snapshot", + { timeout: 120_000 }, + () => { + const tmp = mkdtempSync(join(tmpdir(), "e2e-events-")); + // Each e2e run clones the repo into the OS temp dir; remove it 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") && + !src.includes("packages/core-events"), + }); - // Strip @repo/core-events from feature package.json files so pnpm install - // succeeds without the package being present (simulating the post-removal state). - const featurePackages = ["auth", "blog", "media", "marketing-pages", "navigation"]; - for (const pkg of featurePackages) { - const pkgJson = join(tmp, "packages", pkg, "package.json"); - stripCoreEventsDep(pkgJson); - } - // Also strip from apps/web-next - stripCoreEventsDep(join(tmp, "apps", "web-next", "package.json")); + // Strip @repo/core-events from feature package.json files so pnpm install + // succeeds without the package being present (simulating the post-removal state). + const featurePackages = [ + "auth", + "blog", + "media", + "marketing-pages", + "navigation", + ]; + for (const pkg of featurePackages) { + const pkgJson = join(tmp, "packages", pkg, "package.json"); + stripCoreEventsDep(pkgJson); + } + // Also strip from apps/web-next + stripCoreEventsDep(join(tmp, "apps", "web-next", "package.json")); - execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { stdio: "ignore" }); - execSync(`cd ${tmp} && pnpm turbo gen core-package --args events`, { stdio: "ignore" }); - const result = computeSnapshot(join(tmp, "packages/core-events")); - expect(result).toEqual(expectedSnapshot); - }); + execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { + stdio: "ignore", + }); + execSync(`cd ${tmp} && pnpm turbo gen core-package --args events`, { + stdio: "ignore", + }); + const result = computeSnapshot(join(tmp, "packages/core-events")); + expect(result).toEqual(expectedSnapshot); + }, + ); }); diff --git a/turbo/generators/__tests__/core-package-realtime.e2e.test.ts b/turbo/generators/__tests__/core-package-realtime.e2e.test.ts index d976b44..f3fb052 100644 --- a/turbo/generators/__tests__/core-package-realtime.e2e.test.ts +++ b/turbo/generators/__tests__/core-package-realtime.e2e.test.ts @@ -1,5 +1,5 @@ -import { describe, it, expect } from "vitest"; -import { mkdtempSync, cpSync } from "node:fs"; +import { describe, it, expect, onTestFinished } from "vitest"; +import { mkdtempSync, rmSync, cpSync } from "node:fs"; import { tmpdir } from "node:os"; import { execSync } from "node:child_process"; import { join, resolve } from "node:path"; @@ -8,21 +8,39 @@ import { computeSnapshot } from "../lib/snapshot.js"; import expectedSnapshot from "../__snapshots__/core-package/realtime.snapshot.json" with { type: "json" }; // Repo root is 2 levels up from turbo/generators/__tests__ -const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".."); +const REPO_ROOT = resolve( + fileURLToPath(import.meta.url), + "..", + "..", + "..", + "..", +); describe("e2e: core-package realtime", () => { - it("byte-identical reconstruction matches snapshot", { timeout: 120_000 }, () => { - const tmp = mkdtempSync(join(tmpdir(), "e2e-")); - cpSync(REPO_ROOT, tmp, { - recursive: true, - filter: (src) => - !src.includes("node_modules") && - !src.includes(".turbo") && - !src.includes("packages/core-realtime"), - }); - execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { stdio: "ignore" }); - execSync(`cd ${tmp} && pnpm turbo gen core-package --args realtime`, { stdio: "ignore" }); - const result = computeSnapshot(join(tmp, "packages/core-realtime")); - expect(result).toEqual(expectedSnapshot); - }); + it( + "byte-identical reconstruction matches snapshot", + { timeout: 120_000 }, + () => { + const tmp = mkdtempSync(join(tmpdir(), "e2e-")); + // Each e2e run clones the repo into the OS temp dir; remove it 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") && + !src.includes("packages/core-realtime"), + }); + execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { + stdio: "ignore", + }); + execSync(`cd ${tmp} && pnpm turbo gen core-package --args realtime`, { + stdio: "ignore", + }); + const result = computeSnapshot(join(tmp, "packages/core-realtime")); + expect(result).toEqual(expectedSnapshot); + }, + ); }); diff --git a/turbo/generators/__tests__/core-package-trpc.e2e.test.ts b/turbo/generators/__tests__/core-package-trpc.e2e.test.ts index 55774e3..183dd6d 100644 --- a/turbo/generators/__tests__/core-package-trpc.e2e.test.ts +++ b/turbo/generators/__tests__/core-package-trpc.e2e.test.ts @@ -1,5 +1,11 @@ -import { describe, it, expect } from "vitest"; -import { mkdtempSync, cpSync, readFileSync, writeFileSync } from "node:fs"; +import { describe, it, expect, onTestFinished } from "vitest"; +import { + mkdtempSync, + rmSync, + cpSync, + readFileSync, + writeFileSync, +} from "node:fs"; import { tmpdir } from "node:os"; import { execSync } from "node:child_process"; import { join, resolve } from "node:path"; @@ -8,7 +14,13 @@ import { computeSnapshot } from "../lib/snapshot.js"; import expectedSnapshot from "../__snapshots__/core-package/trpc.snapshot.json" with { type: "json" }; // Repo root is 2 levels up from turbo/generators/__tests__ -const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".."); +const REPO_ROOT = resolve( + fileURLToPath(import.meta.url), + "..", + "..", + "..", + "..", +); /** * Strip "@repo/core-trpc" from a package.json file in the tmp tree. @@ -19,7 +31,11 @@ const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".." function stripCoreTrpcDep(pkgJsonPath: string): void { const raw = readFileSync(pkgJsonPath, "utf8"); const parsed = JSON.parse(raw) as Record>; - for (const section of ["dependencies", "devDependencies", "peerDependencies"] as const) { + for (const section of [ + "dependencies", + "devDependencies", + "peerDependencies", + ] as const) { if (parsed[section]?.["@repo/core-trpc"]) { delete parsed[section]["@repo/core-trpc"]; } @@ -28,24 +44,36 @@ function stripCoreTrpcDep(pkgJsonPath: string): void { } describe("e2e: core-package trpc", () => { - it("byte-identical reconstruction matches snapshot", { timeout: 120_000 }, () => { - const tmp = mkdtempSync(join(tmpdir(), "e2e-trpc-")); - cpSync(REPO_ROOT, tmp, { - recursive: true, - filter: (src) => - !src.includes("node_modules") && - !src.includes(".turbo") && - !src.includes("packages/core-trpc"), - }); + it( + "byte-identical reconstruction matches snapshot", + { timeout: 120_000 }, + () => { + const tmp = mkdtempSync(join(tmpdir(), "e2e-trpc-")); + // Each e2e run clones the repo into the OS temp dir; remove it 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") && + !src.includes("packages/core-trpc"), + }); - // Strip @repo/core-trpc from app package.json files so pnpm install - // succeeds without the package being present (simulating the post-removal state). - stripCoreTrpcDep(join(tmp, "apps", "web-next", "package.json")); - stripCoreTrpcDep(join(tmp, "apps", "web-tanstack", "package.json")); + // Strip @repo/core-trpc from app package.json files so pnpm install + // succeeds without the package being present (simulating the post-removal state). + stripCoreTrpcDep(join(tmp, "apps", "web-next", "package.json")); + stripCoreTrpcDep(join(tmp, "apps", "web-tanstack", "package.json")); - execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { stdio: "ignore" }); - execSync(`cd ${tmp} && pnpm turbo gen core-package --args trpc`, { stdio: "ignore" }); - const result = computeSnapshot(join(tmp, "packages/core-trpc")); - expect(result).toEqual(expectedSnapshot); - }); + execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { + stdio: "ignore", + }); + execSync(`cd ${tmp} && pnpm turbo gen core-package --args trpc`, { + stdio: "ignore", + }); + const result = computeSnapshot(join(tmp, "packages/core-trpc")); + expect(result).toEqual(expectedSnapshot); + }, + ); }); diff --git a/turbo/generators/__tests__/core-package-ui.e2e.test.ts b/turbo/generators/__tests__/core-package-ui.e2e.test.ts index ac85741..cc5ea61 100644 --- a/turbo/generators/__tests__/core-package-ui.e2e.test.ts +++ b/turbo/generators/__tests__/core-package-ui.e2e.test.ts @@ -1,5 +1,11 @@ -import { describe, it, expect } from "vitest"; -import { mkdtempSync, cpSync, readFileSync, writeFileSync } from "node:fs"; +import { describe, it, expect, onTestFinished } from "vitest"; +import { + mkdtempSync, + rmSync, + cpSync, + readFileSync, + writeFileSync, +} from "node:fs"; import { tmpdir } from "node:os"; import { execSync } from "node:child_process"; import { join, resolve } from "node:path"; @@ -8,7 +14,13 @@ import { computeSnapshot } from "../lib/snapshot.js"; import expectedSnapshot from "../__snapshots__/core-package/ui.snapshot.json" with { type: "json" }; // Repo root is 2 levels up from turbo/generators/__tests__ -const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".."); +const REPO_ROOT = resolve( + fileURLToPath(import.meta.url), + "..", + "..", + "..", + "..", +); /** * Strip "@repo/core-ui" from a package.json file in the tmp tree. @@ -19,7 +31,11 @@ const REPO_ROOT = resolve(fileURLToPath(import.meta.url), "..", "..", "..", ".." function stripCoreUiDep(pkgJsonPath: string): void { const raw = readFileSync(pkgJsonPath, "utf8"); const parsed = JSON.parse(raw) as Record>; - for (const section of ["dependencies", "devDependencies", "peerDependencies"] as const) { + for (const section of [ + "dependencies", + "devDependencies", + "peerDependencies", + ] as const) { if (parsed[section]?.["@repo/core-ui"]) { delete parsed[section]["@repo/core-ui"]; } @@ -28,25 +44,37 @@ function stripCoreUiDep(pkgJsonPath: string): void { } describe("e2e: core-package ui", () => { - it("byte-identical reconstruction matches snapshot", { timeout: 120_000 }, () => { - const tmp = mkdtempSync(join(tmpdir(), "e2e-ui-")); - cpSync(REPO_ROOT, tmp, { - recursive: true, - filter: (src) => - !src.includes("node_modules") && - !src.includes(".turbo") && - !src.includes("packages/core-ui"), - }); + it( + "byte-identical reconstruction matches snapshot", + { timeout: 120_000 }, + () => { + const tmp = mkdtempSync(join(tmpdir(), "e2e-ui-")); + // Each e2e run clones the repo into the OS temp dir; remove it 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") && + !src.includes("packages/core-ui"), + }); - // Strip @repo/core-ui from app package.json files so pnpm install - // succeeds without the package being present (simulating the post-removal state). - stripCoreUiDep(join(tmp, "apps", "web-next", "package.json")); - stripCoreUiDep(join(tmp, "apps", "web-tanstack", "package.json")); - stripCoreUiDep(join(tmp, "apps", "storybook", "package.json")); + // Strip @repo/core-ui from app package.json files so pnpm install + // succeeds without the package being present (simulating the post-removal state). + stripCoreUiDep(join(tmp, "apps", "web-next", "package.json")); + stripCoreUiDep(join(tmp, "apps", "web-tanstack", "package.json")); + stripCoreUiDep(join(tmp, "apps", "storybook", "package.json")); - execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { stdio: "ignore" }); - execSync(`cd ${tmp} && pnpm turbo gen core-package --args ui`, { stdio: "ignore" }); - const result = computeSnapshot(join(tmp, "packages/core-ui")); - expect(result).toEqual(expectedSnapshot); - }); + execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, { + stdio: "ignore", + }); + execSync(`cd ${tmp} && pnpm turbo gen core-package --args ui`, { + stdio: "ignore", + }); + const result = computeSnapshot(join(tmp, "packages/core-ui")); + expect(result).toEqual(expectedSnapshot); + }, + ); }); diff --git a/turbo/generators/vitest.config.ts b/turbo/generators/vitest.config.ts index f0ee9d4..d59d078 100644 --- a/turbo/generators/vitest.config.ts +++ b/turbo/generators/vitest.config.ts @@ -7,5 +7,10 @@ export default defineConfig({ include: ["*.test.ts", "lib/*.test.ts", "__tests__/*.test.ts"], clearMocks: true, restoreMocks: true, + // The core-package `*.e2e.test.ts` files each do a full `pnpm install` + // in a temp clone. Running them in parallel saturates the machine and + // trips vitest's worker RPC timeout ("Timeout calling onTaskUpdate"). + // Run test files one at a time so each e2e test gets the box to itself. + fileParallelism: false, }, });