Complete guide to installing, configuring, and using the QualityGraph CLI to analyze test coverage across your repositories.
node -vcurl -fsSL https://qualitygraph.harnessqa.dev/cli-dist/install.sh | bashThis downloads the CLI bundle and installs it to ~/.qualitygraph/bin/qg. It also adds the directory to your PATH in your shell config.
Reload your shell or source your config to use qg immediately:
source ~/.zshrc # or ~/.bashrcVerify it works:
qg --versionIf you prefer not to pipe curl to bash:
# Download the bundle
curl -o ~/.qualitygraph/bin/qg-bundle.js https://qualitygraph.harnessqa.dev/cli-dist/qg-bundle.js
mkdir -p ~/.qualitygraph/bin
# Create wrapper script
cat > ~/.qualitygraph/bin/qg <<'EOF'
#!/usr/bin/env node
require('./qg-bundle.js');
EOF
chmod +x ~/.qualitygraph/bin/qg
# Add to PATH
export PATH="$HOME/.qualitygraph/bin:$PATH"rm -rf ~/.qualitygraph
# Then remove the PATH line from your ~/.zshrc or ~/.bashrcYou need a QualityGraph account to upload analysis results. Create one at qualitygraph.harnessqa.dev/login or use the login command directly (it will register you automatically if you don't have an account).
qg login -e you@company.com -p your-passwordqg statusLogged in as: you@company.com Server: https://qualitygraph.harnessqa.dev
qg logoutSecurity: Your credentials are stored locally at ~/.qualitygraph/config.json with file permissions 0600 (owner read/write only). The JWT token expires after 7 days — re-run qg login to refresh.
Navigate to any git repository and run:
cd /path/to/your/project
qg analyzeThe CLI does two things. It scans the source tree, identifies test files, classifies them by layer (unit, API, integration, UI, E2E, contract) and estimates which production files have a test. And it looks for coverage reports a test run left behind (coverage/lcov.info, coverage.xml, jacoco.xml) and uploads those as measured coverage, with per-file and per-line detail. A measurement always outranks the estimate for its layer.
$ qg analyze
Analyzing myorg/backend-api...
Scanned 1,204 files
myorg/backend-api
────────────────────────────────────────────────────────────
Test Type Coverage Files Test Files Lines
────────────────────────────────────────────────────────────
UNIT 42.30% [████░░░░░░] 89/ 210 94 18240/ 43120
API 8.10% [█░░░░░░░░░] 17/ 210 12 3499/ 43120
INTEGRATION 3.33% [░░░░░░░░░░] 7/ 210 5 1438/ 43120
E2E 1.90% [░░░░░░░░░░] 4/ 210 8 820/ 43120
────────────────────────────────────────────────────────────
Coverage reports found (1):
lcov coverage/lcov.info (184.2 KB)
These measure what the tests ran; they replace the file-layout estimate for their layer.
Uploading to https://qualitygraph.harnessqa.dev...
Uploaded! Repository: a1b2c3d4-...
View at: https://qualitygraph.harnessqa.dev
Uploading coverage/lcov.info as UNIT coverage (lcov)... 71.4% of 43120 lines, 210 filesThe measured numbers come from your own test runner, so run it with coverage on before qg analyze:
npx jest --coverage # writes coverage/lcov.info
pytest --cov=src --cov-report=xml # writes coverage.xml
./gradlew test jacocoTestReport # writes build/reports/jacoco/test/jacocoTestReport.xml
qg analyzeReports are filed under the layer given by --report-type (default UNIT). To upload a specific file, or reports for several layers, use qg coverage upload:
qg coverage upload coverage/lcov.info --type UNIT
qg coverage upload reports/api-coverage.xml --type API --format cobertura
qg analyze --no-reports # estimate only, skip report discoveryRun the analysis without uploading results — useful for previewing before pushing, or for repos you don't want tracked:
qg analyze --localqg analyze -d /path/to/other-repoWithout a report, QualityGraph falls back to structural file-based analysis, shown as an estimate in the dashboard. It works by:
user.test.ts → user.ts, src/test/kotlin/…/FooTest.kt → src/main/kotlin/…/Foo.kt, spec/models/user_spec.rb → app/models/user.rb)IDE scaffolding such as ExampleUnitTest and test helpers under tests/fixtures are not counted as tests. The estimate is language-agnostic and needs no build step, but it only says which files have a test, not which lines ran. Upload a report to get the real number.
| Command | Description | Options |
|---|---|---|
qg login | Authenticate with QualityGraph | -e, --email (required)-p, --password (required)-s, --server (custom server URL) |
qg analyze | Scan repo and upload results | -d, --dir (repo path, default: .)--local (skip upload) |
qg coverage upload <file...> | Upload lcov.info, Cobertura or JaCoCo reports from a test run as measured coverage. Options: --type (layer, default UNIT), --format, --branch, --dir | -d, --dir (repo path, default: .)--local (skip upload) |
qg status | Show current login status | none |
qg logout | Clear stored credentials | none |
qg --version | Show CLI version | none |
qg --help | Show help | none |
The CLI identifies test files by their naming conventions and directory structure, then classifies them into five test types:
Default classification. Any test file that doesn't match a more specific pattern.
File patterns
.test.ts.test.js.spec.ts.spec.js_test.go_test.pytest_*.pyTest.javaSpec.java_test.rb_spec.rbTest.ktTests.csTests.swiftTest.phpDirectory patterns
__tests__/tests/test/spec/Tests that validate HTTP endpoints and API contracts.
File patterns
.api.test.ts.api.spec.ts.api.test.jsDirectory patterns
api-tests/api/tests/api/test/Tests that verify interactions between multiple components or services.
File patterns
.integration.test.ts.integration.spec.ts.int.test.ts.int.spec.tsDirectory patterns
integration/End-to-end tests using browser automation frameworks.
File patterns
.e2e.ts.e2e.js.e2e-spec.tsDirectory patterns
e2e/cypress/playwright/Consumer-driven contract tests (Pact, etc.).
File patterns
.contract.test.ts.contract.spec.ts.pact.test.ts.pact.spec.tsDirectory patterns
contract/pact/Ignored paths: The following are always excluded from analysis: node_modules/, dist/, build/, .git/, vendor/, coverage/, plus config files, lock files, assets, stylesheets, and documentation.
The CLI recognizes source and test files in the following languages:
TypeScript
.ts, .tsx
JavaScript
.js, .jsx
Python
.py
Go
.go
Java
.java
Kotlin
.kt
Ruby
.rb
Rust
.rs
C#
.cs
Swift
.swift
PHP
.php
C/C++
.c, .cpp, .h
All CLI configuration is stored in ~/.qualitygraph/config.json.
{
"server": "https://qualitygraph.harnessqa.dev",
"token": "eyJhbGciOiJIUzI1NiIs...",
"email": "you@company.com"
}~/.qualitygraph/ ├── bin/ │ ├── qg # CLI wrapper script │ └── qg-bundle.js # Bundled CLI (122KB) └── config.json # Auth credentials (mode 0600)
For self-hosted QualityGraph instances, pass the -s flag:
qg login -e you@company.com -p pass -s https://qg.internal.company.comRun QualityGraph analysis automatically in your CI pipeline to track coverage over time.
name: QualityGraph Analysis
on:
push:
branches: [main]
pull_request:
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install QualityGraph CLI
run: curl -fsSL https://qualitygraph.harnessqa.dev/cli-dist/install.sh | bash
- name: Login & analyze
run: |
export PATH="$HOME/.qualitygraph/bin:$PATH"
qg login -e ${{ secrets.QG_EMAIL }} -p ${{ secrets.QG_PASSWORD }}
qg analyzeTip: Store your QualityGraph credentials as repository secrets (QG_EMAIL and QG_PASSWORD) to keep them secure.
qualitygraph:
image: node:20
stage: test
script:
- curl -fsSL https://qualitygraph.harnessqa.dev/cli-dist/install.sh | bash
- export PATH="$HOME/.qualitygraph/bin:$PATH"
- qg login -e $QG_EMAIL -p $QG_PASSWORD
- qg analyze
only:
- mainYour PATH hasn't been updated yet. Either open a new terminal or run:
source ~/.zshrc # or ~/.bashrcThe CLI must be run inside a git repo. Make sure you're in the project root, or use the -d flag:
qg analyze -d /path/to/repoJWT tokens expire after 7 days. Re-authenticate:
qg login -e you@company.com -p your-passwordThe analyzer may not recognize your test naming convention. Check that your test files follow standard patterns like .test.ts, .spec.js, _test.go, etc. Run with --local to preview what's detected.
qg analyze --localYour token is invalid or expired. Log in again:
qg login -e you@company.com -p your-passwordNo. The CLI only uploads file paths and sizes — no file contents, no code, no secrets. The analysis is performed entirely on your machine.
The CLI currently supports email/password authentication. You can link your GitHub account by signing in on the web dashboard first, then using the same email for the CLI.
Traditional code coverage measures which lines of code are executed during tests (runtime analysis). QualityGraph measures structural test coverage — which production files have corresponding test files, across all test types. This gives a higher-level view of your test strategy across repositories.
Yes. Run qg analyze from the monorepo root and it will scan all subdirectories. The analyzer respects standard ignore patterns (node_modules, dist, build).
We recommend running it on every push to main via CI/CD. This gives you a continuous view of how your test coverage evolves over time.