Skip to content

Running Tests

Purpose

How to run tests in the HUPH monorepo. The project uses different test strategies per app — Jest for the Node.js API, pytest for the Python RAG service, and deliberate "no test infrastructure" for the Next.js admin. This page explains each.

Prerequisites

  • Setup completed — you have .venv, installed deps, and infrastructure running
  • Optional: jq for parsing smoke test JSON output

Test stacks per app

App Stack How to run How to verify changes
apps/api Jest + ts-jest npm run test -w apps/api Unit + integration tests
apps/admin None See "Admin verification" below tsc + smoke + manual browser
apps/crawler-worker Light integration only docker-compose logs crawler-worker during local runs Trigger a KB crawl from admin and watch the log
apps/landing None Open in browser

No apps/rag — the self-hosted RAG service was replaced by Dify in April 2026. AI-pipeline tests (prompt assembly, retrieval quality, reranker tuning) now happen inside Dify's own evaluation tooling, not inside the HUPH repo.

API (Jest)

Run all API tests

npm run test -w apps/api

Expected: ~280+ tests passing across suites including intentRouter, leadCapture, notifications, realtime, auth, escalationRules.

Run a single test file

cd apps/api
npx jest src/services/intentRouter/leadCapture/__tests__/clusterResolver.test.ts

Run by test name pattern

npx jest -t "cluster resolver"

Known pre-existing failure

apps/api/src/__tests__/realtime.integration.test.ts has an afterAll httpServer.close() issue predating any recent work. Exclude it if it blocks your run:

npx jest --testPathIgnorePatterns=realtime.integration

Critical gotcha: mocked DB tests can hide SQL bugs

During the API HTTP auth Phase 0 work (Apr 9 2026), mocked DB tests passed but an integration test caught a real bug that only surfaced against a live Postgres. Lesson: for anything touching persistence (writes, triggers, atomic upserts, complex queries), add at least one integration test that runs against the real local Postgres, not just mocks. The 64 leadCapture tests include integration tests hitting real DB — use them as a template.

AI pipeline tests (Dify-owned)

There is no local pytest suite for AI pipeline behavior because the RAG pipeline now lives in Dify, not in this repo. For testing chat quality and retrieval:

  • Retrieval Sandbox in admin → Knowledge base → Evaluation tab lets you run a question and see which documents Dify would retrieve to answer it.
  • Golden QA Dataset — 21 curated questions with expected answers, baseline ~95.2% pass rate. Click Run Eval on the Evaluation tab to execute all.
  • Dify's own eval tooling lives in the Dify admin UI at https://dify.huph.val.id.

For reproducing a specific chat bug locally, you can curl the Dify chat-messages endpoint directly — see the recipe in debugging.en.md.

Admin (no test infrastructure)

The admin app intentionally has no Jest / Vitest / Playwright setup. Verification happens via:

  1. TypeScript check — catches type errors:
cd apps/admin && npx tsc --noEmit
  1. Build check — catches runtime-missing imports and Next.js static analysis failures:
cd apps/admin && npm run build
  1. Manual browser smoke — log in, navigate the key pages (Conversations, Leads v2, Analytics v2, Knowledge base, FAQ, Follow-up, Counselor dashboard)

  2. curl smoke test — hit the API endpoints the admin proxies through. The scripts/smoke-e2e-synthetic.sh script has ~6 synthetic assertions for the full auth + lead capture flow (when API_AUTH_MODE=enforce)

Why no component tests? Admin pages are mostly thin wrappers around shared shadcn/ui components + SWR/polling. Testing them with React Testing Library would duplicate shadcn's own tests and add low-value mocks. The team concluded tsc + browser smoke gives better signal for the effort. See the feedback_admin_no_test_infra memory record for context.

Root-level npm run test

From repo root:

npm run test

This delegates to npm run test -w apps/api (Jest). There is no root-level pytest to run — AI pipeline testing is handled inside Dify.

TDD expectations

For any new feature or bugfix in apps/api:

  1. Write the failing test first
  2. Run it, verify it fails with the expected error
  3. Implement the minimum code to make it pass
  4. Run again, verify it passes
  5. Commit test + implementation in the same commit (or as adjacent commits within the same PR)

See first-pr.en.md for commit conventions. For admin, TDD is not required — follow the smoke workflow above.

Gotchas

  • Root-level npx jest picks up the wrong jest. From /opt/huph root, npx jest picks jest 30.2 from somewhere and can't read apps/api/jest.config.js. Always use npm run test -w apps/api or cd apps/api && npx jest. Spent ~10 minutes diagnosing this during the Apr 8 escalation routing work.
  • Jest config lives in apps/api/jest.config.js, not at the root. If you copy-paste test commands from other monorepos, confirm the -w apps/api workspace filter.
  • Socket.io tests need a running Postgres for the pg_notify bridge. They connect to the same DB as the app — make sure infrastructure is up before running them.
  • The docs site Python venv at docs-env/ at the repo root is for MkDocs only. There is no other Python venv in this repo — if old documentation mentions apps/rag/venv/, that is historical.

See also

  • Setup — infrastructure + services up
  • First PR — conventions + commit style
  • Debugging — when tests pass but something is still broken