teqo-backup/docs/TESTING.md
Francisco Ignácio Fontoura Solla 0e4e6855dc Add the tooling gate: knip, CI, zero-warning lint, as-never ban
- knip (files/deps at error level; unused exports ledgered as warn) with
  config for Payload/Next entries; deleted the dead modules it confirmed:
  RecentlyVisited + UpcomingActionPlansCard + actionPlanUpcomingPreview,
  lazy-dialog helpers, tseZone, federalCandidateTotalsAggregate (test-only),
  unused ui kit files, one-shot rename script; pruned unused radix deps and
  typescript-eslint; added pg/@types/pg (pinned to drizzle's 8.10.2)
- GitHub Actions CI on the mirror: lint, typecheck, knip, unit, migrate, int
  against a Postgres 17 service
- eslint: unused-vars with ^_ ignore patterns (migrations args exempt),
  repo-wide ban on `as never` (no-restricted-syntax), lint gate at
  --max-warnings=0; fixed all 54 pre-existing warnings (dead imports,
  hooks deps, tracking-pixel img disable with impeccable config exception)
- tsconfig: include consolidated from 219 lines to 5 (wildcard covers all
  .next dist variants), noUnusedLocals on
- typed replacements for every as-never: hookFilledCreateData (actions
  create data completed by collection hooks), drizzle scopeColumn narrowing,
  tests' stub<T> helper (property-level checking kept, completeness waived)
- test infra: leased-consent generalization used by onda0 spec (shared
  leases over the stable consent keys; window race ledgered), purge fix
- docs: IMPROVE-CODE-QUALITY-PLAN.md tracker, TECH-DEBT.md ledger,
  TESTING.md safety-net map (package.json also gains the Phase 2
  build:election-aggregates script entry; the script lands next commit)
2026-07-23 23:06:12 -03:00

3 KiB

Testing

Test Strategy

Three layers, all local-database-only (see local-database skill; tests refuse any database not ending in _test):

  • Unit (tests/unit/**/*.unit.spec.ts, 33+ specs): pure logic; runs with a deliberately invalid DATABASE_URL so nothing can touch a database.
  • Integration (tests/int/**/*.int.spec.ts, 42+ specs): real Payload + Postgres (teqo_test); campaign fixtures allocate seeded municipalities via a Postgres sequence so parallel spec files never share one, and purge residue on claim. Shared consent rows with stable keys are leased (tests/helpers/testDatabaseLease.ts), never owned.
  • E2E (tests/e2e, Playwright, 5 specs): smoke-level; most campaign behavior is pinned at the int layer.

CI (.github/workflows/ci.yml) runs lint (zero warnings), typecheck, knip, unit, migrate, int against a Postgres 17 service.

Safety Net Map

Modules the 2026-07 hardening phases touch, and where their behavior is pinned:

Module Pinned behaviors Test files Gaps
campaignAccess.ts (RBAC) per-role municipality/leadership/pledge/supporter/demand/plan scoping; leader lockdown; staff field asymmetry campaignMunicipalityAccess, campaignVotePledge, campaignSupporter, campaignUserPhone, campaignActionPlan, campaignDemandWorkflow, collectionAccessLockdown (int) no dedicated per-export suite; covered through collection behavior
Collection access lockdown campaign JWT denied on users/PII/CMS writes; anonymous read of public content; admin unaffected collectionAccessLockdown.int.spec.ts REST-transport variant untested (Local API with overrideAccess: false is equivalent)
municipalityMapData.ts bundle scoping by URL filters + advisor access; validVotesByYear incl. 2026 reuse of 2022; null on empty scope municipalityMapData.int.spec.ts zone breakdown shape
votePledgeData.ts estimated[scenario] ?? declared aggregation; role scoping; leader denial campaignVotePledge.int.spec.ts
Supporter import (token/bulk) preview→confirm flow, dedup by phone, consent fail-closed campaignSupporter.int.spec.ts supporterImportBulk/supporterImportToken internals only via flow
Leader supporter create linked-municipality scope; out-of-scope rejection; staff rejection collectionAccessLockdown.int.spec.ts
Posts visibility/caching isPostVisible fail-closed; cached listing (indirect via routes) no dedicated posts spec — backlog

Characterization Backlog

  • src/utilities/posts.ts — dedicated spec for isPostVisible fail-closed matrix and cache wrappers.
  • actionPlanViewModels.ts + other actionPlan* utilities (~1k lines) — currently untested directly.
  • campaignDemandData.ts / leadershipData.ts / organizationData.ts / stateDeputyData.ts list loaders.
  • Election aggregate artifact (Phase 2): snapshot test pinning artifact ↔ municipalityCatalog key consistency.