Files
integreat/docs/testing/behaviors/search-indicators.md
Bryce b499d460f3 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.
2026-05-04 12:15:20 -07:00

7.6 KiB

Search & Indicators Behaviors

Overview

The Search subsystem provides a global full-text search dialog accessible from the main navigation bar. It queries a Solr index of invoices, payments, transactions, and journal entries, returning results filtered by the user's client permissions. The Indicators subsystem provides small UI utilities like relative date badges (e.g., "5 days ago") used across the application.

Routes & Pages

Route Method Handler Purpose
GET /search GET :search Opens the search modal dialog
POST /search POST :search Executes search query, returns results HTML
GET /days-ago GET ::days-ago Returns a relative date badge pill (HTMX)

Behaviors

Unit Tests

  • q->solr-q transforms user query into Solr query string
    • Bare words become _text_:"word" clauses joined with AND
    • Quoted phrases are preserved as single tokens
    • Keywords invoice, payment, transaction, journal-entry map to type:<value> filters
    • Dates in normal-date format (e.g., 5/5/2034) are converted to Solr date format
    • Dates in iso-date format are converted to Solr date format
    • Unparseable dates pass through unchanged
    • Decimal numbers (123.45) are formatted to 2 decimal places with HALF_UP rounding
    • Integers pass through unchanged
    • Multiple tokens are joined with AND
  • try-cleanse-date parses normal-date and iso-date formats, returning Solr-formatted date
  • try-cleanse-date returns original string for unparseable input
  • try-parse-number formats decimal strings to exactly 2 decimal places
  • try-parse-number returns non-decimal strings unchanged
  • search-results filters Solr results by can-see-client? against user's allowed clients
  • days-ago* returns "N days ago" pill with color :primary for < 30 days
  • days-ago* returns "N days ago" pill with color :secondary for 30-59 days
  • days-ago* returns "N days ago" pill with color :yellow for 60-89 days
  • days-ago* returns "N days ago" pill with color :red for 90+ days
  • days-ago* returns "N days from now" pill with color :primary for future dates
  • days-ago* returns empty [:div] for nil date

Integration Tests

  • GET /search with authenticated user returns 200 with search modal HTML
  • Search modal contains text input with hx-post="/search", hx-target="#search-results", hx-indicator="#search"
  • Search input triggers on keyup changed delay:300ms and search events
  • POST /search with query parameter q returns HTML search results
  • Search results include card for each Solr document with type icon, client code, amount, vendor name, date, and description
  • Each result card links to the appropriate detail page (/invoices, /transactions, /ledger, /payments) with exact-match-id parameter
  • Results are filtered to only show documents from clients the user can access
  • GET /search without q parameter returns modal dialog (not results)
  • POST /search without q parameter returns modal dialog (not results)
  • GET /days-ago?date=<iso-date> returns colored pill HTML for past dates
  • GET /days-ago?date=<future-date> returns "days from now" pill HTML
  • GET /days-ago with missing or invalid date returns empty div (schema enforcement)

UI Tests (SSR)

Happy Path: Search and View Result

  1. Authenticated user clicks search icon in navbar
  2. Search modal opens with autofocused input and placeholder "5/5/2034 Magheritas"
  3. User types a query (e.g., "invoice 1000")
  4. After 300ms debounce, HTMX POSTs to /search
  5. Results appear below input as cards
  6. Each card shows: type icon, type name, client code pill, amount pill, vendor pill (if present), date, and description/number
  7. User clicks external link icon on a result
  8. Result opens in new tab on the appropriate detail page with exact-match-id set

Search with Type Filter

  1. User opens search modal
  2. User types "payment"
  3. Results are filtered to only show type:payment documents
  4. Each result card shows payment icon and links to /payments/?exact-match-id=<id>

Search with Date

  1. User opens search modal
  2. User types "5/5/2034"
  3. Date is parsed and converted to Solr format
  4. Results matching that date appear

Empty Search Results

  1. User opens search modal
  2. User types a query with no matches
  3. "No results found." message displays

Days-Ago Indicator

  1. User views a page containing a days-ago HTMX element
  2. Element fetches /days-ago?date=<date>
  3. Colored pill renders showing relative time (e.g., "45 days ago" in secondary color)

Edge Cases

  • Special characters in query: Solr special characters are not escaped in user query (relies on phrase wrapping)
  • Empty query: Modal renders without results; no Solr query executed
  • Very long query: Passes through to Solr; UI handles long text via flex layout
  • No accessible clients: Returns empty results even if Solr has matching documents
  • Solr unavailable: Behavior depends on solr/impl (MockSolrClient returns nil/empty)
  • Mixed type keywords and text: "invoice 1000" produces type:invoice AND _text_:"1000"
  • Multiple type keywords: "invoice payment" produces type:invoice AND type:payment (likely zero results)
  • Numeric tokens with commas/currency: $1,000.50 passes through as literal text search
  • Future dates: Date parsing accepts future dates; Solr query includes them

Indicators

  • Nil date: Returns empty div, no error
  • Invalid date format: Schema enforcement rejects before handler executes
  • Same-day date: Returns "0 days ago" with primary color
  • Very old dates: Returns "N days ago" with red color (90+ days threshold)

Test Data Requirements

Solr Index

  • Indexed documents of all four types: invoice, payment, transaction, journal-entry
  • Documents span multiple clients
  • Documents with varying dates, amounts, descriptions, numbers, and vendor names
  • Documents with and without vendor associations

Users

  • Authenticated user with access to subset of clients
  • Authenticated user with access to all clients
  • Admin user (for full client visibility)

Datomic Entities

  • Clients with :client/code and :client/name
  • Invoices with :invoice/invoice-number, :invoice/total, :invoice/date, :invoice/client, :invoice/vendor
  • Payments with :payment/check-number, :payment/amount, :payment/date, :payment/client, :payment/vendor
  • Transactions with :transaction/description-original, :transaction/amount, :transaction/date, :transaction/client, :transaction/vendor
  • Journal entries with :journal-entry/amount, :journal-entry/date, :journal-entry/client, :journal-entry/vendor, :journal-entry/line-items

Dependencies

External Services

  • Solr: Full-text search index (auto-ap.solr). Uses MockSolrClient in test environments without Solr configured
  • Datomic: Client visibility checks pull user/client associations

Frontend Libraries

  • HTMX: Modal loading, search debounce (keyup changed delay:300ms), indicator spinner
  • Alpine.js: Modal card structure

Middleware Stack

  • wrap-secure: Requires authentication for search and days-ago endpoints
  • wrap-client-redirect-unauthenticated: Redirects unauthenticated to /login
  • wrap-schema-enforce: Validates date query parameter for /days-ago
  • Invoices: Search results link to invoice detail pages
  • Payments: Search results link to payment detail pages
  • Transactions: Search results link to transaction detail pages
  • Ledger: Search results link to ledger for journal entries