Skip to content

test: consolidate duplicated live-query test harness - #162

Open
mbret wants to merge 1 commit into
mainfrom
chore/consolidation-2026-08-03
Open

test: consolidate duplicated live-query test harness#162
mbret wants to merge 1 commit into
mainfrom
chore/consolidation-2026-08-03

Conversation

@mbret

@mbret mbret commented Aug 3, 2026

Copy link
Copy Markdown
Owner

Consolidation: live-query test harness (net −162 LOC)

What was duplicated

  • src/lib/queries/useQuery$.reactivity.test.tsx (6 copies)
  • src/lib/queries/useQuery$.unmount.test.tsx (4 copies)

Every test in these two suites rebuilt the exact same scaffold by hand:

const liveQuery$ = new BehaviorSubject([...])
const db$ = new BehaviorSubject<object | undefined>({})
const queryClient = createQueryClient()

function Comp() {
  const { data } = useQuery$({
    ...liveQueryOptions,
    queryKey: [...],
    queryFn: () =>
      db$.pipe(filter(isDefined), switchMap(() => liveQuery$), map((items) => [...items])),
  })
  return <span data-testid="data">{JSON.stringify(data)}</span>
}

render(<Comp />, { wrapper: createWrapper(queryClient) })

plus, in the unmount suite, the same Host/toggle visibility wrapper repeated in all 4 tests, and the same expect(screen.getByTestId("data").textContent).toBe(JSON.stringify(...)) assertion everywhere.

What it became

  • createLiveQuerySource(initialItems) in src/tests/liveQuery.tsx — the shared home these suites already import from (createQueryClient, createWrapper, liveQueryOptions were consolidated there by test: dedupe isDefined helper against the library util #144's follow-ups). It builds the liveQuery$/db$ pair and the filter → switchMap → map queryFn that emulates a live database query.
  • One setup() helper per suite (component shape differs: plain component vs. hide/show host), plus a local expectData assertion helper.

Why they are truly the same concept

All 10 copies exercise the same fixture — "a live query backed by a db-readiness gate that re-emits a fresh array on every push" — against the same rendered output. They were copy-pasted, differing only in query key, initial items, and (in two tests) query options, which are now plain parameters. No behavior changes: query keys, options (including the two tests that intentionally omit staleTime: Infinity), emission sequences, timings, and assertions are byte-for-byte equivalent, and the two-observers test keeps its bespoke double-hook component.

Gates (same commands CI runs, all green before and after; 139/139 tests pass both times)

  • npm run check
  • npm run build (tsc + vite)
  • npm run test:ci

Other candidates surveyed and rejected

  • useSwitchMutation$ / useConcatMutation$: shared adapters were already extracted (mutationOptions.ts); the remaining similarity is genuinely divergent cancellation semantics (abort vs. ready-gate).
  • createLocalStorageAdapter / createLocalforageAdapter: superficially similar JSON (de)serialization but different backends with intentionally different removeItem/clear semantics.
  • Remaining jscpd hits (persistSignals.test.ts, useObserve.compare.test.tsx, useSwitchMutation$.test.tsx) are small intra-file test-case variations; consolidating them would trade readability for little LOC — possible future runs if they grow.

🤖 Generated with Claude Code

https://claude.ai/code/session_015zuCUHEHA1tWwYQ28x4rgB


Generated by Claude Code

The reactivity and unmount test suites each rebuilt the same live-query
scaffold (BehaviorSubject pair + filter/switchMap/map queryFn + data span
component + render) in every test — 10 copies across the two files.
Extract the source into createLiveQuerySource in tests/liveQuery and
collapse the per-test scaffolding into one setup helper per file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants