TestCo Docs
Dashboard

Quickstart: Run your first test suite

Install TestCo, point it at your repo, and see your first test results in the dashboard — no YAML guesswork, no CI pipeline required for the first run. Five minutes, start to finish.

Step 1: Install the CLI

Pick the install path for your platform. All four are first-class and stay in sync.

macOS (Homebrew)

Bash
brew install testco/tap/testco

Linux (apt)

Bash
echo "deb [signed-by=/usr/share/keyrings/testco.gpg] https://apt.testco.com stable main" | sudo tee /etc/apt/sources.list.d/testco.list
sudo apt update && sudo apt install testco

Linux (curl — any distro)

Bash
curl -fsSL https://cli.testco.com/install.sh | sh

Windows (PowerShell)

PowerShell
winget install TestCo.TestCoCLI

Verify the install:

Bash
testco version
# → testco 1.2.0 (commit abc123)

Step 2: Authenticate

Create an API key in the TestCo dashboard at Settings > API Keys and set it:

Bash
testco auth login
# Opens your browser — or paste your key manually:
testco auth set-key tc_key_abc123def456

Verify your auth:

Bash
testco auth whoami
# → Logged in as you@company.com — Project: my-project

Step 3: Run your first suite

From the root of your repository, run:

Bash
testco run

TestCo auto-detects common test frameworks (Jest, pytest, RSpec, Playwright, Cypress, Go test) and runs your default suite. You'll see live output:

Bash
testco run — scanning for test framework...
  Found jest@29.7.0 — running `npx jest`
  ✓ 47 passed  —  3 failed  —  0 flaky
  View results: https://app.testco.com/runs/run_xyz789
Tip

If TestCo doesn't find a framework, pass it explicitly: testco run --framework jest. See Configure a test suite for the full detection list.

Step 4: See your results

Open the URL printed after the run. The signal dashboard shows:

  • Pass rate — tests that passed.
  • Failures — tests that failed, with full output and stack traces.
  • Flaky flag — tests that passed on retry (auto-detected after 2+ runs).

No dashboard? Run testco open to open it in your browser.

Open the dashboard


What's next

Install & configure the CLI

Platform packages, auth token setup, and the defaults TestCo assumes until you add a CI pipeline.

Platform packages

The TestCo CLI is distributed through native package managers and a universal curl installer. Pick one — they are kept in lockstep with every release.

PlatformCommandNotes
macOSbrew install testco/tap/testcoHomebrew tap, auto-updates
Linux (apt)sudo apt install testcoDebian/Ubuntu repo
Linux (any)curl -fsSL https://cli.testco.com/install.sh | shDetects distro, installs to /usr/local/bin
Windowswinget install TestCo.TestCoCLIPowerShell or winget CLI

Authenticate

Create an API key at Settings > API Keys in the dashboard, then sign in:

Bash
testco auth login

For CI and headless environments, set the key from an environment variable instead of a browser flow:

Bash
export TESTCO_API_KEY=tc_key_abc123def456
testco auth whoami
Caution

Never commit your API key to source control. In CI, inject it from a secret — see the CI integration guide.

Pointing TestCo at CI

Until you wire TestCo into CI, runs are manual (testco run). The first CI integration page covers GitHub Actions and GitLab CI; the rest of the CI/CD Integration category handles CircleCI, Jenkins, and generic providers.

Connect your repository

Link a GitHub, GitLab, or Bitbucket repo so TestCo tracks every push and associates runs with branches and commits automatically.

OAuth connection

From the dashboard, open Settings > Repositories > Add repository and authorize the TestCo GitHub, GitLab, or Bitbucket app. TestCo requests read access to repository metadata and commit status only — it does not need write access to source.

Once connected, TestCo receives push webhooks and queues a run for each push to a tracked branch. The dashboard shows the repo, default branch, and last seen commit.

Manual webhook (self-hosted or restricted orgs)

If your org blocks OAuth apps, configure the webhook manually:

Bash
testco repo connect --owner myorg --repo my-service \
  --webhook-url https://api.testco.com/v1/hooks/push

After you connect

TestCo begins tracking immediately. The first push triggers a run; subsequent pushes on tracked branches queue automatically. See Branch and commit tracking for how runs are associated.

Your first CI integration

Run TestCo on every push and pull request. Two examples cover the common cases; the rest live in the CI/CD Integration category.

GitHub Actions

Add this reusable workflow as .github/workflows/testco-run.yml. Store your API key as a repository secret named TESTCO_API_KEY.

YAML · .github/workflows/testco-run.yml
name: TestCo — on push
on:
  push:
    branches: [main]
  pull_request:
jobs:
  testco:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: testco/action-run@v1
        with:
          api-key: ${{ secrets.TESTCO_API_KEY }}
          # Optional: suite identifier
          suite: unit-tests

GitLab CI

Add a job to your .gitlab-ci.yml. Define TESTCO_API_KEY as a CI/CD variable in your project settings.

YAML · .gitlab-ci.yml
testco-run:
  image: testco/cli:latest
  script:
    - testco run --suite integration-tests
  variables:
    TESTCO_API_KEY: $TESTCO_API_KEY
  artifacts:
    reports:
      junit: testco-report.xml

What's next

How TestCo works

Three pieces — the agent, the runner, and the signal layer — turn your existing test suite into a dashboard of useful signals without changing how you write tests.

Architecture overview

TestCo does not host your tests. It runs your existing test command in the environment you already use (your laptop, CI, or a TestCo runner) and reads the structured output to produce signals.

  • Agent — the testco CLI. Detects your framework, invokes your test command, and emits structured results.
  • Runner — where the command executes. In CI, that's the CI job; locally, it's your shell. TestCo also offers hosted runners for scheduled suites.
  • Signal layer — ingests results, computes pass/fail/flaky/degraded/timeout, and renders the dashboard.

TestCo reads JUnit XML, Jest JSON, pytest output, and Playwright reports natively. If your framework emits any of these, you do not need a custom adapter.

Data flow

  1. You run testco run (or a push triggers it).
  2. The agent detects the framework and invokes your test command.
  3. Results stream to TestCo and are associated with your branch and commit.
  4. The signal dashboard updates in near real time.

Continue with Suites, runs, and results for the data model, and The signal dashboard for the UI.

Suites, runs, and results

The core data model: a suite is a named test command; a run is one execution of it; a result is the outcome of a single test.

Suites

A suite binds a name to a test command, a framework, file paths, a timeout, retries, and environment. You define suites in .testco.yml at your repo root. One repo can hold many suites — see monorepos for multi-suite patterns.

FieldRequiredDescription
nameYesUnique identifier for the suite
frameworkYesjest, pytest, playwright, rspec, cypress, go, …
commandYesThe shell command TestCo invokes
pathsNoGlob patterns for the test files
timeoutNoMax duration, e.g. 10m
retriesNoAutomatic retries on failure
envNoEnvironment variables for the run

Runs

A run is a single execution of a suite. Each run has an id (run_xyz789), a status (queued, running, passed, failed, timed_out), and is pinned to a branch and commit. Runs are immutable once finished.

Results

A result is the outcome of one test: pass, fail, flaky, or skipped, with duration, output, and stack trace. TestCo rolls results up into run-level signals — see Test signals.

Branch and commit tracking

How TestCo associates each run with a branch and commit so you can compare signal across time and pinpoint regressions.

Automatic association

When TestCo runs inside a git checkout, the agent reads the current branch and HEAD commit from git and attaches them to the run. No configuration needed — testco run from a branch tags the run with that branch.

Explicit association

In CI where the checkout may be detached, pass the branch and commit explicitly:

Bash
testco run --branch "$CI_COMMIT_BRANCH" --commit "$CI_COMMIT_SHA"

Pinning a suite to a branch

You can restrict a suite so it only runs on specific branches. See Pin a suite to a branch for the full guide.

Test signals — what we surface

TestCo reduces a run to five signals. Each one is actionable, not decorative.

SignalMeaningWhat to do
PassTest passed on first attemptNothing — keep moving.
FailTest failed, including after retriesRead the trace; fix or quarantine.
FlakyPassed on retry after failing firstTrack frequency; see flaky detection.
DegradedPassed but slower than the rolling baselineProfile; check for regressions.
TimeoutExceeded the suite timeoutRaise the timeout or fix a hang.
Note

Flaky is computed over a history window — a single pass-on-retry is not enough. Configure the window under flaky: in .testco.yml.

The signal dashboard

The UI that turns runs into decisions. Every panel answers one question.

Overview panel

At the top: pass rate, failure count, flaky count, and the latest run's duration. Below it, a sparkline of pass rate over the last 30 runs so you can spot drift at a glance.

Run list

Each row is a run: suite, branch, commit (short SHA), signal counts, duration, and status. Click a row to open run details with full test output.

Filters

Filter by suite, branch, status, and signal. Saved views persist per user. Use the List runs API to pull the same data into your own tooling.

Configure a test suite

Define suites in .testco.yml at your repo root. One file, many suites, full control over timeouts, retries, and environment.

Basic structure

YAML · .testco.yml — project root
# .testco.yml — project root
version: 1
suites:
  - name: unit-tests
    framework: jest
    command: npx jest --ci --maxWorkers=4
    paths:
      - src/**/*.test.ts
    timeout: 10m
    retries: 2
    env:
      CI: "true"
      NODE_ENV: test

  - name: integration-tests
    framework: playwright
    command: npx playwright test
    paths:
      - tests/e2e/**
    timeout: 30m
    retries: 1
    env:
      BASE_URL: http://localhost:3000

  - name: api-tests
    framework: pytest
    command: pytest tests/api/ -v
    paths:
      - tests/api/**
    timeout: 15m
    retries: 0

Field reference

For the full field list and defaults, see CLI configuration. The most-tuned fields are timeout, retries, and env — set environment variables here rather than exporting them in CI so the suite is self-describing.

Environment variables

Sensitive values should come from environment variables referenced by name, not hard-coded. TestCo resolves env entries that look like $VAR from the surrounding environment at run time.

Pin a suite to a branch

Restrict a suite so it only runs on the branches that matter — keep main fast, run heavy e2e only on release branches.

Via the CLI

Bash · CLI branch pinning
# Pin a suite to a specific branch
testco config set suite.unit-tests.branch main

# Run only suites pinned to the current branch
testco run --pinned

# List pinned suites
testco config get suite.*.branch

Via .testco.yml

Set branch on a suite to restrict it. Omit the field to run the suite on all branches.

YAML
suites:
  - name: release-e2e
    framework: playwright
    command: npx playwright test
    branch: release/*
    timeout: 30m

Rerun a failed test

One-click rerun from the dashboard, or scripted rerun from the CLI. Both create a new run linked to the original.

From the dashboard

On any failed run, the Rerun failures button creates a new run that executes only the tests that failed in the original. The new run is linked to the source run in the timeline.

From the CLI

Bash · rerun commands
# Rerun all failed tests from the last run
testco rerun

# Rerun from a specific run
testco rerun run_xyz789

# Rerun a single test by name
testco rerun run_xyz789 --test "User API - creates new user"

For programmatic reruns, use the Rerun failed tests API.

Set up flaky-test detection

TestCo flags a test as flaky when it fails on the first attempt and passes on retry repeatedly within a history window. Tune the window and thresholds to match your tolerance.

Configuration

YAML · flaky detection in .testco.yml
# In .testco.yml under a suite
flaky:
  enabled: true
  # A test is flaky if it fails on the first run and passes on retry
  # at least N times in the last M runs
  history_window: 10        # last 10 runs
  fail_threshold: 3        # flagged after 3 failure-then-pass cycles
  retries_on_flaky: 2      # auto-retry flagged tests up to 2 times

Tuning

  • history_window — how many recent runs to consider. Lower for high-traffic repos, higher for stable ones.
  • fail_threshold — how many fail-then-pass cycles before flagging. 1 is noisy; 3 is the default.
  • retries_on_flaky — auto-retry count for already-flagged tests, to keep your suite green while you investigate.
Caution

If you see flaky flags on tests that consistently pass, your history_window may be too short — see Flaky-test false positives.

Manage team notifications

Route test signals to Slack, email, or a webhook. Subscribe per suite and per event so the right people see only what matters.

Slack webhook

Bash · Slack webhook setup
# Add a Slack webhook for test notifications
testco integrations add slack \
  --webhook https://hooks.slack.com/services/T00/B00/abc123 \
  --events failed,flaky

# Test the notification
testco integrations test slack

Email and generic webhooks

Replace slack with email or webhook and supply the matching destination. --events accepts any combination of failed, flaky, degraded, timeout, and passed.

Use TestCo with monorepos

Split a monorepo into independent suites with per-suite watch paths so a frontend change doesn't run backend tests.

Multi-suite strategy

YAML · monorepo .testco.yml
# .testco.yml in a monorepo root
version: 1
suites:
  - name: frontend-unit
    framework: jest
    command: cd frontend && npx jest
    paths:
      - frontend/**
    watch:
      - frontend/src/**
      - frontend/package.json

  - name: backend-unit
    framework: pytest
    command: cd backend && pytest
    paths:
      - backend/**
    watch:
      - backend/**/*.py
      - backend/requirements.txt

  - name: e2e
    framework: playwright
    command: npx playwright test
    paths:
      - e2e/**
    watch:
      - frontend/src/**
      - backend/src/**

The watch field tells TestCo which path changes should trigger a suite. A change to frontend/ runs frontend-unit and e2e, but not backend-unit.

GitHub Actions setup

Step-by-step YAML and a reusable workflow. Store your API key as a repository secret and reference it by name.

Reusable workflow

YAML · .github/workflows/testco-run.yml
name: TestCo — on push
on:
  push:
    branches: [main]
  pull_request:
jobs:
  testco:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: testco/action-run@v1
        with:
          api-key: ${{ secrets.TESTCO_API_KEY }}
          # Optional: suite identifier
          suite: unit-tests

Adding the secret

In your repo, go to Settings > Secrets and variables > Actions > New repository secret, name it TESTCO_API_KEY, and paste your key from the dashboard API keys page.

Note

The testco/action-run@v1 action checks out your repo, installs the CLI, runs the named suite, and uploads the report. You do not need a separate install step.

GitLab CI setup

Job definition, artifact handling, and passing the branch and commit so TestCo can associate the run.

Job definition

YAML · .gitlab-ci.yml
testco-run:
  image: testco/cli:latest
  script:
    - testco run --suite integration-tests
  variables:
    TESTCO_API_KEY: $TESTCO_API_KEY
  artifacts:
    reports:
      junit: testco-report.xml

Artifact handling

The artifacts.reports.junit entry makes the report downloadable from the GitLab job UI and keeps it for the job's retention window. For non-JUnit frameworks, point TestCo at the right report format with --report-path.

Branch and commit

The testco/cli image reads CI_COMMIT_BRANCH and CI_COMMIT_SHA automatically. For detached checkouts, pass them explicitly as shown in Branch and commit tracking.

CircleCI orb

Use the TestCo orb to add a run job in one line. Configure the API key as a CircleCI context environment variable.

Config example

YAML · .circleci/config.yml
version: 2.1
orbs:
  testco: testco/testco@1.2.0
jobs:
  build-test:
    docker:
      - image: cimg/node:20.14
    steps:
      - checkout
      - testco/run:
          suite: unit-tests
          api-key: TESTCO_API_KEY
workflows:
  testco-on-push:
    jobs:
      - build-test:
          context: testco

Orb parameters

ParameterRequiredDescription
suiteYesSuite name from .testco.yml
api-keyYesName of the env var holding the key
report-pathNoOverride the default report location

Jenkins pipeline

A declarative pipeline that installs the CLI, runs a suite, and archives the report. Inject the API key as a credentials binding.

Declarative pipeline

Groovy · Jenkinsfile
pipeline {
  agent any
  environment {
    TESTCO_API_KEY = credentials('testco-api-key')
  }
  stages {
    stage('TestCo') {
      steps {
        sh 'curl -fsSL https://cli.testco.com/install.sh | sh'
        sh 'testco run --suite unit-tests'
      }
      post {
        always {
          archiveArtifacts artifacts: 'testco-report.xml', allowEmptyArchive: true
        }
      }
    }
  }
}

Other CI (generic)

Any CI that can run a shell command and set an environment variable can drive TestCo. Install the CLI, set the key, run the suite.

Generic recipe

Bash · any CI
# 1. Install the CLI
curl -fsSL https://cli.testco.com/install.sh | sh

# 2. Set the API key (from your CI's secret store)
export TESTCO_API_KEY=$TESTCO_API_KEY

# 3. Run the suite
testco run --suite unit-tests

Reporting back to CI

Point TestCo at your report path and consume it in whatever your CI supports (JUnit, JSON, HTML). For programmatic control — trigger runs, poll status — use the REST API.

TestCo CLI commands

The testco CLI is the primary interface: run suites, check status, rerun failures, and manage configuration.

CommandDescription
testco runDetect the framework and run a suite
testco statusShow the latest run status for the current project
testco rerunRerun failed tests from the last or a specific run
testco configGet and set configuration values
testco authLogin, set a key, or show the current user
testco openOpen the dashboard for the current project
testco integrationsAdd and test Slack, email, and webhook integrations
testco repoConnect a repository and manage webhooks

Common examples

Bash
testco run --suite integration-tests --branch main
testco status --run run_xyz789
testco rerun run_xyz789 --test "User API - creates new user"

CLI configuration

The full .testco.yml spec. Every field, every default, in one place.

Top-level fields

FieldDefaultDescription
version1Config schema version
suitesList of suite definitions

Suite fields

FieldRequiredDefaultDescription
nameYesUnique suite identifier
frameworkYesautoTest framework
commandYesShell command to run
pathsNoTest file globs
timeoutNo10mMax duration
retriesNo0Retries on failure
envNoEnvironment variables
branchNoallRestrict to branch(es)
watchNoPaths that trigger the suite
flakyNodisabledFlaky detection config

Full example

YAML
version: 1
suites:
  - name: unit-tests
    framework: jest
    command: npx jest --ci
    paths: [src/**/*.test.ts]
    timeout: 10m
    retries: 2
    env:
      CI: "true"
    flaky:
      enabled: true
      history_window: 10
      fail_threshold: 3
      retries_on_flaky: 2

Environment variables

Override configuration and supply secrets without editing .testco.yml.

VariableRequiredDescription
TESTCO_API_KEYYesAPI key from the dashboard
TESTCO_PROJECTNoProject slug; defaults to the connected repo
TESTCO_API_URLNoOverride the API base URL (self-hosted)
TESTCO_CONFIGNoPath to a config file other than .testco.yml
TESTCO_LOG_LEVELNoerror, warn, info, debug
Danger

Treat TESTCO_API_KEY as a secret. Never echo it in logs or commit it. In CI, pull it from the provider's secret store.

REST API overview

The TestCo REST API exposes runs and suites over HTTPS with bearer-token auth and cursor pagination.

Base URL and auth

  • Base URL: https://api.testco.com/v1
  • Auth: Authorization: Bearer $TESTCO_API_KEY
  • Content type: application/json

Pagination

List endpoints use cursor pagination. Pass limit (default 20, max 100) and use the returned next_cursor to fetch the next page.

Errors

Errors use standard HTTP status codes with a JSON body: {"error": {"code": "not_found", "message": "..."}}. 401 means an invalid or missing key; 429 means you hit the rate limit — back off and retry.

List runs

GET /runs — list runs for the current project, with optional filters and cursor pagination.

Request

Bash
curl -s "https://api.testco.com/v1/runs?limit=10&status=failed" \
  -H "Authorization: Bearer $TESTCO_API_KEY"

Response

JSON
{
  "data": [
    {
      "id": "run_abc123",
      "status": "failed",
      "branch": "main",
      "passed": 44,
      "failed": 3,
      "flaky": 1,
      "created_at": "2026-07-17T09:15:00Z"
    }
  ],
  "pagination": {
    "next_cursor": "cursor_eyJpZCI6InJ1bl9hYmMxMjMifQ==",
    "has_more": true
  }
}

Get run details

GET /runs/{id} — fetch a single run, including its test-level results.

Request

Bash
curl -s "https://api.testco.com/v1/runs/run_xyz789" \
  -H "Authorization: Bearer $TESTCO_API_KEY"

Response

JSON
{
  "id": "run_xyz789",
  "status": "failed",
  "suite": "unit-tests",
  "branch": "main",
  "commit": "a1b2c3d4e5f6",
  "passed": 44,
  "failed": 3,
  "flaky": 1,
  "created_at": "2026-07-17T09:15:00Z",
  "results": [
    { "name": "User API - creates new user", "status": "failed", "duration_ms": 412 }
  ]
}

Trigger a run

POST /runs — start a new run for a suite. Returns the run id and a dashboard URL.

Request

Bash
curl -X POST https://api.testco.com/v1/runs \
  -H "Authorization: Bearer $TESTCO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "suite": "unit-tests",
    "branch": "main",
    "commit": "a1b2c3d4e5f6"
  }'

Response

JSON
{
  "id": "run_xyz789",
  "status": "queued",
  "suite": "unit-tests",
  "branch": "main",
  "created_at": "2026-07-17T10:30:00Z",
  "url": "https://app.testco.com/runs/run_xyz789"
}

Rerun failed tests

POST /runs/{id}/rerun — create a new run that re-executes only the tests that failed in the source run.

Request

Bash
curl -X POST https://api.testco.com/v1/runs/run_xyz789/rerun \
  -H "Authorization: Bearer $TESTCO_API_KEY" \
  -H "Content-Type: application/json"

Response

JSON
{
  "id": "run_xyz987",
  "status": "queued",
  "source_run": "run_xyz789",
  "url": "https://app.testco.com/runs/run_xyz987"
}

List suites

GET /suites — list the suites defined in the current project's .testco.yml.

Request

Bash
curl -s "https://api.testco.com/v1/suites" \
  -H "Authorization: Bearer $TESTCO_API_KEY"

Response

JSON
{
  "data": [
    { "name": "unit-tests", "framework": "jest", "timeout": "10m" },
    { "name": "integration-tests", "framework": "playwright", "timeout": "30m" }
  ]
}

Common setup errors

Auth failures, network issues, and rate limits — and the one fix that clears each.

ErrorCauseFix
401 UnauthorizedMissing or invalid API keyRe-run testco auth login or set TESTCO_API_KEY. See Installation.
Connection refusedNetwork or proxy blocking the APIAllow egress to api.testco.com:443; set HTTPS_PROXY if behind a corporate proxy.
429 Too Many RequestsRate limit exceededBack off exponentially; reduce poll frequency.
Project not foundWrong project slugSet TESTCO_PROJECT to the slug shown in the dashboard.
Caution

If testco auth whoami succeeds but runs fail with 401, the key has been rotated. Generate a new one in Settings > API Keys and update your CI secret.

Tests not appearing

You ran testco run but the dashboard shows no tests. Almost always a config mismatch or a runner issue.

Checklist

  1. Suite name matches. The --suite value must match a name in .testco.yml.
  2. Paths resolve. Globs in paths are relative to the repo root. Run testco config validate to check.
  3. Framework detected. If auto-detection fails, pass --framework explicitly.
  4. Command exits 0 on success. A non-zero exit that isn't a test failure can swallow results. Check the run log.

Flaky-test false positives

TestCo flags a test as flaky, but it consistently passes in your local runs. Tune the detection thresholds.

Common causes

  • History window too short — a single transient failure flips the flag. Raise history_window.
  • Fail threshold too lowfail_threshold: 1 flags on a single fail-then-pass. The default is 3.
  • Genuine environmental flakiness — order-dependent tests or shared state. Run with --randomize to confirm.

Adjusting thresholds

See Set up flaky-test detection for the full config reference. Start from the defaults and widen the window before lowering the threshold.

Contact support

Three channels, ranked by speed. Include your run id and project slug for the fastest resolution.

ChannelBest forResponse
In-app chatQuick questions, config helpMinutes during business hours
Email — support@testco.comReproducible issues with logsWithin one business day
Status page — status.testco.comIncidents and uptimeReal-time
Note

Attach the run id (e.g. run_xyz789) and your project slug. Both are visible in the dashboard URL.