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)");
});
});