docs: add comprehensive test behavior documentation for all pages
Add behavior documentation covering all SSR and legacy SPA pages: - Testing strategy and type definitions (unit/integration/UI) - Dashboard, Invoice, Payment, Transaction, Ledger pages - Company/Settings, POS, Admin, Search, Auth pages - Legacy SPA behavior docs (no UI tests until migrated) - Edge cases, test data requirements, and dependencies per subsystem Total: 3,600+ lines of behavior documentation to guide test authorship.
This commit is contained in:
175
docs/testing/behaviors/dashboard.md
Normal file
175
docs/testing/behaviors/dashboard.md
Normal file
@@ -0,0 +1,175 @@
|
||||
# Dashboard Behaviors
|
||||
|
||||
## Overview
|
||||
|
||||
The Dashboard is an admin-only, SSR-based overview page that displays financial summary cards across selected clients. It provides at-a-glance visibility into bank account balances, outstanding tasks, recent sales trends, expense breakdowns, and profit/loss summaries. Cards are loaded lazily via HTMX for progressive rendering.
|
||||
|
||||
## Routes
|
||||
|
||||
| Route | Handler | Purpose |
|
||||
|-------|---------|---------|
|
||||
| `GET /` | `::page` | Main dashboard page with stub cards |
|
||||
| `GET /expense-card` | `::expense-card` | Expense pie chart (top 5 accounts, last month) |
|
||||
| `GET /pnl-card` | `::pnl-card` | Profit & Loss bar chart (last month) |
|
||||
| `GET /sales-card` | `::sales-card` | Gross sales bar chart (last 14 days) |
|
||||
| `GET /bank-accounts-card` | `::bank-accounts-card` | Bank account balances and sync status |
|
||||
| `GET /tasks-card` | `::tasks-card` | Unpaid invoices and uncategorized transactions |
|
||||
|
||||
## Behaviors
|
||||
|
||||
### Unit Test Behaviors
|
||||
|
||||
- `extract-client-ids` returns intersection of user's allowed clients and requested clients
|
||||
- `is-admin?` returns true only when `user/role` equals `"admin"`
|
||||
- Client trimming takes only first 20 clients from the valid set
|
||||
- `clients-trimmed?` is true when the count of trimmed clients differs from valid clients
|
||||
- Bank account card excludes accounts with `bank-account-type/cash`
|
||||
- Bank account card displays ledger balance formatted as `$X,XXX.XX`
|
||||
- Bank account card shows sync timestamp in `standard-time` format when present
|
||||
- Sales chart queries use ISO date range from 14 days ago to tomorrow
|
||||
- Expense pie chart queries use date range from 1 month ago to tomorrow
|
||||
- P&L card aggregates accounts into `:sales` and `:cogs :payroll :controllable :fixed-overhead :ownership-controllable` categories
|
||||
- Tasks card queries invoices with `invoice-status/unpaid` and transactions with `transaction-approval-status/requires-feedback`
|
||||
- Tasks card only renders task sections when counts are non-zero
|
||||
|
||||
### Integration Test Behaviors
|
||||
|
||||
- Main page `GET /` returns 200 with base layout and 6 stub cards for admin users
|
||||
- Each card endpoint returns 200 with HTML response containing chart canvas or data
|
||||
- Bank accounts card performs Datomic pull for each client's bank accounts with nested Intuit/Yodlee/Plaid data
|
||||
- Sales card executes Datomic query summing `sales-order/total` by ISO date
|
||||
- Expense card executes Datomic query summing `invoice-expense-account/amount` by account name
|
||||
- P&L card calls GraphQL `get-profit-and-loss-raw` with trimmed client IDs and last-month date range
|
||||
- Tasks card executes two separate Datomic queries for unpaid invoices and uncategorized transactions
|
||||
- Expense breakdown card (from `company/reports/expense`) executes query with optional vendor and account filters
|
||||
- All card endpoints apply `wrap-trim-clients` and `wrap-admin` middleware
|
||||
- Non-admin requests to any dashboard route receive 302 redirect to `/login`
|
||||
- Unauthenticated requests receive 302 redirect to `/login` with `redirect-to` parameter
|
||||
|
||||
### UI Test Behaviors (SSR)
|
||||
|
||||
#### Happy Path: Dashboard Loads Successfully
|
||||
1. Admin user navigates to `/`
|
||||
2. Page renders with main navigation, client selector, and breadcrumb "Dashboard"
|
||||
3. Six stub cards appear with loading spinners:
|
||||
- Expenses (pie chart)
|
||||
- Tasks
|
||||
- Bank Accounts (tall card, row-span-2)
|
||||
- Gross Sales, last 14 days (bar chart)
|
||||
- Profit and Loss, last month (horizontal bar chart)
|
||||
- Expense breakdown (bar chart, wide card)
|
||||
4. Each stub card triggers `hx-get` on load to fetch its content
|
||||
5. Cards progressively render with actual data
|
||||
6. User sees bank account balances, task counts, sales chart, expense charts, and P&L summary
|
||||
|
||||
#### Card Interactions
|
||||
- Bank Accounts card displays each client's name, account name, ledger balance, and last sync time
|
||||
- When a bank account has Intuit/Yodlee/Plaid sync, the external balance and sync time display alongside the ledger balance
|
||||
- Yodlee accounts additionally show "Pending Txs" with pending balance
|
||||
- Tasks card shows "Pay now" link for unpaid invoices (links to unpaid invoices page with `date-range=year`)
|
||||
- Tasks card shows "Review now" link for uncategorized transactions (links to requires-feedback transactions page)
|
||||
- Expense breakdown card has Vendor and Account typeahead filters
|
||||
- Changing Vendor or Account filter triggers HTMX request to reload the breakdown chart with filtered data
|
||||
- Expense breakdown chart updates URL via `hx-push-url` with query params
|
||||
|
||||
#### Client Selection Effects
|
||||
- User selects different clients from the client dropdown
|
||||
- Page triggers `clientSelected` event on body
|
||||
- HTMX swaps `#app-contents` with fresh dashboard content for newly selected clients
|
||||
- All cards re-fetch with new client context
|
||||
- If more than 20 clients selected, a yellow warning banner appears: "Warning: These reports are only for twenty of the selected customers. Please select a specific customer to see more detail."
|
||||
|
||||
## Edge Cases
|
||||
|
||||
### No Clients Selected
|
||||
- Dashboard page renders but all cards show empty state
|
||||
- Bank Accounts card renders empty list
|
||||
- Sales chart shows empty bar chart with no data points
|
||||
- Expense pie chart shows empty pie chart
|
||||
- P&L card shows zero income and expenses
|
||||
- Tasks card shows no task notifications (sections hidden when count is zero)
|
||||
|
||||
### Many Clients (Trimming Warning)
|
||||
- When user has access to more than 20 clients and selects all, only first 20 are used
|
||||
- Yellow warning banner displays below breadcrumb
|
||||
- All card queries execute against trimmed client set only
|
||||
- Warning persists across client selection changes until fewer than 21 clients selected
|
||||
|
||||
### No Data for Date Ranges
|
||||
- Sales chart (14-day window): Empty chart renders with no bars when no sales orders exist
|
||||
- Expense pie chart (last month): Empty pie chart renders when no invoices with expense accounts exist
|
||||
- P&L card: Shows `$0.00` for both income and expenses
|
||||
- Tasks card: No task sections render (conditional on non-zero counts)
|
||||
- Bank Accounts: Accounts still display with zero/null balances if they exist but have no transactions
|
||||
|
||||
### Error Loading Individual Cards
|
||||
- Each card loads independently via separate HTMX request
|
||||
- Failure in one card endpoint does not prevent other cards from loading
|
||||
- Stub card shows spinner until successful response or timeout
|
||||
- Server errors in card endpoints return appropriate HTTP status without breaking page layout
|
||||
|
||||
### Permissions (Admin vs User)
|
||||
- Only users with `user/role = "admin"` can access dashboard routes
|
||||
- Non-admin authenticated users receive 302 redirect to `/login`
|
||||
- Unauthenticated users receive 302 redirect to `/login` with `redirect-to` parameter
|
||||
- Admin role is verified by `wrap-admin` middleware before any data queries execute
|
||||
|
||||
### Bank Account Sync States
|
||||
- Account with no external sync (Intuit/Yodlee/Plaid): Shows only ledger balance and sync time
|
||||
- Account with Intuit sync: Shows Intuit balance and last synced timestamp
|
||||
- Account with Yodlee sync: Shows available balance, last synced timestamp, and pending balance
|
||||
- Account with Plaid sync: Shows Plaid balance and last synced timestamp
|
||||
- Missing/null balances display as `$0.00`
|
||||
|
||||
## Test Data Requirements
|
||||
|
||||
### Users
|
||||
- Admin user (`:user/role "admin"`) with access to multiple clients
|
||||
- Non-admin user (`:user/role "user"`) to test permission denial
|
||||
|
||||
### Clients (minimum 2, ideally 25+)
|
||||
- Client with `client/name` and at least one bank account
|
||||
- Mix of clients with Intuit, Yodlee, and Plaid synced accounts
|
||||
- Client with `:bank-account-type/cash` account (should be excluded from display)
|
||||
|
||||
### Bank Accounts
|
||||
- Bank account with `:bank-account/current-balance` and `:bank-account/current-balance-synced`
|
||||
- Bank account linked to Intuit (`:bank-account/intuit-bank-account`)
|
||||
- Bank account linked to Yodlee (`:bank-account/yodlee-account` with available + pending balance)
|
||||
- Bank account linked to Plaid (`:bank-account/plaid-account`)
|
||||
|
||||
### Sales Orders
|
||||
- Sales orders dated within last 14 days with `:sales-order/total`
|
||||
- Sales orders dated outside 14-day window (should not appear)
|
||||
|
||||
### Invoices
|
||||
- Invoices with `:invoice/expense-accounts` (with `:invoice-expense-account/amount` and `:account/name`) within last month
|
||||
- Invoices with `:invoice/status :invoice-status/unpaid` within last year
|
||||
- Invoices with `:invoice/outstanding-balance`
|
||||
- Voided invoices (should be excluded from expense breakdown)
|
||||
|
||||
### Transactions
|
||||
- Transactions with `:transaction/approval-status :transaction-approval-status/requires-feedback` within last year
|
||||
- Transactions with `:transaction/amount`
|
||||
|
||||
### P&L Data
|
||||
- Chart of accounts with categories `:sales`, `:cogs`, `:payroll`, `:controllable`, `:fixed-overhead`, `:ownership-controllable`
|
||||
- Account balances within last month for selected clients
|
||||
|
||||
## Dependencies
|
||||
|
||||
### External Services
|
||||
- **Datomic**: All card data queried from Datomic database
|
||||
- **GraphQL endpoint**: P&L card calls `get-profit-and-loss-raw` (Lacinia GraphQL)
|
||||
- **Intuit/Yodlee/Plaid**: Bank account sync data for external balances (data stored in Datomic)
|
||||
|
||||
### Frontend Libraries
|
||||
- **HTMX**: Progressive card loading via `hx-get`/`hx-trigger`/`hx-swap`
|
||||
- **Chart.js**: Canvas-based chart rendering (bar, pie, horizontal bar charts)
|
||||
- **Alpine.js**: Chart data binding via `x-data`/`x-init` attributes
|
||||
|
||||
### Middleware Stack
|
||||
- `wrap-admin`: Enforces admin-only access
|
||||
- `wrap-client-redirect-unauthenticated`: Handles auth redirects
|
||||
- `wrap-trim-clients`: Limits client scope to 20
|
||||
- `wrap-hydrate-clients`: Populates client data in request
|
||||
Reference in New Issue
Block a user