Skip to main content

Testing Strategy

Citadel employs a multi-layered testing strategy to ensure reliability across its microservices architecture, frontend applications, and critical user flows.

1. Unit Testing​

Unit tests focus on individual functions, classes, and modules in isolation.

Backend Services (Go)​

Each Go service includes a helper script scripts/test.sh that handles unit tests, integration tests, and coverage reporting.

  • Command: ./scripts/test.sh (within a service directory)
  • What it does: Runs go test with race detection, coverage profiles, and appropriate flags.

To run tests for a specific package from the root using Turbo:

# Test a specific package (e.g., iam-service)
pnpm -F iam-service test

# Lint a specific package
pnpm -F iam-service lint

Frontend Applications (React)​

  • Framework: Jest / Vitest + React Testing Library.
  • Command: pnpm -F <app-name> test (e.g., pnpm -F admin-portal-ui test).

2. End-to-End (E2E) Testing​

End-to-End tests verify the integrated system from the user's perspective. We use Playwright to simulate user interactions against a running environment.

Location​

All E2E tests are located in scripts/tests:

  • scripts/tests/ui/: UI-driven flows (login, registration).
  • scripts/tests/api/: Direct API calls to verify backend logic.

Running E2E Tests​

The scripts/e2e.sh script is the single entry point for running the test suite. It handles:

  1. Database Reset: Cleans the database to a known state.
  2. Service Startup: Boots up all services (IAM, Keycloak, Frontend, etc.).
  3. Test Execution: Runs Playwright.

Prerequisites​

  • Docker & Docker Compose running.
  • Node.js installed (pnpm install).
  • Playwright browsers installed: pnpm exec playwright install --with-deps.

Command​

./scripts/e2e.sh

Interactive Mode (UI)​

To debug tests or watch them execute:

./scripts/e2e.sh --ui

This opens the Playwright Inspector, allowing you to step through tests and view traces.

Writing New E2E Tests​

  1. Create a new .spec.ts file in scripts/tests/ui or scripts/tests/api.
  2. Use the test object from @playwright/test.
  3. Leverage helper functions in scripts/tests/utils for common tasks like generating random users or tokens.
import { test, expect } from '@playwright/test';

test('should allow user to login', async ({ page }) => {
await page.goto('http://localhost:5000');
await page.getByRole('button', { name: 'Login' }).click();
// ... interactions ...
await expect(page).toHaveURL(/dashboard/);
});