| ... | @@ -1,51 +1,43 @@ | ... | @@ -1,51 +1,43 @@ |
| 1 | import { EnvironmentId, ThreadId } from "@t3tools/contracts"; | 1 | import { act } from "react"; |
| 2 | import { renderToStaticMarkup } from "react-dom/server"; | 2 | import { create, type ReactTestRenderer } from "react-test-renderer"; |
| 3 | import { describe, expect, it, vi } from "vite-plus/test"; | 3 | import { afterEach, expect, it, vi } from "vite-plus/test"; |
| 4 | | 4 | |
| 5 | const mocks = vi.hoisted(() => ({ favicon: null as string | null })); | 5 | vi.mock("~/browserFaviconStore", () => ({ useFaviconForThreadUrl: () => null })); |
| 6 | | 6 | |
| 7 | vi.mock("~/browserFaviconStore", () => ({ | 7 | import { FaviconImage } from "./PreviewFaviconIcon"; |
| 8 | useFaviconForThreadUrl: () => mocks.favicon, | 8 | |
| 9 | })); | 9 | let renderer: ReactTestRenderer | undefined; |
| 10 | | 10 | |
| 11 | import { FaviconImage, PreviewFaviconIcon, selectFaviconSource } from "./PreviewFaviconIcon"; | 11 | afterEach(async () => { |
| 12 | | 12 | await act(async () => renderer?.unmount()); |
| 13 | const threadRef = { | 13 | vi.unstubAllGlobals(); |
| 14 | environmentId: EnvironmentId.make("env-1"), | 14 | }); |
| 15 | threadId: ThreadId.make("thread-1"), | 15 | |
| 16 | }; | 16 | it("falls through failed favicon sources and retries when the source list changes", async () => { |
| 17 | | 17 | vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true); |
| 18 | describe("preview favicon image", () => { | 18 | const captured = "data:image/png;base64,AAAA"; |
| 19 | it("renders a captured source before later fallback sources", () => { | 19 | const remote = "https://public.example/icon"; |
| 20 | expect( | 20 | await act(async () => { |
| 21 | renderToStaticMarkup( | 21 | renderer = create( |
| 22 | <FaviconImage | 22 | <FaviconImage sources={[captured, remote]} fallback={<span>fallback</span>} />, |
| 23 | sources={["data:image/png;base64,AAAA", "https://public.example/icon"]} | | |
| 24 | fallback={<span>fallback</span>} | | |
| 25 | />, | | |
| 26 | ), | | |
| 27 | ).toContain('src="data:image/png;base64,AAAA"'); | | |
| 28 | const captured = "data:image/png;base64,AAAA"; | | |
| 29 | const google = "https://public.example/icon"; | | |
| 30 | expect(selectFaviconSource([captured, google], new Set())).toBe(captured); | | |
| 31 | expect(selectFaviconSource([captured, google], new Set([captured]))).toBe(google); | | |
| 32 | expect(selectFaviconSource([captured, google], new Set([captured, google]))).toBeNull(); | | |
| 33 | expect(selectFaviconSource(["data:image/png;base64,BBBB", google], new Set([captured]))).toBe( | | |
| 34 | "data:image/png;base64,BBBB", | | |
| 35 | ); | 23 | ); |
| 36 | }); | 24 | }); |
| | 25 | expect(renderer!.root.findByType("img").props.src).toBe(captured); |
| 37 | | 26 | |
| 38 | it("uses a stored project icon or falls back to the browser mockup", () => { | 27 | await act(async () => renderer!.root.findByType("img").props.onError()); |
| 39 | mocks.favicon = null; | 28 | expect(renderer!.root.findByType("img").props.src).toBe(remote); |
| 40 | const html = renderToStaticMarkup( | 29 | |
| 41 | <PreviewFaviconIcon threadRef={threadRef} url="http://localhost:3000/" />, | 30 | await act(async () => renderer!.root.findByType("img").props.onError()); |
| 42 | ); | 31 | expect(renderer!.root.findAllByType("img")).toHaveLength(0); |
| 43 | expect(html).not.toContain("<img"); | 32 | expect(renderer!.root.findByType("span").children).toEqual(["fallback"]); |
| 44 | expect(html).toContain("rounded-[5px]"); | 33 | |
| 45 | mocks.favicon = "data:image/png;base64,AAAA"; | 34 | await act(async () => { |
| 46 | const faviconHtml = renderToStaticMarkup( | 35 | renderer!.update( |
| 47 | <PreviewFaviconIcon threadRef={threadRef} url="http://localhost:3000/" />, | 36 | <FaviconImage |
| | 37 | sources={[captured, "https://public.example/new-icon"]} |
| | 38 | fallback={<span>fallback</span>} |
| | 39 | />, |
| 48 | ); | 40 | ); |
| 49 | expect(faviconHtml).toContain('src="data:image/png;base64,AAAA"'); | | |
| 50 | }); | 41 | }); |
| | 42 | expect(renderer!.root.findByType("img").props.src).toBe(captured); |
| 51 | }); | 43 | }); |