Files

4.5 KiB
Raw Permalink Blame History

TESTING — anwarpy.ai

Owner decision 2026-10-11: tier (b) is the bar — Vitest unit tests for the core libs + regression tests for API route behavior. Tier (c) — Playwright E2E for critical journeys — activates when Phase 3 (Stripe) lands; journeys to cover then: signup→verify→login, VIP ghost-read (billing on), checkout happy path, webhook apply.

1. Standing gates (before any commit/merge)

cd web && npx tsc --noEmit        # must exit 0
cd web && npm run build           # must exit 0 (includes generate:types)

Both green = minimum. Gates alone are not proof of behavior — see §3.

2. Unit tests (Vitest, tier b)

  • Add vitest as a dev dependency; tests live beside the code or under web/src/lib/__tests__/ — pick one location and stay consistent (recommend __tests__/ next to src/lib).
  • Required suites (the known-risk list):
Suite Must pin
launch.test.ts policy truth table: billingEnabled() false when LAUNCH_MODE unset/free_early_access/paid… — including the fail-safe default
lexical.test.ts lexicalToText/countLexicalWords descend into content.root (regression: the 2026-10-10 launch-blocking bug where both returned 0/'' on real serialized trees); extractH2s, lexicalToPlain
secret-scan.test.ts one case per pattern (aws_access_key, pem_private_key, openai_api_key, github_token, generic_credential) returns pattern name only, never the matched text; clean payload passes; string content is scanned too
topics.test.ts isTopic accepts exactly agents/models/automation/foundations; topicsFor mapping
format.test.ts guidesLabel (1 دليل، 2 دليلان، 3–10 أدلة، 11+), minutesLabel, MEMBERSHIP_PRICE
  • Rule: tests assert behavior, not implementation text. No snapshot-of-source, no tautologies (expect(fn).toBeDefined()), no mock-echo tests, no bare "does not throw".
  • Runtime env manipulation: use vi.stubEnv/unstubAllEnvs — never let one test's LAUNCH_MODE leak into another.

3. API route regression tests

Behavior tests for the routes with contracts (per PRD §3.6, SECURITY §4):

  • POST/PUT /api/agent/posts: 401 wrong/missing key (note: x-agent-key, not Bearer); 400 on string content; 422 with pattern names on secret-bearing Lexical; sourceId dedup returns existing post (no 409, no duplicate row); pickFields strips access/readingMinutes; PUT cannot set status.
  • POST /api/subscribe: 503 + exact Arabic body while billing is off.
  • POST /api/notify: records row then honest 503 when mail transport fails; duplicate email → 200 alreadySubscribed: true; no double-send on dup.
  • Comments route: unauthenticated → reject; client-sent author ignored (server-forced).
  • Likes: 401 anonymous; second like by same user → no duplicate row.

Implementation: pure logic moves into src/lib helpers where possible and gets unit-tested; handler-level tests run the route module with a mocked Payload local API (or hit a dev server for the smoke tier — §5). Prefer extracting decision logic over wiring up heavy mocks.

4. What must NOT become a test

  • Wiring/copies/forwarding, mock echoes, source-text greps, "file exists".
  • Incidental defaults that aren't contracts (an unstyled div's class list is not a spec).
  • Anything already verified cheaper by the ghost-read/smoke script in §5.
  • Per the gstack rule: existing tests that pin wording/implementation instead of behavior get deleted, not "fixed".

5. Smoke & verification scripts (throwaway, not committed)

  • Prod verification is HTTP-level and scripted ad hoc (curl batches): ghost-read a VIP post logged out; check isAccessibleForFree, og:image 1200×630, JSON-LD types; subscribe 503; notify row + cleanup; sitemap contents; www 308. Use @example.com rows and delete them after (ground truth: users=6, launch_notifications=0).
  • Keep the failing-before/passing-after pair when fixing a bug — a permanent regression test in §2/§3 if it's pure logic, the script transcript if it's deploy/config.

6. Before-merge checklist (condensed)

  1. tsc --noEmit + npm run build exit 0.
  2. New/changed lib behavior → matching Vitest suite updated or added.
  3. Changed route contract → §3 regression updated (status + body shape).
  4. Changed access logic → ghost-read check (logged-out VIP post) recorded in the PR.
  5. No new any, no new 'use client' without justification, no new dependency without a line of justification (CODE_STYLE §8).