CI
Lab fits CI best when test dependencies are explicit and output is easy to scan. Use --reporter=simple, wait for external services, and keep local fixture URLs reachable from the selected runtime.
Basic CI command
lab run tests/ --reporter=simple
The process exits with status 0 when all tests pass and status 1 when any test fails.
Wait for services
Use --wait for HTTP services that may start in parallel with the test job.
lab run tests/integration \ --wait=http://127.0.0.1:9222/json/version \ --wait-timeout=10 \ --wait-attempts=12 \ --reporter=simple
Waits happen before the runtime is created and before test files execute.
Retry unstable dependencies
Use --attempts for tests that can fail because a dependency is not fully settled even after a health check.
lab run tests/integration \ --attempts=3 \ --timeout=60 \ --reporter=simple
--attempts=3 allows up to three attempts total for a failing test.
Run in GitHub Actions
name: Lab
on:
pull_request:
jobs:
lab:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Lab
run: |
mkdir -p "$HOME/.ferret"
curl -fsSL https://raw.githubusercontent.com/MontFerret/lab/main/install.sh | sh
echo "$HOME/.ferret" >> "$GITHUB_PATH"
- name: Run Lab tests
run: |
lab run tests/ \
--reporter=simple \
--attempts=3 \
--timeout=60
Use a pinned VERSION in the install step when the pipeline must stay on a specific Lab release.
Run with Docker
The Docker image can run tests from a mounted directory:
docker run --rm -v "$PWD/tests:/test" montferret/lab:latest
To pass explicit flags, mount the workspace and call run:
docker run --rm -v "$PWD:/workspace" montferret/lab:latest \ run /workspace/tests \ --reporter=simple \ --attempts=3
The image entrypoint starts the bundled browser entrypoint before invoking Lab for Lab commands.
Serve local fixtures in CI
Use --serve for static fixtures and --mock for OpenAPI mock APIs:
lab run tests/e2e \ --serve ./dist@app \ --mock ./users.yaml@api \ --reporter=simple
Tests can read @lab.static.app and @lab.mock.api.
For the full local service syntax, see Static File Server and Mock API Server.
If the selected Ferret runtime runs outside the Lab process, make the fixture services reachable from that runtime:
lab run tests/e2e \ --runtime=https://ferret.example.com \ --serve ./dist@app \ --mock ./users.yaml@api \ --serve-bind 0.0.0.0 \ --serve-host host.docker.internal \ --reporter=simple
--serve-host controls the URLs passed to FQL. --serve-bind controls where Lab listens.
Keep output deterministic
For CI logs:
- Prefer
--reporter=simple. - Keep
--concurrencylow when tests share external state. - Use
--timesfor repeatability checks. - Use explicit aliases for
--serveand--mockso FQL reads stable parameter names.
Example:
lab run tests/smoke \ --concurrency=2 \ --times=3 \ --serve ./fixtures@fixtures \ --reporter=simple