1import { render, screen } from "@testing-library/react"
2import { describe, expect, it } from "vitest"
3
4import { GestureHUD, resolveHudState } from "@/features/gesture/GestureHUD"
5
6/* DESIGN-SYSTEM §11: HUD gesture memakai `role="status"`. Keadaan `holding`
7 tidak bisa dipicu kamera palsu, jadi dibuktikan di sini. */
8
9const BASE = {
10 cameraActive: true,
11 enabled: true,
12 status: "ready" as const,
13 phase: "ready" as const,
14 holdAction: null,
15}
16
17describe("resolveHudState", () => {
18 it("menyembunyikan HUD saat kamera belum aktif atau model gagal", () => {
19 expect(resolveHudState({ ...BASE, cameraActive: false })).toBe("hidden")
20 expect(
21 resolveHudState({ ...BASE, cameraActive: false, holdAction: "snap" })
22 ).toBe("hidden")
23 expect(resolveHudState({ ...BASE, status: "failed" })).toBe("hidden")
24 expect(
25 resolveHudState({ ...BASE, status: "failed", phase: "complete" })
26 ).toBe("hidden")
27 })
28
29 it("menahan selalu menang atas keadaan lain", () => {
30 expect(resolveHudState({ ...BASE, holdAction: "snap" })).toBe("holding")
31 expect(
32 resolveHudState({ ...BASE, enabled: false, holdAction: "retake" })
33 ).toBe("holding")
34 expect(
35 resolveHudState({ ...BASE, status: "loading", holdAction: "snap" })
36 ).toBe("holding")
37 })
38
39 it("sakelar mati: mati saat siap, selesai saat semua slot terisi", () => {
40 expect(resolveHudState({ ...BASE, enabled: false })).toBe("off")
41 expect(
42 resolveHudState({ ...BASE, enabled: false, phase: "complete" })
43 ).toBe("done")
44 expect(
45 resolveHudState({ ...BASE, enabled: false, phase: "countdown" })
46 ).toBe("hidden")
47 })
48
49 it("menampilkan status memuat hanya saat pratinjau siap", () => {
50 expect(resolveHudState({ ...BASE, status: "loading" })).toBe("loading")
51 expect(
52 resolveHudState({ ...BASE, status: "loading", phase: "countdown" })
53 ).toBe("hidden")
54 })
55
56 it("siap: siap saat pratinjau siap, selesai saat semua slot terisi, sisanya sembunyi", () => {
57 expect(resolveHudState(BASE)).toBe("ready")
58 expect(resolveHudState({ ...BASE, phase: "complete" })).toBe("done")
59 expect(resolveHudState({ ...BASE, phase: "countdown" })).toBe("hidden")
60 expect(resolveHudState({ ...BASE, phase: "capturing" })).toBe("hidden")
61 expect(resolveHudState({ ...BASE, phase: "pause" })).toBe("hidden")
62 expect(resolveHudState({ ...BASE, phase: "holding" })).toBe("hidden")
63 })
64
65 it("status idle saat sakelar menyala tidak menampilkan apa pun", () => {
66 expect(resolveHudState({ ...BASE, status: "idle" })).toBe("hidden")
67 })
68})
69
70describe("GestureHUD", () => {
71 it("keadaan siap menyebut perintahnya", () => {
72 render(<GestureHUD state="ready" />)
73 expect(screen.getByRole("status")).toBeTruthy()
74 expect(screen.getByText("Angkat dua jari, tahan sebentar")).toBeTruthy()
75 })
76
77 it("keadaan memuat menyebut sedang menyiapkan", () => {
78 render(<GestureHUD state="loading" />)
79 expect(screen.getByText("Menyiapkan gesture...")).toBeTruthy()
80 })
81
82 it("keadaan mati menyebut jalan lain", () => {
83 render(<GestureHUD state="off" />)
84 expect(screen.getByText("Gesture mati. Pakai tombol kamera.")).toBeTruthy()
85 })
86
87 it("keadaan selesai menyebut jumlah foto", () => {
88 render(<GestureHUD state="done" shotCount={4} />)
89 expect(screen.getByText("4 foto siap dihias")).toBeTruthy()
90 })
91
92 it("keadaan tersembunyi tidak merender apa pun", () => {
93 const { container } = render(<GestureHUD state="hidden" />)
94 expect(container.firstChild).toBeNull()
95 })
96
97 it("keadaan menahan mengisi batang sesuai progres", () => {
98 const { container } = render(<GestureHUD state="holding" progress={0.35} />)
99 expect(screen.getByText("Terdeteksi. Tahan...")).toBeTruthy()
100
101 const bar = container.querySelector<HTMLDivElement>("div[style]")
102 expect(bar?.style.width).toBe("35%")
103 })
104
105 it("progres nol dan penuh dipotong ke 0 dan 100 persen", () => {
106 const kosong = render(<GestureHUD state="holding" progress={0} />)
107 expect(
108 kosong.container.querySelector<HTMLDivElement>("div[style]")?.style.width
109 ).toBe("0%")
110 kosong.unmount()
111
112 const penuh = render(<GestureHUD state="holding" progress={1} />)
113 expect(
114 penuh.container.querySelector<HTMLDivElement>("div[style]")?.style.width
115 ).toBe("100%")
116 })
117})
118