import { describe, it, expect } from "vitest"; import { resolveArea, type Topology } from "./resolve-area.js"; // Mirrors apps/cloud/docs/examples/fragments.config.example.ts, normalized to // the array shape the architecture doc locks in. function makeTopology(overrides?: Partial): Topology { return { version: 1, areas: [ { id: "checkout", name: "Checkout", criticality: "revenue", owners: ["checkout-platform"], files: ["src/app/checkout/**", "src/features/checkout/**", "src/app/payment/**"], routes: ["/checkout/**"], }, { id: "dashboard", name: "Dashboard", criticality: "high", owners: ["dashboard-platform"], files: ["src/app/dashboard/**"], }, { id: "marketing", name: "Marketing", criticality: "medium", owners: ["growth"], files: ["src/app/(marketing)/**", "src/pages/{index,pricing}.tsx"], }, ], ...overrides, }; } describe("resolveArea", () => { it("matches a file to its area and records the winning glob", () => { const match = resolveArea("src/app/checkout/page.tsx", makeTopology()); expect(match).toEqual({ areaId: "checkout", areaName: "Checkout", criticality: "revenue", owners: ["checkout-platform"], matchedGlob: "src/app/checkout/**", }); }); it("matches nested files under a globstar", () => { const match = resolveArea("src/features/checkout/cart/Total.tsx", makeTopology()); expect(match?.areaId).toBe("checkout"); expect(match?.matchedGlob).toBe("src/features/checkout/**"); }); it("returns null for an unmatched path (becomes Unassigned downstream)", () => { expect(resolveArea("src/lib/utils.ts", makeTopology())).toBeNull(); }); it("treats Next.js route-group parens as literal path segments", () => { const match = resolveArea("src/app/(marketing)/home.tsx", makeTopology()); expect(match?.areaId).toBe("marketing"); // The parens must not behave like a regex/extglob group. expect(resolveArea("src/app/marketing/home.tsx", makeTopology())).toBeNull(); }); it("expands brace alternation", () => { const topology = makeTopology(); expect(resolveArea("src/pages/index.tsx", topology)?.areaId).toBe("marketing"); expect(resolveArea("src/pages/pricing.tsx", topology)?.areaId).toBe("marketing"); // The literal dot must not act as a wildcard. expect(resolveArea("src/pages/indexXtsx", topology)).toBeNull(); }); it("matches a single `*` within one segment only (no slash crossing)", () => { const topology: Topology = { version: 1, areas: [ { id: "features", name: "Features", criticality: "medium", owners: [], files: ["src/features/*/index.ts"], }, ], }; expect(resolveArea("src/features/billing/index.ts", topology)?.areaId).toBe("features"); // `*` is single-segment, so a nested path must not match. expect(resolveArea("src/features/billing/nested/index.ts", topology)).toBeNull(); }); it("uses first-match by declaration order when priorities are equal", () => { const topology: Topology = { version: 1, areas: [ { id: "first", name: "First", criticality: "low", owners: [], files: ["src/**"] }, { id: "second", name: "Second", criticality: "low", owners: [], files: ["src/app/**"] }, ], }; expect(resolveArea("src/app/x.tsx", topology)?.areaId).toBe("first"); }); it("honors priority as a tie-break (higher wins regardless of order)", () => { const topology: Topology = { version: 1, areas: [ { id: "broad", name: "Broad", criticality: "low", owners: [], files: ["src/**"] }, { id: "specific", name: "Specific", criticality: "high", owners: [], files: ["src/app/**"], priority: 10, }, ], }; expect(resolveArea("src/app/x.tsx", topology)?.areaId).toBe("specific"); }); it("normalizes Windows separators and leading ./ before matching", () => { const topology = makeTopology(); expect(resolveArea("src\\app\\checkout\\page.tsx", topology)?.areaId).toBe("checkout"); expect(resolveArea("./src/app/checkout/page.tsx", topology)?.areaId).toBe("checkout"); }); it("matches an area's own root directory path, not just descendants", () => { const topology = makeTopology(); // `src/app/checkout/**` should match the directory itself, not only files // under it (picomatch `a/**` semantics). expect(resolveArea("src/app/checkout", topology)?.areaId).toBe("checkout"); expect(resolveArea("src/app/checkout/page.tsx", topology)?.areaId).toBe("checkout"); }); it("matches a mid-path globstar against zero or more segments", () => { const topology: Topology = { version: 1, areas: [ { id: "api", name: "API", criticality: "high", owners: [], files: ["src/**/route.ts"] }, ], }; expect(resolveArea("src/route.ts", topology)?.areaId).toBe("api"); expect(resolveArea("src/app/api/route.ts", topology)?.areaId).toBe("api"); }); it("never throws on a malformed glob — the bad glob is skipped, not the scan", () => { const topology: Topology = { version: 1, areas: [ { id: "broken", name: "Broken", criticality: "low", owners: [], // Unbalanced brace → invalid RegExp. Must not abort resolution. files: ["src/{a,b/x.ts", "src/good/**"], }, ], }; expect(() => resolveArea("src/whatever.ts", topology)).not.toThrow(); // The malformed glob is skipped; the valid sibling still matches. expect(resolveArea("src/good/file.ts", topology)?.areaId).toBe("broken"); // A path only the broken glob could have matched falls through to null. expect(resolveArea("src/a", topology)).toBeNull(); }); it("returns the same result across repeated calls (cache correctness)", () => { const topology = makeTopology(); const a = resolveArea("src/app/dashboard/Home.tsx", topology); const b = resolveArea("src/app/dashboard/Home.tsx", topology); expect(a).toEqual(b); expect(a?.areaId).toBe("dashboard"); }); });