import { act, renderHook, waitFor } from "@testing-library/react"; import { describe, expect, it, vi } from "vitest"; import type { Layer, LayerEffect } from "@pien-studio/types"; import { useFaceBlurWorkflow } from "./use-face-blur-workflow"; function makeImageLayer(overrides: Partial = {}): Layer { return { id: "layer-1", type: "raster", asset: { kind: "inline", uri: "data:image/png;base64,abc" }, x: 0, y: 0, width: 100, height: 100, scale: 1, rotation: 0, opacity: 1, effects: [], visible: true, ...overrides, } as Layer; } describe("useFaceBlurWorkflow", () => { it("selects all detected faces by default when no existing face blur", async () => { const setLayerEffect = vi.fn(); const removeLayerEffect = vi.fn(); const selectedLayer = makeImageLayer(); const faceDetections = [ { x: 1, y: 2, width: 10, height: 12, label: "a", sourceWidth: 100, sourceHeight: 100, }, { x: 5, y: 8, width: 7, height: 9, label: "b", sourceWidth: 100, sourceHeight: 100, }, ]; const { result } = renderHook(() => useFaceBlurWorkflow({ selectedLayer, faceDetectionsLayerId: "layer-1", faceDetections, setLayerEffect, removeLayerEffect, }), ); await waitFor(() => { expect(result.current.selectedFaceIndices).toEqual([0, 1]); const faceBlurEffect = result.current.faceBlurPreview?.effects.find( (e) => e.kind === "face-blur", ); expect( faceBlurEffect?.kind === "face-blur" ? faceBlurEffect.regions : undefined, ).toHaveLength(2); }); }); it("keeps selection empty when selected image already has blur", async () => { const setLayerEffect = vi.fn(); const removeLayerEffect = vi.fn(); const faceBlurEffect: LayerEffect = { kind: "face-blur", enabled: true, method: "gaussian", amount: 14, regions: [{ x: 0, y: 0, width: 4, height: 4 }], }; const selectedLayer = makeImageLayer({ effects: [faceBlurEffect] }); const { result } = renderHook(() => useFaceBlurWorkflow({ selectedLayer, faceDetectionsLayerId: "layer-1", faceDetections: [ { x: 1, y: 2, width: 10, height: 12, label: "a", sourceWidth: 100, sourceHeight: 100, }, ], setLayerEffect, removeLayerEffect, }), ); await waitFor(() => { expect(result.current.selectedFaceIndices).toEqual([]); expect(result.current.faceBlurPreview).toBeNull(); }); }); it("toggles face selection and applies blur to selected regions", async () => { const setLayerEffect = vi.fn(); const removeLayerEffect = vi.fn(); const selectedLayer = makeImageLayer(); const faceDetections = [ { x: 1, y: 2, width: 10, height: 12, label: "a", sourceWidth: 100, sourceHeight: 100, }, { x: 50, y: 60, width: 20, height: 22, label: "b", sourceWidth: 100, sourceHeight: 100, }, ]; const { result } = renderHook(() => useFaceBlurWorkflow({ selectedLayer, faceDetectionsLayerId: "layer-1", faceDetections, setLayerEffect, removeLayerEffect, }), ); await waitFor(() => { expect(result.current.selectedFaceIndices).toEqual([0, 1]); }); act(() => { result.current.toggleFaceIndex(1); }); expect(result.current.selectedFaceIndices).toEqual([0]); act(() => { result.current.blurFaces(result.current.selectedFaceIndices); }); expect(setLayerEffect).toHaveBeenCalledTimes(1); expect(setLayerEffect).toHaveBeenCalledWith( "layer-1", expect.objectContaining({ kind: "face-blur", method: "gaussian", amount: 14, regions: expect.arrayContaining([ expect.objectContaining({ x: 1, y: 2, width: 10, height: 12, censorColor: "#111111", sourceWidth: 100, sourceHeight: 100, }), ]), }), ); expect(result.current.selectedFaceIndices).toEqual([]); expect(result.current.faceBlurPreview).toBeNull(); }); });