feat(webui): add guided setup flows
* 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
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user