Skip to main content
Spawn the decipher-qa CLI as a subprocess and parse its final result block. Below is a copy-pasteable reference implementation.
This is boilerplate — a thin wrapper around the CLI to get you started. Fork it, rename the functions, add retry logic, wire it into pytest fixtures, emit your own telemetry — whatever fits your pipeline. The CLI is the contract; the wrapper is just convenience.

The Runner

The CLI prints a final === RESULT === block with the run summary as JSON. The runner spawns the process, streams its output, and parses that block on exit. decipher_qa_runner.py
import json
import re
import subprocess
import sys
from dataclasses import dataclass
from typing import Literal, Optional

TestRunStatus = Literal["passed", "failed", "failed_internal"]

_ANSI_RE = re.compile(r"\x1b\[[0-9;]*m")
_RESULT_MARKER = "=== RESULT ==="


@dataclass
class RunTestResult:
    status: TestRunStatus
    duration: int  # milliseconds
    run_id: int
    run_url: str


def run_decipher_qa_test(
    test_id: int,
    *,
    cdp_url: Optional[str] = None,
    headful: bool = False,
    origin: Optional[str] = None,
    stream: bool = True,
) -> RunTestResult:
    args = ["decipher-qa", "test", "run-cdp", "--testId", str(test_id)]
    if cdp_url:
        args += ["--cdp", cdp_url]
    if headful:
        args.append("--headful")
    if origin:
        args += ["--origin", origin]

    process = subprocess.Popen(
        args,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        text=True,
        bufsize=1,
    )

    captured: list[str] = []
    assert process.stdout is not None
    for line in process.stdout:
        if stream:
            sys.stdout.write(line)
            sys.stdout.flush()
        captured.append(line)

    process.wait()

    clean = _ANSI_RE.sub("", "".join(captured))
    marker = clean.rfind(_RESULT_MARKER)
    if marker == -1:
        raise RuntimeError("decipher-qa exited without a result block")

    payload = clean[marker + len(_RESULT_MARKER) :].strip()
    data = json.loads(payload)
    return RunTestResult(
        status=data["status"],
        duration=data["duration"],
        run_id=data["runId"],
        run_url=data["runUrl"],
    )

Example Script

Here’s a self-contained script that runs test 1522 against a local headful Chromium and logs the result. Swap in your own test_id and options:
from decipher_qa_runner import run_decipher_qa_test

def main() -> None:
    result = run_decipher_qa_test(
        test_id=1522,
        headful=True,
        origin="https://staging.myapp.com",
        stream=True,
    )

    print("\n=== RESULT ===")
    print(result)

    if result.status != "passed":
        raise SystemExit(1)

if __name__ == "__main__":
    main()

Usage

python run_test.py
You’ll get a streaming view of the run followed by the parsed result:
RunTestResult(status='passed', duration=127000, run_id=48291, run_url='https://app.getdecipher.com/tests/1522/runs/48291')
The process exits 0 on pass and 1 on fail, so it slots into any CI pipeline that already expects conventional exit codes.
Need help? Contact our support team.