fix(generators): run UI tests, guard optional bus, harden e2e clones
Three generator fixes:
- templates/feature/vitest.config.ts.hbs lacked an include for
.test.{ts,tsx}; the node base only includes .test.ts, so scaffolded
UI component tests never executed
- gen event consume emitted an unguarded bus.subscribe although
ctx.bus is optional in BindContext — now wrapped in if (bus) {}
- e2e repo clones now exclude /dist and /.next build outputs, and
every dep-stripping e2e strips the scaffolded package from EVERY
workspace package.json via globSync instead of a hardcoded dependent
list that drifts as packages gain or drop the dependency
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,10 @@ describe("e2e: core-package analytics", () => {
|
||||
!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") &&
|
||||
!src.includes("packages/core-analytics"),
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
mkdtempSync,
|
||||
rmSync,
|
||||
cpSync,
|
||||
globSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
@@ -58,12 +59,22 @@ describe("e2e: core-package audit", () => {
|
||||
!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") &&
|
||||
!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 EVERY workspace package.json so pnpm
|
||||
// install succeeds without the package being present (simulating the
|
||||
// post-removal state) — a hardcoded dependent list drifts as packages
|
||||
// gain or drop the dependency.
|
||||
for (const pkgJson of globSync(
|
||||
join(tmp, "{apps,packages}", "*", "package.json"),
|
||||
)) {
|
||||
stripCoreAuditDep(pkgJson);
|
||||
}
|
||||
|
||||
execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, {
|
||||
stdio: "ignore",
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
mkdtempSync,
|
||||
rmSync,
|
||||
cpSync,
|
||||
globSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
@@ -58,13 +59,22 @@ describe("e2e: core-package consent", () => {
|
||||
!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") &&
|
||||
!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"));
|
||||
// Strip @repo/core-consent from EVERY workspace package.json so pnpm
|
||||
// install succeeds without the package being present (simulating the
|
||||
// post-removal state) — a hardcoded dependent list drifts as packages
|
||||
// gain or drop the dependency.
|
||||
for (const pkgJson of globSync(
|
||||
join(tmp, "{apps,packages}", "*", "package.json"),
|
||||
)) {
|
||||
stripCoreConsentDep(pkgJson);
|
||||
}
|
||||
|
||||
execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, {
|
||||
stdio: "ignore",
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
mkdtempSync,
|
||||
rmSync,
|
||||
cpSync,
|
||||
globSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
@@ -58,12 +59,22 @@ describe("e2e: core-package dsr", () => {
|
||||
!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") &&
|
||||
!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"));
|
||||
// Strip @repo/core-dsr from EVERY workspace package.json so pnpm
|
||||
// install succeeds without the package being present (simulating the
|
||||
// post-removal state) — a hardcoded dependent list drifts as packages
|
||||
// gain or drop the dependency.
|
||||
for (const pkgJson of globSync(
|
||||
join(tmp, "{apps,packages}", "*", "package.json"),
|
||||
)) {
|
||||
stripCoreDsrDep(pkgJson);
|
||||
}
|
||||
|
||||
execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, {
|
||||
stdio: "ignore",
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
mkdtempSync,
|
||||
rmSync,
|
||||
cpSync,
|
||||
globSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
@@ -58,24 +59,22 @@ describe("e2e: core-package events", () => {
|
||||
!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") &&
|
||||
!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");
|
||||
// Strip @repo/core-events from EVERY workspace package.json so pnpm
|
||||
// install succeeds without the package being present (simulating the
|
||||
// post-removal state) — a hardcoded dependent list drifts as packages
|
||||
// gain or drop the dependency.
|
||||
for (const pkgJson of globSync(
|
||||
join(tmp, "{apps,packages}", "*", "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",
|
||||
|
||||
@@ -31,6 +31,10 @@ describe("e2e: core-package realtime", () => {
|
||||
!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") &&
|
||||
!src.includes("packages/core-realtime"),
|
||||
});
|
||||
execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, {
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
mkdtempSync,
|
||||
rmSync,
|
||||
cpSync,
|
||||
globSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
@@ -58,21 +59,21 @@ describe("e2e: core-package trpc", () => {
|
||||
!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") &&
|
||||
!src.includes("packages/core-trpc"),
|
||||
});
|
||||
|
||||
// Strip @repo/core-trpc from every package that references it so pnpm
|
||||
// Strip @repo/core-trpc from EVERY workspace package.json so pnpm
|
||||
// install succeeds without the package being present (simulating the
|
||||
// post-removal state). Apps list it directly; the blog, marketing-pages,
|
||||
// and navigation features depend on it for their ./ui tRPC hooks.
|
||||
for (const pkgDir of [
|
||||
["apps", "web-next"],
|
||||
["apps", "web-tanstack"],
|
||||
["packages", "blog"],
|
||||
["packages", "marketing-pages"],
|
||||
["packages", "navigation"],
|
||||
]) {
|
||||
stripCoreTrpcDep(join(tmp, ...pkgDir, "package.json"));
|
||||
// post-removal state) — a hardcoded dependent list drifts as packages
|
||||
// gain or drop the dependency.
|
||||
for (const pkgJson of globSync(
|
||||
join(tmp, "{apps,packages}", "*", "package.json"),
|
||||
)) {
|
||||
stripCoreTrpcDep(pkgJson);
|
||||
}
|
||||
|
||||
execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, {
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
mkdtempSync,
|
||||
rmSync,
|
||||
cpSync,
|
||||
globSync,
|
||||
readFileSync,
|
||||
writeFileSync,
|
||||
} from "node:fs";
|
||||
@@ -58,14 +59,22 @@ describe("e2e: core-package ui", () => {
|
||||
!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") &&
|
||||
!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 EVERY workspace package.json so pnpm
|
||||
// install succeeds without the package being present (simulating the
|
||||
// post-removal state) — a hardcoded dependent list drifts as packages
|
||||
// gain or drop the dependency.
|
||||
for (const pkgJson of globSync(
|
||||
join(tmp, "{apps,packages}", "*", "package.json"),
|
||||
)) {
|
||||
stripCoreUiDep(pkgJson);
|
||||
}
|
||||
|
||||
execSync(`cd ${tmp} && pnpm install --frozen-lockfile=false`, {
|
||||
stdio: "ignore",
|
||||
|
||||
@@ -38,7 +38,11 @@ describe("e2e: feature generator composition", () => {
|
||||
filter: (src) =>
|
||||
!src.includes("node_modules") &&
|
||||
!src.includes(".turbo") &&
|
||||
!src.includes(".pnpm-store"),
|
||||
!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`, {
|
||||
|
||||
@@ -1300,7 +1300,10 @@ function handlerBindBlock(a: {
|
||||
${containerVar}.unbind(${handlerSymbol});
|
||||
}
|
||||
${containerVar}.bind(${handlerSymbol}).toConstantValue(${wrappedVar});
|
||||
bus.subscribe(${eventConst}, "${a.feature}", ${wrappedVar});`;
|
||||
// ctx.bus is an OPTIONAL core (guard per CLAUDE.md binder conventions).
|
||||
if (bus) {
|
||||
bus.subscribe(${eventConst}, "${a.feature}", ${wrappedVar});
|
||||
}`;
|
||||
}
|
||||
|
||||
function printConsumeNextSteps(a: {
|
||||
|
||||
@@ -12,6 +12,9 @@ import {
|
||||
// manifest when adjusting per-feature bands.
|
||||
export default mergeConfig(nodeVitestConfig, {
|
||||
test: {
|
||||
// The node base only includes .test.ts; UI tests are .test.tsx files
|
||||
// that opt into jsdom per-file via the @vitest-environment docblock.
|
||||
include: ["src/**/*.test.{ts,tsx}"],
|
||||
coverage: {
|
||||
exclude: [
|
||||
// DI bootstrap — wires InversifyJS at app startup; not unit-testable
|
||||
|
||||
Reference in New Issue
Block a user