test(web): add 57 UI component and hook tests with jsdom cleanup

Fix jsdom environment: add esbuild automatic JSX transform and
afterEach cleanup to prevent DOM leakage between tests.

Components: Badge (8), Button (13), FilterBar (5), EmptyState (8),
ConfirmDialog (8), useSelection hook (15).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-10 17:06:42 +02:00
parent 63db4a09e6
commit c0ba062460
8 changed files with 425 additions and 0 deletions
+113
View File
@@ -0,0 +1,113 @@
import { describe, expect, it } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useSelection } from "./useSelection.js";
describe("useSelection", () => {
it("starts with empty selection", () => {
const { result } = renderHook(() => useSelection());
expect(result.current.count).toBe(0);
expect(result.current.selectedArray).toEqual([]);
});
it("toggles an item on", () => {
const { result } = renderHook(() => useSelection());
act(() => result.current.toggle("a"));
expect(result.current.selectedIds.has("a")).toBe(true);
expect(result.current.count).toBe(1);
});
it("toggles an item off", () => {
const { result } = renderHook(() => useSelection());
act(() => result.current.toggle("a"));
act(() => result.current.toggle("a"));
expect(result.current.selectedIds.has("a")).toBe(false);
expect(result.current.count).toBe(0);
});
it("toggleAll selects all items when none are selected", () => {
const { result } = renderHook(() => useSelection());
act(() => result.current.toggleAll(["a", "b", "c"]));
expect(result.current.count).toBe(3);
expect(result.current.selectedIds.has("a")).toBe(true);
expect(result.current.selectedIds.has("b")).toBe(true);
expect(result.current.selectedIds.has("c")).toBe(true);
});
it("toggleAll deselects all items when all are selected", () => {
const { result } = renderHook(() => useSelection());
act(() => result.current.toggleAll(["a", "b"]));
act(() => result.current.toggleAll(["a", "b"]));
expect(result.current.count).toBe(0);
});
it("toggleAll selects remaining items when some are selected", () => {
const { result } = renderHook(() => useSelection());
act(() => result.current.toggle("a"));
act(() => result.current.toggleAll(["a", "b", "c"]));
expect(result.current.count).toBe(3);
});
it("clear removes all selections", () => {
const { result } = renderHook(() => useSelection());
act(() => {
result.current.toggle("a");
result.current.toggle("b");
});
act(() => result.current.clear());
expect(result.current.count).toBe(0);
});
it("isAllSelected returns true when all given ids are selected", () => {
const { result } = renderHook(() => useSelection());
act(() => result.current.toggleAll(["a", "b"]));
expect(result.current.isAllSelected(["a", "b"])).toBe(true);
});
it("isAllSelected returns false when some ids are not selected", () => {
const { result } = renderHook(() => useSelection());
act(() => result.current.toggle("a"));
expect(result.current.isAllSelected(["a", "b"])).toBe(false);
});
it("isAllSelected returns false for empty ids array", () => {
const { result } = renderHook(() => useSelection());
expect(result.current.isAllSelected([])).toBe(false);
});
it("isIndeterminate returns true when some but not all are selected", () => {
const { result } = renderHook(() => useSelection());
act(() => result.current.toggle("a"));
expect(result.current.isIndeterminate(["a", "b"])).toBe(true);
});
it("isIndeterminate returns false when all are selected", () => {
const { result } = renderHook(() => useSelection());
act(() => result.current.toggleAll(["a", "b"]));
expect(result.current.isIndeterminate(["a", "b"])).toBe(false);
});
it("isIndeterminate returns false when none are selected", () => {
const { result } = renderHook(() => useSelection());
expect(result.current.isIndeterminate(["a", "b"])).toBe(false);
});
it("selectedArray reflects the current selection", () => {
const { result } = renderHook(() => useSelection());
act(() => {
result.current.toggle("x");
result.current.toggle("y");
});
expect(result.current.selectedArray.sort()).toEqual(["x", "y"]);
});
it("preserves other selections when toggling individual items", () => {
const { result } = renderHook(() => useSelection());
act(() => {
result.current.toggle("a");
result.current.toggle("b");
});
act(() => result.current.toggle("a"));
expect(result.current.selectedIds.has("b")).toBe(true);
expect(result.current.count).toBe(1);
});
});