import { useEffect, useLayoutEffect } from "react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { waitFor } from "@testing-library/react"; import { renderWithProviders as render, screen } from "../utils/test-utils"; import "@testing-library/jest-dom/vitest"; import { FinalReviewScreen } from "../../app/(app)/create/screens/review/FinalReviewScreen"; import { useCreateFlow } from "../../app/(app)/create/context/CreateFlowContext"; import { CREATE_FLOW_ANONYMOUS_KEY } from "../../app/(app)/create/utils/anonymousDraftStorage"; import { dominantColorFromImageUrl, randomPreviewSurfaceColor, } from "../../lib/create/previewSurfaceColor"; import type { CreateFlowState } from "../../app/(app)/create/types"; vi.mock("../../lib/create/previewSurfaceColor", async (importOriginal) => { const actual = await importOriginal< typeof import("../../lib/create/previewSurfaceColor") >(); return { ...actual, dominantColorFromImageUrl: vi.fn(async () => "rgb(12, 80, 40)"), randomPreviewSurfaceColor: vi.fn(() => "hsl(12, 50%, 80%)"), }; }); function FinalReviewWithAvatar() { const { replaceState } = useCreateFlow(); useLayoutEffect(() => { replaceState({ title: "Oak Park Commons", communityContext: "Local mutual aid.", communityAvatarUrl: "/api/uploads/avatar-1", }); }, [replaceState]); return ; } function FinalReviewWithStateProbe({ initial, onState, }: { initial: CreateFlowState; onState: (_state: CreateFlowState) => void; }) { const { state, replaceState } = useCreateFlow(); useLayoutEffect(() => { replaceState(initial); }, [replaceState, initial]); useEffect(() => { onState(state); }, [onState, state]); if (state.title !== initial.title) return null; if ( initial.previewSurfaceColor && state.previewSurfaceColor !== initial.previewSurfaceColor ) { return null; } return ; } describe("Final review preview surface", () => { beforeEach(() => { window.localStorage.removeItem(CREATE_FLOW_ANONYMOUS_KEY); vi.mocked(randomPreviewSurfaceColor).mockClear(); }); it("fills the card from the uploaded logo’s most common color", async () => { render(); await waitFor(() => { const card = screen.getByRole("button", { name: /Oak Park Commons/i }); expect(card).toHaveStyle({ backgroundColor: "rgb(12, 80, 40)" }); }); expect(vi.mocked(dominantColorFromImageUrl)).toHaveBeenCalledWith( "/api/uploads/avatar-1", ); expect( screen.getByRole("img", { name: "Oak Park Commons" }), ).toHaveAttribute("src", expect.stringContaining("avatar-1")); }); it("writes a fallback fill onto the draft when no logo is uploaded", async () => { let latest: CreateFlowState = {}; render( { latest = state; }} />, ); await waitFor(() => { expect(latest.previewSurfaceColor).toBe("hsl(12, 50%, 80%)"); }); expect(vi.mocked(randomPreviewSurfaceColor)).toHaveBeenCalled(); }); it("reuses a fallback saved only in localStorage across a fresh mount", async () => { window.localStorage.setItem( CREATE_FLOW_ANONYMOUS_KEY, JSON.stringify({ title: "Oak Park Commons", communityContext: "Local mutual aid.", previewSurfaceColor: "hsl(200, 60%, 80%)", }), ); let latest: CreateFlowState = {}; render( { latest = state; }} />, ); await waitFor(() => { expect(latest.previewSurfaceColor).toBe("hsl(200, 60%, 80%)"); }); expect(vi.mocked(randomPreviewSurfaceColor)).not.toHaveBeenCalled(); }); it("reuses the stored fallback instead of picking a new color", async () => { vi.mocked(randomPreviewSurfaceColor).mockClear(); render( {}} />, ); await waitFor(() => { const card = screen.getByRole("button", { name: /Oak Park Commons/i }); expect(card.style.backgroundColor).not.toBe(""); }); expect(vi.mocked(randomPreviewSurfaceColor)).not.toHaveBeenCalled(); const card = screen.getByRole("button", { name: /Oak Park Commons/i }); expect(card.style.backgroundColor).not.toBe("rgb(12, 80, 40)"); }); });