# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

A k6-based performance testing framework supporting both backend (GraphQL/REST API) and frontend (browser-based) load testing. Tests run inside Docker containers with AWS Secrets Manager integration for credentials, a background token caching service, and runtime GraphQL query fetching.

## Commands

```bash
# Lint
yarn lint

# Unit tests (Jest)
yarn unit-test

# Run a single test file
yarn jest unitTests/<filename>.spec.ts

# Compile framework scripts (TypeScript → JS, required before running tests)
yarn compile-framework

# Bundle a k6 test (TEST_FILE env var selects which test)
TEST_FILE=dx/digital-exchange-test yarn bundle

# Fetch user credentials from AWS Secrets Manager
make fetch_secret_files

# Fetch GraphQL queries from remote repos (requires GITHUB_TOKEN)
make fetch_gql_queries

# Start token fetcher service (background, caches OAuth tokens)
make start_token_fetcher

# Full local test cycle: clean → build image → run tests
make build_and_run_docker_k6_test

# Run k6 test in Docker (assumes image is already built)
make run_k6_test_in_docker

# Validate metrics against thresholds (reads K6_METRIC_THRESHOLDS env var)
make check_thresholds
```

## Architecture

### Test Execution Flow

```
1. make fetch_secret_files   → AWS Secrets Manager → src/variables/user-data.json
2. make fetch_gql_queries    → GitHub private repos → src/k6/graphqlQueries/
3. make start_token_fetcher  → Runs Express server on background; pre-fetches OAuth tokens
4. yarn compile-framework    → Compiles src/frameworkScripts/ TypeScript to JS
5. yarn bundle               → Webpack bundles src/k6/tests/{TEST_FILE} → k6Ready/testFile.bundle.js
6. k6 run k6Ready/testFile.bundle.js → Executes load test; writes reports/summary.json
7. make check_thresholds     → Validates summary.json metrics against K6_METRIC_THRESHOLDS
```

### Two Compilation Pipelines

The codebase has **two separate TypeScript compilation targets**:

1. **`src/frameworkScripts/`** → Compiled with `tsc` (`yarn compile-framework`) → Node.js scripts run directly
2. **`src/k6/`** → Bundled with Webpack (`yarn bundle`) → Single JS file for k6 runtime

These use separate `tsconfig.json` files and cannot be mixed. k6 code cannot use Node.js APIs; framework scripts cannot use k6 APIs.

### Webpack Module Aliases

Webpack defines aliases so k6 code uses bare import paths — not relative paths:

| Alias | Resolves to |
|---|---|
| `helpers` | `src/k6/helpers/` |
| `setup` | `src/k6/setup/` |
| `frontend` | `src/k6/frontend/` |
| `graphqlQueries` | `src/k6/graphqlQueries/` |
| `tests` | `src/k6/tests/` |

Example: `import { setupMetrics } from 'setup/setupMetrics'` — this is a webpack alias, not a node module.

### Test Types

**1. Hybrid tests** (abacus): Both backend (GraphQL via `createBackendScenario`) and frontend (browser via `createFrontendScenario`) run as separate named scenarios in the same file. Each exported function name must match the scenario key in `options.scenarios`.

**2. Generic API test** (`src/k6/tests/api.ts`): Entirely config-driven by `src/variables/endpoints/<BACKEND_SERVICE>.json`. Dynamically creates exported scenario functions at module init time using `exports[name] = fn`. Reads `BACKEND_SERVICE` and optionally `SCENARIO` (to run a single named scenario).

**3. Dedicated service tests** (e.g., `src/k6/tests/dx/digital-exchange-test.ts`): Similar to api.ts but hardcodes `appName = 'dx'` and does not require auth — uses public endpoints directly.

### Configuration-Driven API Tests

`src/variables/endpoints/<service>.json` describes a service: `baseUrl`, `slackChannel`, and `scenarios` (each with `stages`, `gracefulStop`, `endpoints`). A `username` field in a scenario pins it to a specific user instead of random selection. No TypeScript changes needed to add a new endpoint.

### Token Fetcher Service

A background Express server (`src/frameworkScripts/tokenFetcher/`) pre-fetches and caches Auth0 tokens before tests start. k6 tests call `getTokenFromFetcher()` to hit this local service instead of authenticating inline. Supports standard password grant and MFA (TOTP) flows — users with `totpSecret` in `user-data.json` trigger the MFA path automatically.

Auth0 client credentials are read from `src/variables/auth0-data.json` (not committed); keys follow the pattern `{application}_auth_client_id` and `{application}_auth_client_secret`.

### GraphQL Query Registration

GQL queries are fetched from private GitHub repos at runtime (not committed). The fetch config lives in `src/frameworkScripts/queryFetcher/gqlQueryFileLocations.json` — each entry maps a query name to a `repo` + `path`. To add a new query, add an entry there and re-run `make fetch_gql_queries`.

### Metrics Pattern

Tests register custom k6 `Trend` and `Counter` metrics in `src/k6/setup/setupMetrics.ts`. Metric names follow conventions like `gql_{queryName}_duration`, `frontend_journey_duration`. The `check_thresholds` Makefile target validates these against a JSON array in `K6_METRIC_THRESHOLDS`.

### Summary Output

Every test file exports a `handleSummary` function (via `buildSummary` helper) that writes:
- `reports/summary.txt` — plain-text k6 summary
- `reports/slackMessage.txt` / `reports/slackChannel.txt` — Slack notification content
- `reports/screenshots/` — browser test screenshots (auto-zipped post-run)

## Key Environment Variables

See `.env.shadow` for the full list. Essential ones:

| Variable | Description |
|---|---|
| `TEST_FILE` | Relative path under `src/k6/tests/` (e.g., `dx/digital-exchange-test`) |
| `BACKEND_SERVICE` | Service name for `api.ts`; selects `src/variables/endpoints/{name}.json` |
| `SCENARIO` | Optional: run a single named scenario within `api.ts` |
| `APP_URL` | Frontend URL for browser tests |
| `GRAPHQL_URL` | GraphQL endpoint |
| `K6_BACKEND_STAGE_1_VUS` / `_DURATION` | Load ramp-up configuration |
| `K6_BACKEND_STAGE_2_VUS` / `_DURATION` | Sustained load configuration |
| `K6_BACKEND_START_VUS` | Initial VU count before ramp-up (default 0) |
| `K6_GRACEFUL_STOP_DURATION` | Time allowed for VUs to finish after scenario ends |
| `K6_FRONTEND_VUS`, `_DURATION`, `_START_TIME` | Browser test configuration |
| `K6_METRIC_THRESHOLDS` | JSON array: `[{"key":"metric","metric":"avg","threshold":500}]` |
| `GITHUB_TOKEN` | For fetching GraphQL queries from private repos |
| `JOB_NAME` | When set, enables StatsD output to Datadog and tags metrics with pipeline name |

## Docker

Tests run in a custom Docker image built on `grafana/k6-with-browser` with a custom k6 binary that includes the `xk6-output-statsd` extension. The Dockerfile compiles framework scripts at build time. Use `make build_docker_image` to rebuild.

## CI/CD

Jenkins pipeline (Jenkinsfile) has two modes controlled by parameters:
- **Deploy mode** (`RUN_TESTS=false`): Builds and pushes Docker image to ECR (master branch only)
- **Test mode** (`RUN_TESTS=true`): Runs performance tests and validates thresholds

PR builds use `ci_run_PR_docker_k6_test` (builds image first); main branch test runs use `ci_run_docker_k6_test` (pulls latest image).
