diff --git a/apps/web/src/components/pullRequest/pullRequestPresentation.test.tsx b/apps/web/src/components/pullRequest/pullRequestPresentation.test.tsx new file mode 100644 index 000000000000..df38d75152cf --- /dev/null +++ b/apps/web/src/components/pullRequest/pullRequestPresentation.test.tsx @@ -0,0 +1,28 @@ +import { act } from "react"; +import { create, type ReactTestRenderer } from "react-test-renderer"; +import { afterEach, expect, it, vi } from "vite-plus/test"; + +import { PullRequestActorAvatar } from "./pullRequestPresentation"; + +let renderer: ReactTestRenderer | undefined; + +afterEach(async () => { + await act(async () => renderer?.unmount()); + vi.unstubAllGlobals(); +}); + +it("falls back to the actor initial when a remote avatar fails", async () => { + vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true); + await act(async () => { + renderer = create( + , + ); + }); + + await act(async () => renderer!.root.findByType("img").props.onError()); + + expect(renderer!.root.findAllByType("img")).toHaveLength(0); + expect(renderer!.root.findByType("span").children).toEqual(["O"]); +}); diff --git a/apps/web/src/components/pullRequest/pullRequestPresentation.tsx b/apps/web/src/components/pullRequest/pullRequestPresentation.tsx index 890efb67cb9b..e011fa640311 100644 --- a/apps/web/src/components/pullRequest/pullRequestPresentation.tsx +++ b/apps/web/src/components/pullRequest/pullRequestPresentation.tsx @@ -19,7 +19,7 @@ import { TriangleAlertIcon, UserCheckIcon, } from "lucide-react"; -import { Children, isValidElement, type ReactNode } from "react"; +import { Children, isValidElement, type ReactNode, useState } from "react"; import { cn } from "~/lib/utils"; @@ -346,8 +346,9 @@ export function PullRequestActorAvatar({ }) { const login = actor?.login ?? "ghost"; const avatarUrl = actor?.avatarUrl ?? null; - return avatarUrl === null ? ( - // Not every host reports an avatar, so the initial stands in where none arrives. + const [failedAvatarUrl, setFailedAvatarUrl] = useState(null); + return avatarUrl === null || failedAvatarUrl === avatarUrl ? ( + // Not every host reports an avatar, and a private host may refuse the browser's request. setFailedAvatarUrl(avatarUrl)} /> ); }