import { describe, it, expect, vi, beforeEach } from "vitest"; const goto = vi.fn(); // Capture the afterNavigate callback so tests can simulate navigations and thus // drive the in-app depth counter that canGoBack/navigateBack rely on. let afterNavigateCb: ((nav: { from: unknown; to: unknown; delta?: number }) => void) | null = null; vi.mock("$app/navigation", () => ({ goto: (...args: unknown[]) => goto(...args), afterNavigate: (cb: (nav: any) => void) => { afterNavigateCb = cb; }, })); import { navigateUp, navigateBack, canGoBack, registerNavigationTracking, __resetNavigationDepthForTest, } from "./navigation"; /** Simulate a SvelteKit navigation to move the depth counter. */ function nav(opts: { from?: boolean; delta?: number }) { afterNavigateCb?.({ from: opts.from === false ? null : {}, to: {}, delta: opts.delta, }); } describe("navigation", () => { beforeEach(() => { goto.mockClear(); // registerNavigationTracking is idempotent; the first call in the suite wins // and wires afterNavigateCb. Ensure it is registered, then reset depth so // each case starts from the entry page (module state persists otherwise). registerNavigationTracking(); __resetNavigationDepthForTest(); }); describe("navigateUp", () => { it("always goes to the given parent path, never touching history", () => { const back = vi.fn(); vi.spyOn(history, "back").mockImplementation(back); navigateUp("/library/music"); expect(goto).toHaveBeenCalledWith("/library/music"); expect(back).not.toHaveBeenCalled(); }); }); describe("navigateBack / canGoBack", () => { it("falls back to the path when there is no in-app history yet", () => { // Fresh session: only the initial load happened (from == null), so depth // stays at 0 and there is nothing to pop. nav({ from: false }); expect(canGoBack()).toBe(false); const back = vi.fn(); vi.spyOn(history, "back").mockImplementation(back); navigateBack("/library"); expect(goto).toHaveBeenCalledWith("/library"); expect(back).not.toHaveBeenCalled(); }); it("pops history after a real in-app forward navigation", () => { nav({ from: false }); // initial load nav({}); // navigated deeper within the app expect(canGoBack()).toBe(true); const back = vi.fn(); vi.spyOn(history, "back").mockImplementation(back); navigateBack("/library"); expect(back).toHaveBeenCalledOnce(); expect(goto).not.toHaveBeenCalled(); }); it("does not go below zero when the user backs out to the entry page", () => { nav({ from: false }); // load nav({}); // forward → depth 1 nav({ delta: -1 }); // back → depth 0 nav({ delta: -1 }); // extra back (e.g. stale delta) must not underflow expect(canGoBack()).toBe(false); navigateBack("/library/music"); expect(goto).toHaveBeenCalledWith("/library/music"); }); }); });