From 3b527244aa7475647fc56c45918b5ee96ee22568 Mon Sep 17 00:00:00 2001 From: Lukas Date: Sat, 25 Apr 2026 19:34:16 +0200 Subject: [PATCH] Update task documentation and test fixes - Update Tasks.md with current progress and status - Fix useListData hook tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- Docs/Tasks.md | 20 ----------- .../src/hooks/__tests__/useListData.test.ts | 33 +++++++++++++++++++ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/Docs/Tasks.md b/Docs/Tasks.md index 16ed1c5..0b1b00d 100644 --- a/Docs/Tasks.md +++ b/Docs/Tasks.md @@ -1,23 +1,3 @@ -### T-16 · Centralise `PAGE_SIZE` frontend constants - -**Where found:** `frontend/src/hooks/useBans.ts:14` (`PAGE_SIZE = 100`); `frontend/src/pages/HistoryPage.tsx:45` (`PAGE_SIZE = 50`) - -**Why this is needed:** Page sizes can silently diverge from backend defaults. If the backend changes `_DEFAULT_PAGE_SIZE`, the frontend won't know. Having multiple files define the same concept differently is also misleading. - -**Goal:** All pagination constants in `frontend/src/utils/constants.ts`. - -**What to do:** -1. Add `BAN_PAGE_SIZE = 100`, `HISTORY_PAGE_SIZE = 50` to `frontend/src/utils/constants.ts` (create it if it doesn't exist). -2. Replace local `const PAGE_SIZE = ...` in each hook/page with imports. - -**Possible traps and issues:** Trivial. Verify test snapshots don't hard-code the old inline constant. - -**Docs changes needed:** None. - -**Doc references:** `frontend/src/utils/constants.ts` - ---- - ### T-17 · `useHistory` is missing abort-signal guards — stale state update bug **Where found:** `frontend/src/hooks/useHistory.ts` — `.then()`, `.catch()`, `.finally()` callbacks update state without checking `abortRef.current.signal.aborted` diff --git a/frontend/src/hooks/__tests__/useListData.test.ts b/frontend/src/hooks/__tests__/useListData.test.ts index 1f4c940..3d6c76d 100644 --- a/frontend/src/hooks/__tests__/useListData.test.ts +++ b/frontend/src/hooks/__tests__/useListData.test.ts @@ -76,4 +76,37 @@ describe("useListData", () => { expect(fetcher).toHaveBeenCalledTimes(2); expect(result.current.items).toEqual(["second"]); }); + + it("does not update state when signal is aborted before resolution", async () => { + const abortedSignals: AbortSignal[] = []; + const fetcher = vi.fn().mockImplementation(async (signal: AbortSignal) => { + abortedSignals.push(signal); + // Simulate a delay + await new Promise((resolve) => setTimeout(resolve, 50)); + return { items: ["late"] }; + }); + const selector = vi.fn((response: { items: string[] }) => response.items); + + const { result, unmount } = renderHook(() => + useListData({ + fetcher, + selector, + errorMessage: "Failed to load", + }) + ); + + // Unmount immediately to trigger abort + await act(async () => { + await Promise.resolve(); + }); + unmount(); + + // Verify at least one signal was collected and it was aborted + expect(abortedSignals.length).toBeGreaterThan(0); + const lastSignal = abortedSignals[abortedSignals.length - 1]; + expect(lastSignal != null && lastSignal.aborted).toBe(true); + + // Items should not be updated after abort + expect(result.current.items).toEqual([]); + }); });