* feat(channels): add guided setup flows * test(channels): preserve setup config values * fix(channels): reflect saved setup state * refactor(channels): simplify setup state metadata * fix(channels): harden setup lifecycle * refactor(channels): centralize setup contracts * fix(channels): route setup actions through webui shim * fix(channels): adapt settings for compact screens * fix(models): preserve default preset display * feat(models): add curated Codex catalog * fix(webui): stop attached gateway on interrupt * fix(webui): simplify apps catalog * docs(webui): clarify apps and runtime features * feat(settings): add guided capability setup * fix(webui): harden setup and managed services * test: keep managed runtime checks portable * test: scope POSIX runtime coverage * fix(webui): simplify file settings * feat(files): bundle document reading * fix(webui): harden setup request boundaries * fix(webui): prevent channel setup status squeeze * fix(settings): group provider compatibility aliases * refactor(settings): remove redundant setup surfaces * fix(webui): harden guided setup lifecycle * fix(webui): preserve channel setup compatibility
55 lines
1.6 KiB
TypeScript
55 lines
1.6 KiB
TypeScript
import { fireEvent, render, screen } from "@testing-library/react";
|
|
import { afterEach, describe, expect, it } from "vitest";
|
|
|
|
import {
|
|
__clearLogoFallbackCacheForTests,
|
|
useLogoFallback,
|
|
} from "@/hooks/useLogoFallback";
|
|
|
|
function TestLogo({ urls }: { urls: string[] }) {
|
|
const { logoUrl, onLogoError, onLogoLoad } = useLogoFallback(urls);
|
|
if (!logoUrl) return <span>No logo</span>;
|
|
return (
|
|
<img
|
|
src={logoUrl}
|
|
alt="Logo"
|
|
onLoad={onLogoLoad}
|
|
onError={onLogoError}
|
|
/>
|
|
);
|
|
}
|
|
|
|
describe("useLogoFallback", () => {
|
|
afterEach(() => {
|
|
__clearLogoFallbackCacheForTests();
|
|
});
|
|
|
|
it("remembers failed and loaded logo candidates across remounts", () => {
|
|
const urls = [
|
|
"https://bad.example/favicon.ico",
|
|
"https://good.example/favicon.ico",
|
|
];
|
|
const first = render(<TestLogo urls={urls} />);
|
|
|
|
expect(screen.getByRole("img", { name: "Logo" })).toHaveAttribute("src", urls[0]);
|
|
|
|
fireEvent.error(screen.getByRole("img", { name: "Logo" }));
|
|
expect(screen.getByRole("img", { name: "Logo" })).toHaveAttribute("src", urls[1]);
|
|
|
|
fireEvent.load(screen.getByRole("img", { name: "Logo" }));
|
|
first.unmount();
|
|
render(<TestLogo urls={urls} />);
|
|
|
|
expect(screen.getByRole("img", { name: "Logo" })).toHaveAttribute("src", urls[1]);
|
|
});
|
|
|
|
it("returns no logo once every candidate failed", () => {
|
|
const urls = ["https://bad.example/favicon.ico"];
|
|
render(<TestLogo urls={urls} />);
|
|
|
|
fireEvent.error(screen.getByRole("img", { name: "Logo" }));
|
|
|
|
expect(screen.getByText("No logo")).toBeInTheDocument();
|
|
});
|
|
});
|