import { describe, it, expect, vi, beforeEach } from "vitest";
import { render } from "@testing-library/react";
// Mutable pathname + a spy for the shared capture helper. The tracker reads
// usePathname() and forwards it to capturePageview; section-normalization and
// dedup live in @multica/core/analytics and are unit-tested there, so here we
// only assert the wiring (which path is forwarded, and that the query string
// never re-triggers the effect).
const { state, capturePageview } = vi.hoisted(() => ({
state: { pathname: "/" as string | null },
capturePageview: vi.fn<(path?: string) => void>(),
}));
vi.mock("next/navigation", () => ({
usePathname: () => state.pathname,
}));
vi.mock("@multica/core/analytics", () => ({
capturePageview,
}));
import { PageviewTracker } from "./pageview-tracker";
beforeEach(() => {
state.pathname = "/";
capturePageview.mockClear();
});
describe("web PageviewTracker", () => {
it("captures the pathname on mount and on each pathname change", () => {
const { rerender } = render();
expect(capturePageview).toHaveBeenCalledTimes(1);
expect(capturePageview).toHaveBeenLastCalledWith("/");
state.pathname = "/acme/issues";
rerender();
expect(capturePageview).toHaveBeenCalledTimes(2);
expect(capturePageview).toHaveBeenLastCalledWith("/acme/issues");
});
it("does not re-capture on a query-string-only navigation", () => {
state.pathname = "/acme/issues";
const { rerender } = render();
expect(capturePageview).toHaveBeenCalledTimes(1);
// A filter/sort/search change alters only the query string, which the
// tracker no longer reads — usePathname() is unchanged so the effect's
// dependency does not change and no new pageview fires.
rerender();
expect(capturePageview).toHaveBeenCalledTimes(1);
});
});