import { readFileSync } from "node:fs"; import { resolve } from "node:path"; import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, it, vi } from "vitest"; import type { HousekeepingSurface } from "../contracts"; import type { HousekeepingNavigationDomain } from "../navigation"; import { HousekeepingShell } from "./housekeeping-shell"; vi.mock("@/actions/housekeeping-search", () => ({ executeHousekeepingSearch: vi.fn(), })); const labels = { skipToContent: "Skip to housekeeping content", primaryNavigation: "Primary housekeeping navigation", contextualNavigation: "Operations navigation", command: "Search housekeeping", preview: "Preview", backToSite: "Back to site", operatorRank: "Rank 6", commandDeck: { placeholder: "Search navigation, commands, and entities", navigation: "Navigation", commands: "Commands", entities: "Entities", loading: "Searching…", empty: "No results", partial: "Some providers are unavailable", close: "Close", }, }; const domains: readonly HousekeepingNavigationDomain[] = [ { id: "operations", href: "/ase-next/operations", iconId: "inbox", label: "Operations", description: "Manage operations", items: [ { id: "queue", href: "/ase-next/operations/queue", label: "Queue" }, ], }, { id: "people", href: "/ase-next/people", iconId: "users", label: "People", description: "Manage people", items: [], }, { id: "content", href: "/ase-next/content", iconId: "file-text", label: "Content", description: "Manage content", items: [], }, { id: "economy", href: "/ase-next/economy", iconId: "gem", label: "Economy", description: "Manage economy", items: [], }, { id: "hotel", href: "/ase-next/hotel", iconId: "hotel", label: "Hotel", description: "Manage hotel", items: [], }, { id: "system", href: "/ase-next/system", iconId: "settings", label: "System", description: "Manage system", items: [], }, ]; const taskFiles = [ "src/features/housekeeping/foundation/shell/housekeeping-shell.tsx", "src/features/housekeeping/foundation/shell/domain-rail.tsx", "src/features/housekeeping/foundation/shell/context-nav.tsx", "src/features/housekeeping/foundation/shell/command-trigger.tsx", "src/features/housekeeping/foundation/shell/operator-summary.tsx", "src/features/housekeeping/foundation/page/housekeeping-page-shell.tsx", "src/features/housekeeping/foundation/page/housekeeping-page-state.tsx", "src/features/housekeeping/foundation/shell/housekeeping-shell.test.tsx", "src/features/housekeeping/foundation/page/housekeeping-page-state.test.tsx", ] as const; const componentTaskFiles = taskFiles.slice(0, 7); const structuralBoundaryRules = [ { label: "client directive", pattern: new RegExp("use " + "client") }, { label: "palette color", pattern: /(?:bg|text|border|from|via|to|ring|outline|fill|stroke|divide|shadow|accent|caret|decoration|placeholder)-(?:white|black|slate|gray|zinc|neutral|stone|red|orange|amber|yellow|lime|green|emerald|teal|cyan|sky|blue|indigo|violet|purple|fuchsia|pink|rose)(?:-\d{2,3})?/, }, { label: "hex color", pattern: new RegExp("#" + "[0-9a-fA-F]{3,8}") }, { label: "rgb or hsl color", pattern: new RegExp("(?:r" + "gb|h" + "sl)\\("), }, ]; const componentBoundaryRules = [ { label: "React hook", pattern: /\b(?:React\.)?use[A-Z]\w*(?:\s*\(|\s*(?:as|,|}))/, }, { label: "click handler", pattern: /\bonClick\s*=/ }, { label: "keyboard handler", pattern: /\bonKey(?:Down|Up|Press)\s*=/ }, { label: "executable JSX event prop", pattern: /\bon[A-Z]\w*\s*=/ }, { label: "event listener", pattern: new RegExp("addEvent" + "Listener") }, { label: "inline literal color", pattern: /\bstyle\s*=\s*\{\{[^}]*\b(?:color|background(?:Color)?|borderColor|fill|stroke)\s*:\s*["'](?!var\(--admin-[^)]+\))[^"']+["']/, }, { label: "database or action import", pattern: new RegExp( "(?:from\\s*|import\\s*\\()\\s*['\"][^'\"]*(?:@/lib/" + "db|drizzle(?:-orm)?|/" + "actions?)[^'\"]*['\"]", ), }, { label: "command package", pattern: new RegExp("cmd" + "k", "i") }, { label: "localization import", pattern: new RegExp("next" + "-intl") }, { label: "search or mutation runtime", pattern: /\b(?:fetch|useQuery|useMutation)\s*\(/, }, { label: "persistence storage", pattern: /\b(?:localStorage|sessionStorage|indexedDB)\b|\.(?:setItem|getItem|removeItem)\s*\(/, }, ]; function renderShell( activeDomainId: HousekeepingNavigationDomain["id"] = "operations", availableDomains: readonly HousekeepingNavigationDomain[] = domains, surface: HousekeepingSurface = "preview", ): string { return renderToStaticMarkup(

Deck body

, ); } function anchors(html: string): readonly string[] { return html.match(/]*>/g) ?? []; } function anchorForHref(html: string, href: string): string { const anchor = anchors(html).find((candidate) => candidate.includes(`href="${href}"`), ); if (!anchor) throw new Error(`missing anchor for ${href}`); return anchor; } function boundaryViolations( source: string, rules: readonly { label: string; pattern: RegExp }[], ): readonly string[] { return rules .filter((rule) => rule.pattern.test(source)) .map((rule) => rule.label); } describe("HousekeepingShell", () => { it("renders the accessible command deck landmarks and supplied shell content", () => { const html = renderShell(); expect(html).toContain('href="#housekeeping-content"'); expect(html).toContain(">Skip to housekeeping content<"); expect(html).toContain("Deck body

"); expect(html).toContain('href="/ase-next/operations/queue"'); expect(html).toContain(">Queue<"); expect(html).toContain(">Nora<"); expect(html).toContain(">6<"); expect(html).toContain(">Preview<"); expect(html).toContain('href="/"'); expect(html).toContain(">Back to site<"); expect(html).toContain('aria-haspopup="dialog"'); expect(html).toContain(">Search housekeeping<"); expect(html).not.toContain('disabled=""'); }); it("maps all six authorized icons and exactly one active domain", () => { const html = renderShell("people"); const allAnchors = anchors(html); const activeAnchors = allAnchors.filter((anchor) => anchor.includes('aria-current="page"'), ); const peopleAnchor = anchorForHref(html, "/ase-next/people"); for (const iconClass of [ "lucide-inbox", "lucide-users", "lucide-file-text", "lucide-gem", "lucide-hotel", "lucide-settings", ]) { expect(html).toContain(`class="lucide ${iconClass}"`); } expect(activeAnchors).toHaveLength(1); expect(peopleAnchor).toContain('aria-current="page"'); for (const anchor of allAnchors.filter( (anchor) => anchor !== peopleAnchor, )) { expect(anchor).not.toContain('aria-current="page"'); } }); it("only marks the preview surface as preview", () => { expect(renderShell()).toContain(">Preview<"); expect(renderShell("operations", domains, "canonical")).not.toContain( ">Preview<", ); }); it("does not throw or render contextual items when a valid active domain is absent", () => { const domainsWithoutSystem = domains.filter( (domain) => domain.id !== "system", ); expect(() => renderShell("system", domainsWithoutSystem)).not.toThrow(); const html = renderShell("system", domainsWithoutSystem); expect(html).not.toContain('href="/ase-next/operations/queue"'); expect(html).not.toContain(">Queue<"); }); it("keeps Task 10 modules within the server-rendered source boundary", () => { for (const path of taskFiles) { const source = readFileSync(resolve(process.cwd(), path), "utf8"); expect(boundaryViolations(source, structuralBoundaryRules)).toEqual([]); } for (const path of componentTaskFiles) { const source = readFileSync(resolve(process.cwd(), path), "utf8"); expect(boundaryViolations(source, componentBoundaryRules)).toEqual([]); } }); it("detects representative prohibited source mutations", () => { const componentMutations = [ ["React hook", 'import { useState } from "react";'], ["click handler", "