useBountyStatus.test.tsx tests a hook that no longer exists: it mocks fetchBounty, asserts data with enabled:false, and leaks the module-level poller registry between cases

Aperta
#846 1 commento 0 reazioni 0 assegnatari Vedi su GitHub

I maintainer di solito rispondono entro 1 giorno

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
3/5
Tempo stimato
1-2 giorni
Idoneità per principianti
57/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
react, typescript
Ambito
frontend, testing

Direzione di ricerca

Start with src/hooks/useBountyStatus.test.tsx, then read src/hooks/useBountyStatus.ts and src/hooks/bountyPoller.ts to align tests with the hook’s subscription registry. Run npx jest src/hooks/useBountyStatus.test.tsx to confirm the failures; done means the suite isolates registry state and covers the stated subscription, polling, refetch, and failed-fetch behavior. The issue also raises whether to remove or reconnect useSmartPolling, which adds scope.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

bug testing

Location

src/hooks/useBountyStatus.test.tsx (whole file), against the current src/hooks/useBountyStatus.ts and src/hooks/bountyPoller.ts.

Problem

The suite was written for the pre-#631 hook, which ran its own useSmartPolling loop over an injected fetchBounty. Its own header still says so: "Covers the hook wrapping useSmartPolling". The hook is now a thin useSyncExternalStore over the module-level registry in bountyPoller.ts. The tests were never updated, and several of them cannot pass against the current implementation:

  1. enabled: false cases assert fetched data. Cases 1 and 2 render with enabled: false. In the current hook that makes the subscribe function a no-op (useBountyStatus.ts:42), so subscribeBounty is never called, no entry is created, and getBountySnapshot returns { bounty: null, source: null, loading: false, error: null }. The assertions expect(result.current.bounty).toEqual(mockBounty) and expect(result.current.source).toBe("live") are asserting state that the code has no way to produce.

  2. Case 3 asserts a callback the hook never invokes. onStatusChange is destructured and then never referenced anywhere in useBountyStatus.ts (filed separately), so expect(onStatusChange).toHaveBeenCalledWith("open") can only time out.

  3. Cross-test state leakage. registry in bountyPoller.ts is module-level and is never reset. beforeEach(() => jest.clearAllMocks()) clears the fetchBounty mock but not the registry, so an entry created by one case — along with its bounty, its source and, if the terminal-status branch did not fire, its live setInterval — survives into the next. Cases therefore pass or fail depending on declaration order, and the real intervals keep firing across the file.

  4. The mock is now at the wrong seam. jest.mock("@/lib/api", () => ({ fetchBounty: jest.fn() })) replaces the module the registry calls, not anything the hook calls. That is why the suite looks like it is exercising fetch behaviour while actually exercising nothing: the hook under test makes no API call of its own, and the mock also strips every other export of @/lib/api, so any future import from that module inside the hook silently becomes undefined.

Relatedly, useSmartPolling is now dead code: the only references to it anywhere under src/ outside its own file are its own test (src/hooks/useSmartPolling.test.tsx) and a comment in useClaimRace.ts. Nothing renders it. The open report #568 ("useSmartPolling stops polling after the first re-render because useBountyStatus passes inline fetchFn/compareFn/onDataChange") describes a call site that no longer exists, so that issue is unverifiable as written and should be re-scoped or closed.

Why it matters

This is worse than having no tests, which is the state #620 was filed about. The file's presence is what makes useBountyStatus look covered, so the genuine defects now living in bountyPoller.ts (a stopped poller that never restarts, a failed fetch blanking the bounty, refetch being a no-op) sit behind a green-looking test file that exercises none of them. And because the suite cannot pass as written, CI is either red on this file or the file is being skipped — both of which hide the same thing.

Reproduction

npx jest src/hooks/useBountyStatus.test.tsx — cases 1, 2 and 3 fail for the reasons above (1 and 2 on the bounty/source assertion, 3 on the waitFor timeout).

Suggested fix

Rewrite the suite against the seam the hook actually has:

  • Export a __resetBountyPollerRegistry() (test-only) from bountyPoller.ts, or clear the map via jest.resetModules() in beforeEach, so each case starts clean.
  • Mock @/lib/api with ...jest.requireActual("@/lib/api") spread in, overriding only fetchBounty, so the rest of the module stays intact.
  • Use fake timers and assert the behaviours that matter: one shared fetch loop for two subscribers on the same id; polling stops on a terminal status; polling restarts when a new subscriber arrives after the last one left; refetch() performs a fetch while the loop is stopped; a failed fetch surfaces error without blanking a previously loaded bounty.
  • Drop the enabled: false data assertions, and replace them with the real contract: enabled: false means no subscription and no fetch.

Then decide useSmartPolling's fate: delete the hook and its test if the registry is the way forward, or re-wire it and keep its tests meaningful. Leaving it in src/hooks/ invites a contributor to adopt it and inherit the bugs reported against it.

Lingua principale
TypeScript
Stelle
1
Fork
94
Merge medio
1h 2m
PR unite (30g)
25

Preparare l'ambiente

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di MergeFi/frontend

Tutte le issue di MergeFi/frontend

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.