Files
bank/app/dash/e2e/dashboard.spec.ts
zeekayandHanzo Dev 1bed68b1ad bank: close the chain-boundary honesty gaps from the ultracode audit (v1.6.0)
The visual swarm confirmed the sandbox + testnet crypto loop is
genuinely live end-to-end (12/12 Playwright specs, 12 screenshots)
over a real double-entry ledger — and flagged that the chain boundary
is simulated and mislabeled. Fixes:

- Live-mode crypto send now 503s ("on-chain send unavailable") instead
  of debiting the ledger against a random txHash that is never
  broadcast — the same discipline the exchange applies without forexd.
  The faucet was already sandbox-gated; send was not.
- Network label is derived from mode via networkName() (lux-testnet /
  lux-mainnet), not hardcoded; the wallet and crypto-prices responses
  report sandbox: Sandbox() instead of a literal true, so a production
  deploy can no longer report itself as testnet.
- getMonthlyVolume normalizes to USD cents (was summing raw minor
  units, letting crypto micro-units inflate volume ~10^4x and grant
  the fee discount by accident) — matching the limit/AML fix.
- Transaction history carries txHash + network from metadata, so the
  activity feed can render a send's hash, not just the live response.
- Wallet drops the false "Non-custodial" label (the sandbox wallet is
  custodial with an unspendable display address).

Also lands the swarm's visual e2e suite (crypto-loop, dashboard,
exchange specs + screenshots on every flow) and the agent's fix to
Exchange.tsx, where the convert confirmation was wiped on the same
tick it was set — a customer never saw "Converted X to Y".

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-21 14:11:51 -07:00

22 lines
771 B
TypeScript

import { test, expect } from '@playwright/test'
import { signIn, shot } from './demo'
test('the dashboard opens on balances and activity', async ({ page }) => {
await signIn(page)
await expect(page.getByText(/Welcome back/)).toBeVisible()
const balances = page.getByRole('heading', { name: 'Balances' })
await expect(balances).toBeVisible()
const usd = page.locator('section').filter({ has: balances }).getByText('USD', { exact: true })
await expect(usd).toBeVisible()
await expect(page.getByRole('heading', { name: 'Recent activity' })).toBeVisible()
for (const action of ['Send', 'Exchange', 'Crypto', 'Cards']) {
await expect(page.getByRole('link', { name: action, exact: true }).first()).toBeVisible()
}
await shot(page, 'dashboard')
})