Skip to Content
Output & Integration

Output & Integration

LATdx is built to drop into existing tooling without surprises. The output streams follow a strict contract, JSON modes are stable, and the human-friendly live renderer disables itself automatically when piped or run under CI.

Stream Contract

The CLI separates payload from diagnostics on the two output streams:

StreamWhat’s on it
stdoutCommand result only. With --json, exactly one JSON document. Without --json, the human-formatted result.
stderrLogs (text or NDJSON), spinners, the live test renderer, --progress-events, and interactive prompts.

The two streams are never mixed. Pipes like latdx test run --json | jq work without any extra flags.

The CLI auto-degrades the stderr-side affordances (spinner, live renderer, color) when:

  • stdout is not a TTY,
  • CI is set to any non-empty value,
  • NO_COLOR is set,
  • TERM=dumb,
  • or --json is passed.

You can force the degraded mode with --plain. You can also force colors off explicitly with --no-color. There is no --live / --no-live toggle; the live renderer is automatic.

--json (Result Payload)

latdx test run --json and latdx test list --json emit exactly one JSON document on stdout. The test run envelope is drop-in compatible with sf apex test run --json:

{ "status": 0, "result": { "summary": { "outcome": "Passed", "testsRan": 12, "passing": 12, "failing": 0, "passRate": "100%", "failRate": "0%", "testStartTime": "2026-04-27T12:00:00.000Z", "testExecutionTime": "1500 ms", "testTotalTime": "1700 ms", "commandTime": "1900 ms", "hostname": "...", "orgId": "00D...", "username": "user@example.com", "userId": "005...", "testRunId": "" }, "tests": [ { "Id": "", "QueueItemId": "", "StackTrace": null, "Message": null, "AsyncApexJobId": "", "MethodName": "passes_simple", "Outcome": "Pass", "ApexClass": { "Id": "", "Name": "MyTestClass", "NamespacePrefix": "" }, "RunTime": 120, "FullName": "MyTestClass.passes_simple" } ] }, "warnings": [] }

Notes:

  • status is 0 on full pass, 1 if any test failed.
  • Outcome is Pass / Fail / Skip.
  • FullName is <ClassName>.<methodName> — same as sf.
  • Org-side identifiers LATdx cannot produce locally (Id, QueueItemId, AsyncApexJobId, ApexClass.Id, testRunId) are emitted as empty strings, matching sf’s behavior on local-only runs.
  • result.coverage is not yet populated; tracked as a follow-up.
  • --json implies --plain, so the live renderer and spinner stay off and stdout remains a single parseable document.

latdx test list --json returns a structured list of discovered methods on stdout instead of the human one-line-per-method format. Diagnostics still go to stderr.

--progress-events (Streaming NDJSON)

For programmatic consumers that want method-by-method progress without parsing the live renderer, pass --progress-events. Each event is one JSON object on stderr, newline-delimited:

// queued: discovery / scheduling { "event": "queued", "className": "MyTest", "methodName": "happy" } // start: batch began executing this method { "event": "start", "className": "MyTest", "methodName": "happy" } // complete (success): final state { "event": "complete", "className": "MyTest", "methodName": "happy", "status": "passed", "success": true } // complete (failure): includes errorMessage / message when available { "event": "complete", "className": "MyTest", "methodName": "boom", "status": "failed", "success": false, "errorMessage": "System.AssertException: ...", "message": "Assertion Failed: expected 1 was 2" }

Consumer rules:

  • Read line by line on stderr; ignore non-JSON lines (logger output may interleave when log level allows).
  • Dedupe by (className, methodName) for queued events: a packed batch failure causes the runner to re-enqueue remaining tests, which re-emits a queued event for each.
  • A method always ends with exactly one complete event per attempt.

--progress-events composes with --json: the JSON result still lands on stdout, and the NDJSON progress stream lands on stderr.

CI Recipes

latdx test run is non-interactive when CI=true or stdout is not a TTY: it never blocks on a confirmation prompt. The Delete all logs to continue? debug-log-storage prompt auto-accepts and retries. Set LATDX_AUTO_CONFIRM=true to also force auto-confirmation in interactive shells.

GitHub Actions

name: Apex Tests on: [push, pull_request] jobs: test: runs-on: ubuntu-latest env: CI: "true" NO_COLOR: "1" SF_AUTH_URL: ${{ secrets.SF_AUTH_URL }} steps: - uses: actions/checkout@v4 - name: Install Salesforce CLI run: npm install --global @salesforce/cli - name: Authenticate org run: | echo "$SF_AUTH_URL" | sf org login sfdx-url --sfdx-url-stdin --alias ci-org --set-default - name: Install LATdx run: curl -fsSL https://raw.githubusercontent.com/nebulity/latdx-cli/main/install.sh | bash - name: Verify org readiness run: latdx --version -o ci-org - name: Run tests run: latdx test run --json -o ci-org > test-result.json - name: Upload result if: always() uses: actions/upload-artifact@v4 with: name: latdx-test-result path: test-result.json

--json > file.json is the simplest way to capture results: stdout is a clean JSON document, while logs and progress remain on stderr (and in the Actions log).

Generic Shell

export CI=true latdx test run --json -o ci-org > test-result.json exit_code=$? jq '.result.summary | {outcome, passing, failing}' test-result.json exit $exit_code

--progress-events pairs naturally with custom dashboards or chat notifications:

latdx test run --json --progress-events -o ci-org > result.json 2> events.ndjson # tail -f events.ndjson | jq -c 'select(.event == "complete")'

Container Image

LATdx ships static binaries with no Node runtime. A minimal container only needs the binary plus sf and a CA bundle:

FROM debian:stable-slim RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates curl bash git && rm -rf /var/lib/apt/lists/* RUN npm install --global @salesforce/cli RUN curl -fsSL https://raw.githubusercontent.com/nebulity/latdx-cli/main/install.sh | bash ENV CI=true NO_COLOR=1 ENTRYPOINT ["latdx"]

Editor Integration

LATdx ships a VS Code extension (apps/extension) with the same engine as the CLI: in-editor coverage gutters, code-lens “Run / Debug” affordances on Apex test methods, and a sidebar showing live progress. CLI behavior and extension behavior are intentionally aligned, so both pick up the same ~/.latdx/ caches and the same managed-package version requirements.

The extension is distributed via the GitHub releases  for now; a Marketplace listing is planned.

When both the CLI and the extension are in use on the same workspace, they share the workspace daemon. Stopping the daemon (latdx daemon stop) affects both; running tests through either path warms the cache for the other.

Exit Codes

CodeMeaning
0Successful run / list / adapt path; all tests passed.
1Validation failure, runtime error, or one-or-more test failures.

latdx uninstall and latdx restore also exit 1 when class restoration fails. latdx --version -o <alias> exits 1 if the org package query fails. Prefer --json in CI: parse the envelope to distinguish “test failed” (status: 1, result.summary.failing > 0) from “engine failed” (no envelope, non-zero exit, log line on stderr).