Files
pj 8c8e87761d fix(folio-web): keep submit live for 400ms after saving
Defers the navigation back so the button is tappable while the label
reads Saved, widening the double-submit window the counting property
is there to catch.
2026-08-17 23:27:37 +05:30
..

Folio (web)

A React + Vite port of the folio personal-ledger app: login with demo credentials, create accounts, add credits and debits. Exists as the minimal web example sanderling runs its property-based specs against.

Stack

  • React 19 + Vite + TypeScript
  • Stable HTML id attributes on every interactive element so the spec targets DOM nodes by id, not by aria-label parsing
  • data-* attributes (data-cents, data-account-id, data-txn-count) carry structured numeric state for property assertions

Prerequisites

  • just
  • bun (installs the JS toolchain; the project uses bun.lock, not package-lock.json or pnpm-lock.yaml)
  • Chrome installed (sanderling drives it via CDP)
bun install

Demo credentials

email:    [email protected]
password: ledger123

Run a sanderling test

just test

The justfile boots the Vite dev server on port 5173, waits for the port to respond, then runs sanderling test --platform web --bundle-id http://localhost:5173 against it. Override the port with PORT=4000 just test; DURATION, SEED, and OUTPUT work the same way as in the KMP folio example.

Traces land in ./sanderling/runs/<timestamp>/.

How it connects to sanderling

  • The spec at sanderling/spec.ts finds elements by HTML id (#email, #add-account, #ledger, #txn-amount, ...). Anything the spec touches has a stable id in the markup.
  • Numeric state the spec asserts on is exposed via data-cents and similar attributes. The spec reads el.attrs["data-cents"] rather than parsing currency strings out of aria-label.
  • Account cards expose data-account-id + data-balance so the spec can correlate cards across steps without depending on DOM order.
  • just test invokes sanderling test --platform web, which connects to Chrome via the Chrome DevTools Protocol; no extension or app SDK is involved.