import { describe, it } from "vitest"; import { RuleTester } from "eslint"; import path from "node:path"; import os from "node:os"; import fs from "node:fs"; import rule from "./feature-must-have-manifest.js"; function makeFeatureFixture({ withManifest }) { const repoRoot = fs.mkdtempSync(path.join(os.tmpdir(), "fmm-")); const featureDir = path.join(repoRoot, "packages", "demo"); fs.mkdirSync(path.join(featureDir, "src", "application", "use-cases"), { recursive: true }); if (withManifest) { fs.writeFileSync( path.join(featureDir, "src", "feature.manifest.ts"), `export const demoManifest = defineFeature({ name: "demo", requiredCores: [], useCases: {}, realtimeChannels: [], jobs: [] } as const);`, ); } const useCaseFile = path.join(featureDir, "src", "application", "use-cases", "do-thing.use-case.ts"); fs.writeFileSync(useCaseFile, `export const doThingUseCase = () => async () => {};`); return { repoRoot, useCaseFile }; } const tester = new RuleTester({ languageOptions: { ecmaVersion: "latest", sourceType: "module" } }); describe("feature-must-have-manifest", () => { it("passes when the feature has a manifest", () => { const { repoRoot, useCaseFile } = makeFeatureFixture({ withManifest: true }); tester.run("feature-must-have-manifest", rule, { valid: [ { filename: useCaseFile, code: fs.readFileSync(useCaseFile, "utf8"), options: [{ repoRoot }], }, ], invalid: [], }); }); it("fires when the feature has no manifest", () => { const { repoRoot, useCaseFile } = makeFeatureFixture({ withManifest: false }); tester.run("feature-must-have-manifest", rule, { valid: [], invalid: [ { filename: useCaseFile, code: fs.readFileSync(useCaseFile, "utf8"), options: [{ repoRoot }], errors: [{ messageId: "missingManifest" }], }, ], }); }); });