STATUS: Design Stage
A local-first report viewer that scales from “drop a file” to “org-wide dashboard”:
scenetest/
├── .reports/
│ ├── 2026-01-25T103000-a762c2b-main.jsonl
│ ├── 2026-01-25T104512-f69279b-feat-checkout.jsonl
│ └── ...
├── scenes/
└── config.ts
Report naming: {timestamp}-{commit}-{branch}.jsonl
{"type":"meta","commit":"a762c2b","branch":"main","ts":"2026-01-25T10:30:00Z"}
{"type":"assertion","name":"cart.updates","status":"passed","ms":12,"actor":"alice","file":"src/Cart.tsx","line":42}
{"type":"assertion","name":"checkout.validates","status":"passed","ms":8,"actor":"bob","file":"src/Checkout.tsx","line":87}
{"type":"assertion","name":"payment.processes","status":"failed","ms":45,"actor":"alice","file":"src/Payment.tsx","line":23,"error":"timeout waiting for stripe"}
Reading:
const records = fs.readFileSync(file, 'utf8')
.trim().split('\n')
.map(line => JSON.parse(line))
Writing:
records.forEach(r => fs.appendFileSync(file, JSON.stringify(r) + '\n'))
For security, context objects are not saved to reports. Use the live dev panel to inspect context during development.
JSONL files for now. Simple glob to find all reports, load into memory, filter/sort in JS.
A future server version might store these in a database, but the filesystem is good enough for now.
The fullscreen viewer uses the small floating panel as a sidebar - like an email inbox view. List of assertions on the left, expanded detail view on the right.
┌──────────────────────┬─────────────────────────────────────────────┐
│ ✓ cart.updates 12 │ │
│ ✓ checkout.valid 8 │ checkout.validates │
│ ✗ payment.proc 45 │ │
│ │ Status: passed │
│ ───────────────── │ Duration: 8ms │
│ Run: main @ a762c2b │ Actor: bob │
│ 2026-01-25 10:30 │ Location: src/Checkout.tsx:87 │
│ │ │
└──────────────────────┴─────────────────────────────────────────────┘
Drag a JSONL file onto the page, instantly explore. Works offline, zero setup.
Scans scenetest/.reports/ directory, lists all reports with metadata, click to explore.
Side-by-side diff showing:
┌─────────────────────────────────┬─────────────────────────────────┐
│ main @ a762c2b │ feat/checkout @ f69279b │
├─────────────────────────────────┼─────────────────────────────────┤
│ ✓ cart.updates 12ms │ ✓ cart.updates 14ms │
│ ✓ checkout.validates 8ms │ ✗ checkout.validates 92ms ← │
│ │ ✓ checkout.applyCoupon 5ms + │
│ ✓ payment.processes 45ms │ ✓ payment.processes 43ms │
└─────────────────────────────────┴─────────────────────────────────┘
# .github/workflows/test.yml
- name: Run scenetest
run: pnpm scenetest run --report
- name: Upload report
uses: scenetest/upload-report@v1
with:
path: scenetest/.reports/
PR comment:
Scenetest Report for
feat/checkout@ f69279b23 assertions (22 passed, 1 failed)
Change Assertion Details Regression checkout.validates was 8ms/pass, now 92ms/fail New checkout.applyCoupon 5ms pass
For the hosted solution: