import { describe, expect, it } from "vitest"; import { type ModuleUiHostContext, type ModuleUiNavigation, ModuleUiNavigationError, } from "../src/index.js"; /** The navigation capability's public surface (ADR 0063). Its behaviour is the host's: the * Dashboard's implementation is proven in `surfaces/shell/tests/module-navigation.test.tsx`. */ describe("module UI navigation contract", () => { it("reports a refused path with a stable code and a fixed message that never echoes the path", () => { for (const code of [ "MODULE_NAVIGATION_PATH_INVALID", "MODULE_NAVIGATION_PATH_UNKNOWN", ] as const) { const error = new ModuleUiNavigationError(code); expect(error).toBeInstanceOf(Error); expect(error.name).toBe("ModuleUiNavigationError"); expect(error.code).toBe(code); expect(error.stack).toBe(`ModuleUiNavigationError: ${error.message}`); expect(error.message).not.toMatch(/[/:?#]/u); } }); it("makes navigation a context member a host without pages leaves undefined", () => { // A type-level contract: a context may say it has no navigation, as the display host does, and // a module reads it through an optional check. const describe = (context: Pick): string => context.navigation?.location().path ?? "no navigation"; const navigation: ModuleUiNavigation = { link: () => ({ href: "/m/x", onClick: () => undefined }), location: () => ({ page: "x", path: "x" }), navigate: () => undefined, settings: undefined, subscribe: () => () => undefined, }; expect(describe({ navigation: undefined })).toBe("no navigation"); expect(describe({ navigation })).toBe("x"); }); });