Files
BanGUI/frontend/src/hooks/__tests__/useConfigItem.test.ts
2026-03-22 14:24:32 +01:00

89 lines
2.5 KiB
TypeScript

import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { renderHook, act } from "@testing-library/react";
import { useConfigItem } from "../useConfigItem";
describe("useConfigItem", () => {
beforeEach(() => {
vi.useFakeTimers();
});
afterEach(() => {
vi.useRealTimers();
vi.clearAllMocks();
});
it("loads data and sets loading state", async () => {
const fetchFn = vi.fn().mockResolvedValue("hello");
const saveFn = vi.fn().mockResolvedValue(undefined);
const { result } = renderHook(() => useConfigItem<string, string>({ fetchFn, saveFn }));
expect(result.current.loading).toBe(true);
await act(async () => {
await Promise.resolve();
});
expect(fetchFn).toHaveBeenCalled();
expect(result.current.data).toBe("hello");
expect(result.current.loading).toBe(false);
});
it("sets error if fetch rejects", async () => {
const fetchFn = vi.fn().mockRejectedValue(new Error("nope"));
const saveFn = vi.fn().mockResolvedValue(undefined);
const { result } = renderHook(() => useConfigItem<string, string>({ fetchFn, saveFn }));
await act(async () => {
await Promise.resolve();
});
expect(result.current.error).toBe("nope");
expect(result.current.loading).toBe(false);
});
it("save updates data when mergeOnSave is provided", async () => {
const fetchFn = vi.fn().mockResolvedValue({ value: 1 });
const saveFn = vi.fn().mockResolvedValue(undefined);
const { result } = renderHook(() =>
useConfigItem<{ value: number }, { delta: number }>({
fetchFn,
saveFn,
mergeOnSave: (prev, update) =>
prev ? { ...prev, value: prev.value + update.delta } : prev,
})
);
await act(async () => {
await Promise.resolve();
});
expect(result.current.data).toEqual({ value: 1 });
await act(async () => {
await result.current.save({ delta: 2 });
});
expect(saveFn).toHaveBeenCalledWith({ delta: 2 });
expect(result.current.data).toEqual({ value: 3 });
});
it("saveError is set when save fails", async () => {
const fetchFn = vi.fn().mockResolvedValue("ok");
const saveFn = vi.fn().mockRejectedValue(new Error("save failed"));
const { result } = renderHook(() => useConfigItem<string, string>({ fetchFn, saveFn }));
await act(async () => {
await Promise.resolve();
});
await act(async () => {
await expect(result.current.save("test")).rejects.toThrow("save failed");
});
expect(result.current.saveError).toBe("save failed");
});
});