Appearance
0042 — Manual Testing Tool Suite ​
Status: Accepted
Date: 2026-06-24
ADO work item: AB#4415
Deciders: Kristopher Turner
Context ​
The Heritage Community Hub codebase spans a Node.js/Fastify API, a React web app, shared TypeScript packages, Bicep infrastructure-as-code, and PowerShell automation scripts. Before any deployment goes live, the team needs confidence that every layer of the stack is correct — from infrastructure templates to UI components to API service logic.
The project runs on a single production environment. There is no automated gate that blocks a bad deployment; the developer is responsible for running the appropriate tools before pushing code live. The goal is a well-defined suite of purpose-built tools — one per layer — that can each be run independently and manually to verify correctness and catch problems before they reach users.
This ADR defines that suite: what tool covers what layer, why it was chosen, and how it is used.
Decision ​
We will maintain a suite of purpose-built testing tools — one per layer of the stack — each run manually before deployment. No single tool covers everything. Each tool is chosen because it is the best fit for its specific layer.
The suite covers the following layers:
Infrastructure (Bicep / Azure) ​
Tool: PSRule for Azure (Az.Test ruleset)
PSRule for Azure validates Bicep templates against the Azure Well-Architected Framework and Microsoft best-practice rules before deployment. It runs entirely offline against the template files — no Azure subscription required.
powershell
Invoke-PSRule -InputPath infrastructure/ -Module 'PSRule.Rules.Azure'Tool: ARM Template Toolkit (arm-ttk)
arm-ttk validates the ARM JSON that Bicep compiles to, catching structural errors, naming violations, and parameter issues.
powershell
Test-AzTemplate -TemplatePath infrastructure/API — Unit and Integration ​
Tool: Vitest
Vitest is the unit and integration test runner for the Node.js/Fastify API. Each service class is tested in isolation with a mocked Prisma client. Integration tests use Fastify's app.inject() to exercise the full middleware stack — auth guards, error envelopes, route registration — without a live database or Clerk connection.
Tests live in apps/api/src/ alongside the source files they cover. The shared Prisma mock is in apps/api/src/test/setup.ts.
Run from bld-01 or WSL:
bash
pnpm --filter @hch/api testAPI — Live Endpoint Testing ​
Tool: Bruno (or VS Code REST Client .http files)
Bruno is an open-source API client (no cloud sync, no account required) for manually testing live API endpoints. Request collections live in apps/api/requests/ and cover every route — authenticated and unauthenticated — with example payloads and expected responses documented inline.
VS Code REST Client .http files are an alternative for developers who prefer to stay in the editor.
Web — Component and Page Tests ​
Tool: Vitest + React Testing Library
React Testing Library tests verify that key pages and components render correctly, respond to user interaction, and handle conditional UI logic (auth state, role-based visibility, empty/loading/error states).
Run from bld-01 or WSL:
bash
pnpm --filter @hch/web testWeb — Browser-Level ​
Tool: Playwright
Playwright smoke tests verify critical user flows in a real browser — sign-in redirect, authenticated page access, API health — against the live deployed environment. Tests live in e2e/.
bash
pnpm exec playwright testShared TypeScript Packages ​
Tool: Vitest
Lightweight smoke tests for @hch/shared-config (featureRegistry logic, role filtering) and @hch/shared-types (ROLE_LEVEL shape, FEATURE_ROLES set).
bash
pnpm --filter @hch/shared-config test
pnpm --filter @hch/shared-types testPowerShell Scripts ​
Tool: Pester 5
Pester is the standard PowerShell testing framework. Any PowerShell automation scripts in this repo (infrastructure helpers, seed scripts, tooling) have corresponding .Tests.ps1 files that verify their behavior.
powershell
Invoke-Pester ./scripts/Dependency and Secret Scanning ​
Tool: Snyk
Snyk scans all npm packages for known vulnerabilities.
bash
npx snyk test --severity-threshold=highTool: Gitleaks
Gitleaks scans the full git history for accidentally committed secrets or credentials.
bash
gitleaks detect --source . --verbose --redactStatic Analysis / Lint ​
Tool: ESLint + TypeScript compiler
The TypeScript compiler (tsc --noEmit) and ESLint catch type errors, unsafe patterns, and style violations across all packages before a build.
bash
pnpm turbo lintAlternatives considered ​
| Layer | Chosen | Alternatives considered | Why not chosen |
|---|---|---|---|
| Infrastructure | PSRule for Azure + arm-ttk | Manual az deployment validate only | az validate catches syntax errors only; PSRule enforces best practices |
| API unit/integration | Vitest | Jest | Jest requires additional Babel/ESM config; Vitest is already in the workspace |
| API live endpoints | Bruno | Postman, Insomnia | Postman requires cloud account; Bruno is open-source and offline-first |
| Web components | Vitest + RTL | Cypress component testing | Cypress adds significant overhead for component tests; RTL is lighter |
| Browser-level | Playwright | Cypress E2E | Playwright is faster, cross-browser, and has better TypeScript support |
| PowerShell | Pester 5 | Manual execution only | Pester is the PowerShell standard; manual-only provides no repeatability |
| Secrets | Gitleaks | truffleHog | Both are good; Gitleaks is already integrated |
Consequences ​
Positive ​
- Every layer of the stack has a purpose-built tool that understands its language, format, and failure modes.
- Tools are independent — a developer can run only the layer relevant to what they changed.
- No single monolithic test run; faster feedback for targeted changes.
- Bruno collections serve as living API documentation alongside the tests.
- PSRule catches infrastructure drift from Azure best practices before it costs money or causes incidents.
Negative / trade-offs ​
- Multiple tools to install and maintain across the suite.
- Requires developer discipline — no automatic gate enforces that all tools are run before deployment.
- Bruno collections must be kept in sync with API route changes.
Risks ​
- Tool not run before deploy — mitigated by a pre-deployment checklist in the operations runbook that maps each change type to the tools that must pass.
- Mock drift in Vitest — if the Prisma schema changes and
setup.tsis not updated, unit tests pass against a stale mock. Mitigated by updatingsetup.tsas part of every schema migration. - PSRule false positives — some rules may not apply to this project's scale. A
.ps-rule/suppression file will be maintained to document intentional rule suppressions.
References ​
- AB#4415 — Build comprehensive automated test suite
- AB#4416 — API service unit tests (220+ tests, completed)
- AB#4417 — API controller/route tests
- AB#4418 — API integration tests
- AB#4419 — Web component tests
- AB#4420 — Shared package tests
- AB#4421 — E2E smoke tests (Playwright)
- ADR 0029 — CI/CD pipeline