User Guide
How to use the Snapline Hub web interface: dashboard, run history, uploads, run detail, and diff inspection.
Navigation
The sidebar is organized into clear sections:
| Page | Path | Purpose |
|---|---|---|
| Dashboard | / | Pass rate, recent runs, projects and tags overview |
| Test runs | /reports | Full history with search, quick filters, and advanced filters |
| Import report | /upload | Upload JSON manually with optional project and tags |
| Run detail | /reports/:id | Suite drill-down, step results, and diff viewer |
Dashboard
The dashboard shows aggregate metrics across all stored reports:
- Total runs — ingested
TestRunReportdocuments - Suites executed — sum of suite counts across runs
- Passed / failed — suite-level outcomes
- Pass rate — percentage of suites that passed
The Projects & tags section lists groupings from pushed metadata. Click any chip to open the test runs page with that filter applied.
Recent runs shows the latest reports with project, tags, framework, and result badges. Use View all for the full filterable list.
Test runs — search and filters
The test runs page is designed for finding specific reports quickly without bias toward any single filter.
Search bar
Search across label, project, framework, and tags. Input is debounced (300ms) so typing does not trigger excessive API calls.
Quick filters
One-click presets at the top:
| Preset | Effect |
|---|---|
| All runs | Clear filters |
| Node.js | Tag filter: node |
| Python | Tag filter: python |
| Failed only | Runs with at least one failed suite |
| Last 7 / 30 days | Date range from today backward |
Active filter chips
When filters are applied, chips appear below the search bar showing exactly what is active. Click a chip to remove that filter, or use Clear all.
Advanced filters
Expand Advanced filters for project, framework, status, date range, and tag selection. When multiple tags are selected, choose:
- Match any — runs with at least one selected tag (OR)
- Match all — runs that have every selected tag (AND)
Columns
| Column | Source |
|---|---|
| Run | label or truncated ID |
| Project | project metadata from push/upload |
| Tags | tags[] — click a tag to filter |
| Framework | report.framework |
| Passed / failed | summary.passed / summary.failed |
| Date | generatedAt |
Import report
Upload a TestRunReport JSON file when you are not pushing programmatically. Optionally set project and tags before upload — they are stored as searchable metadata.
Accepted format
The file must be a valid TestRunReport JSON object. Minimum required fields:
{
"generatedAt": "2026-07-07T10:00:00.000Z",
"framework": "@vaagatech/snapline-engine",
"summary": { "total": 1, "passed": 1, "failed": 0 },
"suites": [
{
"name": "My suite",
"passed": true,
"results": [{ "step": "api", "passed": true }]
}
]
}
How to upload
- Drag a
.jsonfile onto the drop zone, or click to open a file picker - Hub parses and validates the JSON
- On success, the label defaults to the filename (without
.json) - You are redirected to the run detail page
Common upload errors
| Error | Cause | Fix |
|---|---|---|
| Invalid JSON | File is not valid JSON | Validate with jq . file.json |
| Invalid TestRunReport | Missing generatedAt, framework, summary, or suites | Ensure file was produced by writeTestReport with format: 'json' |
| HTML file uploaded | Uploaded .html report instead of JSON | Use REPORT_FORMAT=json or convert is not supported — regenerate as JSON |
Run Detail
Each stored report has a unique UUID. The detail page shows:
Header
- Run label and framework name
- Generation timestamp
- Delete button — permanently removes the report from SQLite
Summary cards
Total suites, passed count, failed count, and duration (summary.durationMs).
Environment
If the report includes an environment object (set via buildReport meta), each key-value pair is displayed — e.g. baseUrl, reportFormat, suiteName, CI build IDs you add yourself.
Failures section
When any step failed, a highlighted Failures section appears at the top listing every failed step across all suites, with full diff blocks. This lets you diagnose issues without expanding each suite manually.
Suites
Each suite is a collapsible card:
- Suite name — from
TestSuiteResult.name - Step counts — total, passed, failed
- PASSED / FAILED badge
Failed suites are expanded by default. Passed suites are collapsed. Click the header to toggle.
Understanding step results
Each step in a suite maps to a TestStepResult:
| Field | Meaning |
|---|---|
step | Step or case identifier — e.g. auth, api, 01-pass-customer-account |
passed | Whether this step succeeded |
message | Human-readable outcome (optional) |
diff | Structured mismatch on failure (see below) |
processed | Live data after Snapline transforms (optional) |
source / target | Cross-system comparison sides (DB↔API, etc.) |
Fixture case semantics
For runApiFixtureCases / run_snapline_fixture_cases:
stepis the case directory name (e.g.04-fail-segment-mapping), not the human-readablenamefromcase.json- Cases with
expectMatch: falsepass when Snapline finds a mismatch — Hub shows them as passed steps - Auth failure cases (
expectStatus: 401) pass when HTTP 401 is returned
Diff viewer
When a step fails, Hub renders the Snapline DiffResult:
{
"path": "segment",
"actual": "premium",
"expected": "standard",
"message": "Value mismatch"
}
- path — dot-path to the first mismatch (depth-first). Nested fields use dots; array indices use brackets:
orders[0].status - actual — value from the live/processed side after transforms
- expected — value from the expected fixture after
ignoreFields - message — mismatch category:
Value mismatch,Type mismatch,Missing key, etc.
Labels
Labels help identify runs in the UI. Set them when pushing:
// Node.js
await pushTestReportToHub(report, { hubUrl: '...', label: 'CI build #4821' });
// Python
push_test_report_to_hub(report, hub_url='...', label='CI build #4821')
// Env
SNAPLINE_HUB_LABEL="nightly-$(date +%Y%m%d)" SNAPLINE_HUB_URL=... npm run demo
When uploading, the filename (without extension) becomes the label.
Deleting reports
On the run detail page, click Delete and confirm. This removes the report from SQLite permanently. There is no undo.
API equivalent: DELETE /api/reports/:id — see API Reference.