Files
OmniRoute/tests/unit/ui/providerPageHighlightLogic.test.tsx
Jay Ongg 58ab8b1d2c Clicking a provider card hitting back loses scroll position (#8349)
* clicking a provider card hitting back loses scroll position

* clean up code

* Rename some funcitons

* minor UX updates

* add null-guard in highlight()

* Add providerCardHandle tests

* add highlight tests. refactored code into separate utility functions

* Minor change to skip a firstElementChild call - use a ref to access the Link inside ProviderCard.
2026-07-25 02:51:00 -03:00

130 lines
4.3 KiB
TypeScript

// @vitest-environment jsdom
/**
* Tests for the page-level highlighted-card matching/clearing logic
* extracted into providerPageHighlightUtils.ts.
*
* These import the real production functions — not copied code.
*/
import { afterEach, describe, expect, it, vi } from "vitest";
import type { ProviderCardHandle } from "@/app/(dashboard)/dashboard/providers/components/ProviderCard";
import {
recordProviderNavigation,
resolveHighlightedCard,
} from "@/app/(dashboard)/dashboard/providers/providerPageHighlightUtils";
function createMockHandle(
id: string,
callbacks?: { onScroll?(): void; onHighlight?(): void }
): ProviderCardHandle {
return {
getProviderId() {
return id;
},
scrollIntoView() {
callbacks?.onScroll?.();
},
highlight() {
callbacks?.onHighlight?.();
},
};
}
describe("resolveHighlightedCard", () => {
it("calls scrollIntoView + highlight when handle matches highlighted id", () => {
const onScroll = vi.fn();
const onHighlight = vi.fn();
const onAfterHighlight = vi.fn();
const handle = createMockHandle("openai", { onScroll, onHighlight });
resolveHighlightedCard(handle, "openai", onAfterHighlight);
expect(onScroll).toHaveBeenCalledTimes(1);
expect(onHighlight).toHaveBeenCalledTimes(1);
expect(onAfterHighlight).toHaveBeenCalledTimes(1);
});
it("does NOT call scrollIntoView or highlight when ids do not match", () => {
const onScroll = vi.fn();
const onHighlight = vi.fn();
const onAfterHighlight = vi.fn();
const handle = createMockHandle("openai", { onScroll, onHighlight });
resolveHighlightedCard(handle, "anthropic", onAfterHighlight);
expect(onScroll).not.toHaveBeenCalled();
expect(onHighlight).not.toHaveBeenCalled();
expect(onAfterHighlight).toHaveBeenCalledTimes(1);
});
it("calls onAfterHighlight even when handle is null", () => {
const onAfterHighlight = vi.fn();
resolveHighlightedCard(null, "openai", onAfterHighlight);
expect(onAfterHighlight).toHaveBeenCalledTimes(1);
});
it("calls onAfterHighlight even when ids do not match", () => {
const onAfterHighlight = vi.fn();
const handle = createMockHandle("kimi-coding");
resolveHighlightedCard(handle, "openai", onAfterHighlight);
expect(onAfterHighlight).toHaveBeenCalledTimes(1);
});
it("only the matching handle triggers scroll + highlight among multiple", () => {
const calls: string[] = [];
const onAfterHighlight = vi.fn();
const handles = [
createMockHandle("openai", {
onScroll: () => calls.push("openai-scroll"),
onHighlight: () => calls.push("openai-highlight"),
}),
createMockHandle("anthropic", {
onScroll: () => calls.push("anthropic-scroll"),
onHighlight: () => calls.push("anthropic-highlight"),
}),
createMockHandle("cursor", {
onScroll: () => calls.push("cursor-scroll"),
onHighlight: () => calls.push("cursor-highlight"),
}),
];
resolveHighlightedCard(handles[0], "cursor", onAfterHighlight);
resolveHighlightedCard(handles[1], "cursor", onAfterHighlight);
resolveHighlightedCard(handles[2], "cursor", onAfterHighlight);
expect(calls).toEqual(["cursor-scroll", "cursor-highlight"]);
expect(onAfterHighlight).toHaveBeenCalledTimes(3);
});
});
describe("recordProviderNavigation", () => {
const originalReplaceState = window.history.replaceState;
afterEach(() => {
window.history.replaceState = originalReplaceState;
});
it("calls history.replaceState with the provider id", () => {
const replaceSpy = vi.fn();
window.history.replaceState = replaceSpy;
recordProviderNavigation("openai");
expect(replaceSpy).toHaveBeenCalledTimes(1);
expect(replaceSpy).toHaveBeenCalledWith({ providerId: "openai" }, "");
});
it("sets different provider ids on successive calls", () => {
const replaceSpy = vi.fn();
window.history.replaceState = replaceSpy;
recordProviderNavigation("openai");
recordProviderNavigation("anthropic");
recordProviderNavigation("kimi-coding");
expect(replaceSpy).toHaveBeenCalledTimes(3);
expect(replaceSpy.mock.calls[0][0]).toEqual({ providerId: "openai" });
expect(replaceSpy.mock.calls[1][0]).toEqual({ providerId: "anthropic" });
expect(replaceSpy.mock.calls[2][0]).toEqual({ providerId: "kimi-coding" });
});
});