Files
soleprint/soleprint/station/tools/tester
2026-08-10 03:23:30 -03:00
..
2026-01-20 05:31:26 -03:00
2026-01-20 05:31:26 -03:00
2026-08-10 03:23:30 -03:00
2026-01-20 05:31:26 -03:00
2026-04-12 05:50:08 -03:00
2026-08-10 03:23:30 -03:00
2026-01-20 05:31:26 -03:00
2026-08-10 03:23:30 -03:00
2026-01-20 05:31:26 -03:00
2026-04-12 05:50:08 -03:00
2026-04-12 03:07:25 -03:00
2026-08-10 03:23:30 -03:00
2026-04-12 03:07:25 -03:00
2026-01-20 05:31:26 -03:00
2026-01-20 05:31:26 -03:00
2026-04-12 05:50:08 -03:00
2026-01-20 05:31:26 -03:00
2026-04-12 03:07:25 -03:00
2026-01-20 05:31:26 -03:00
2026-08-10 03:23:30 -03:00
2026-01-20 05:31:26 -03:00

Tester — HTTP Contract Test Runner

Discovers and runs contract tests against any environment, with a web UI for visibility.

Test DefinitionsTester (Runner + UI)Target API

Quick Start

CONTRACT_TEST_URL=http://localhost:8000 python -m tester run
python -m tester discover        # list what was found

# In a built instance, the UI is mounted by the hub:
#   http://localhost:12000/tools/tester

Where tests live

No test bodies are committed to core. The tool ships the base class, the runner and the UI. Tests belong to a room:

cfg/<room>/soleprint/station/tools/tester/tests/

They are merged into the built instance and discovered from tests/ there.

See tests/test_template.py — an intentionally empty test file whose docstring covers the execution modes, environment targeting, the ContractTestCase surface, and a worked example.

Keeping tests in the room rather than the runner means they version alongside the API they describe, and the runner stays reusable across projects.

Layout

tester/
├── base.py              # ContractTestCase — httpx + stdlib unittest
├── core.py              # discovery & execution
├── cli.py               # python -m tester [discover|run]
├── config.py            # .env + environment overrides
├── api.py               # FastAPI routes
├── environments.json    # named targets
├── templates/           # web UI
├── gherkin/             # optional feature/scenario metadata mapping
├── playwright/          # browser adapter (scaffolded; see the template)
└── tests/
    ├── base.py
    ├── test_template.py # start here
    └── example/         # fallback health check, runs with no room config

Configuration

Single environment (.env)

CONTRACT_TEST_URL=https://api.example.com
CONTRACT_TEST_API_KEY=your-api-key-here

Multiple environments (environments.json)

Same suite, many targets — this is the point of the tool.

[
  {
    "id": "local",
    "name": "Local",
    "url": "http://localhost:8000",
    "api_key": "",
    "description": "Local development server",
    "default": true
  },
  {
    "id": "stage",
    "name": "Staging",
    "url": "https://stage.example.com",
    "api_key": "stage-token-here",
    "description": "Staging environment"
  }
]

Selection is available in the UI header and persists via localStorage. Tokens are per-environment; keep real ones in a room's gitignored config, never here.

See the template for every CONTRACT_TEST_* variable.

API

GET  /tools/tester/                        # Runner UI
GET  /tools/tester/filters                 # Filters UI
GET  /tools/tester/api/tests               # List all tests
GET  /tools/tester/api/tests/tree          # Tests grouped as a tree
GET  /tools/tester/api/environments        # List environments
POST /tools/tester/api/environment/select  # Switch environment
POST /tools/tester/api/run                 # Start test run
GET  /tools/tester/api/run/{run_id}        # Run status (polling)
GET  /tools/tester/api/runs                # List all runs
GET  /tools/tester/api/features            # Gherkin features
POST /tools/tester/api/features/sync       # Sync feature files

URL parameters

The runner accepts deep links:

/tools/tester/?run=abc123&modules=customers&search=invoice
  • run — auto-load results for this run ID
  • domains / modules — comma-separated filters
  • search — search term for test names
  • statuspassed,failed,skipped

Why this design

Tests scattered across repos give no visibility and are hard to demonstrate. Keeping definitions with the API while the runner stays generic means the suite evolves with the code, non-developers can run it from the UI, and the same tests prove the contract in every environment you can point them at.