mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-03 13:52:09 +03:00
* chore(auth): condense #8407 note in tokenHealthCheck to fit frozen file-size baseline The 3-line comment added by #8426 pushed tokenHealthCheck.ts to 843 LOC, 2 over its frozen baseline of 841 (base-red on release/v3.8.49). Fold the devin-cli rationale into one line — same meaning, gate green again. * refactor(dashboard): extract provider card highlight into HighlightableProviderCard #8349 left the back-navigation highlight concern inline in providers/page.tsx (state + two callbacks + onCardClick/ref props repeated at 18 card call sites), pushing the page to 1990 LOC over its frozen baseline of 1927. Move the concern into a HighlightableProviderCard wrapper: each card instance keeps its own copy of the highlighted id and only the card whose provider id matches scrolls into view and highlights — same semantics as the single page-level state, since resolveHighlightedCard already gates on the id match. page.tsx drops to 1917 LOC (under the frozen baseline, no rebaseline needed). * test(dashboard): cover HighlightableProviderCard wiring Direct coverage for the wrapper extracted in the previous refactor: mount-time scroll+highlight only when history.state.providerId matches, no reaction on mismatch/null state, isolation across multiple card instances, and click-time navigation recording via history.replaceState. Note: the jsdom scrollIntoView shim is a plain no-op rather than a vi.fn() — vi.restoreAllMocks() would otherwise restore the shared mock and let the next test's spy inherit its accumulated call count.
146 lines
4.9 KiB
TypeScript
146 lines
4.9 KiB
TypeScript
// @vitest-environment jsdom
|
|
/**
|
|
* HighlightableProviderCard — the wrapper owning the back-navigation
|
|
* highlight concern: per-instance highlighted-id state initialized from
|
|
* history.state, ref wiring into ProviderCard's imperative handle, and
|
|
* click-time navigation recording.
|
|
*
|
|
* Complements providerPageHighlightLogic.test.tsx (pure utils) and
|
|
* providerCardHandle.test.tsx (imperative handle) by covering the wiring
|
|
* between them.
|
|
*/
|
|
import React from "react";
|
|
import { createRoot } from "react-dom/client";
|
|
import { act } from "react";
|
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
import HighlightableProviderCard from "@/app/(dashboard)/dashboard/providers/components/HighlightableProviderCard";
|
|
|
|
vi.mock("next-intl", () => ({ useTranslations: () => (k: string) => k }));
|
|
vi.mock("@/shared/components/ProviderTestSlideOver", () => ({ default: () => null }));
|
|
vi.mock("@/shared/components/ProviderIcon", () => ({ default: () => null }));
|
|
// Deterministic anchor so the click path does not depend on next/link's router.
|
|
vi.mock("next/link", () => ({
|
|
__esModule: true,
|
|
default: React.forwardRef(function MockLink(
|
|
{ href, children, ...rest }: { href: string; children: React.ReactNode },
|
|
ref: React.Ref<HTMLAnchorElement>
|
|
) {
|
|
return (
|
|
<a href={href} ref={ref} {...rest}>
|
|
{children}
|
|
</a>
|
|
);
|
|
}),
|
|
}));
|
|
|
|
// jsdom does not implement scrollIntoView or animate. Plain no-ops (not
|
|
// vi.fn()) so per-test vi.spyOn never inherits call history through
|
|
// vi.restoreAllMocks() restoring a shared mock.
|
|
if (typeof Element.prototype.scrollIntoView === "undefined") {
|
|
Object.defineProperty(Element.prototype, "scrollIntoView", {
|
|
value: () => {},
|
|
writable: true,
|
|
configurable: true,
|
|
});
|
|
}
|
|
if (typeof Element.prototype.animate === "undefined") {
|
|
Object.defineProperty(Element.prototype, "animate", {
|
|
value: () => ({ cancel: () => {}, finished: Promise.resolve() }),
|
|
writable: true,
|
|
configurable: true,
|
|
});
|
|
}
|
|
|
|
function renderCards(...providerIds: string[]) {
|
|
const container = document.createElement("div");
|
|
document.body.appendChild(container);
|
|
const root = createRoot(container);
|
|
act(() => {
|
|
root.render(
|
|
<>
|
|
{providerIds.map((id) => (
|
|
<HighlightableProviderCard
|
|
key={id}
|
|
providerId={id}
|
|
provider={{ id, name: id }}
|
|
stats={{ total: 1, connected: 1, error: 0, warning: 0 }}
|
|
authType="apikey"
|
|
onToggle={() => {}}
|
|
/>
|
|
))}
|
|
</>
|
|
);
|
|
});
|
|
return container;
|
|
}
|
|
|
|
describe("HighlightableProviderCard", () => {
|
|
let container: HTMLDivElement | null = null;
|
|
|
|
afterEach(() => {
|
|
vi.restoreAllMocks();
|
|
window.history.replaceState(null, "");
|
|
if (container) {
|
|
document.body.removeChild(container);
|
|
container = null;
|
|
}
|
|
});
|
|
|
|
it("scrolls and highlights on mount when history.state.providerId matches", () => {
|
|
window.history.replaceState({ providerId: "openai" }, "");
|
|
const scrollSpy = vi.spyOn(Element.prototype, "scrollIntoView");
|
|
const animateSpy = vi.spyOn(Element.prototype, "animate");
|
|
|
|
container = renderCards("openai");
|
|
|
|
expect(scrollSpy).toHaveBeenCalledTimes(1);
|
|
expect(scrollSpy).toHaveBeenCalledWith({ behavior: "auto", block: "center" });
|
|
expect(animateSpy).toHaveBeenCalled();
|
|
});
|
|
|
|
it("does not scroll or highlight when history.state holds a different provider id", () => {
|
|
window.history.replaceState({ providerId: "anthropic" }, "");
|
|
const scrollSpy = vi.spyOn(Element.prototype, "scrollIntoView");
|
|
const animateSpy = vi.spyOn(Element.prototype, "animate");
|
|
|
|
container = renderCards("openai");
|
|
|
|
expect(scrollSpy).not.toHaveBeenCalled();
|
|
expect(animateSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("does nothing when history.state is null", () => {
|
|
const scrollSpy = vi.spyOn(Element.prototype, "scrollIntoView");
|
|
const animateSpy = vi.spyOn(Element.prototype, "animate");
|
|
|
|
container = renderCards("openai");
|
|
|
|
expect(scrollSpy).not.toHaveBeenCalled();
|
|
expect(animateSpy).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("among several cards only the one matching history.state.providerId reacts", () => {
|
|
window.history.replaceState({ providerId: "cursor" }, "");
|
|
const scrollSpy = vi.spyOn(Element.prototype, "scrollIntoView");
|
|
const animateSpy = vi.spyOn(Element.prototype, "animate");
|
|
|
|
container = renderCards("openai", "cursor", "kimi-coding");
|
|
|
|
expect(scrollSpy).toHaveBeenCalledTimes(1);
|
|
expect(animateSpy).toHaveBeenCalledTimes(1);
|
|
});
|
|
|
|
it("records the clicked provider id into history.state", () => {
|
|
const replaceSpy = vi.spyOn(window.history, "replaceState");
|
|
container = renderCards("openai");
|
|
const link = container.querySelector("a");
|
|
expect(link).not.toBeNull();
|
|
|
|
act(() => {
|
|
link!.dispatchEvent(new MouseEvent("click", { bubbles: true, cancelable: true }));
|
|
});
|
|
|
|
expect(replaceSpy).toHaveBeenCalledWith({ providerId: "openai" }, "");
|
|
});
|
|
});
|