Files
Pien-Studio/apps/web/hooks/use-face-blur-workflow.test.tsx
T

184 lines
4.5 KiB
TypeScript
Raw Normal View History

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