Documentation Index
Fetch the complete documentation index at: https://docs.laportenard.com/llms.txt
Use this file to discover all available pages before exploring further.
The sync system has 575 tests across three packages, all using Vitest.
| Package | Test files | Tests | What’s covered |
|---|
nu_pos_sync_protocol | 1 | 55 | Zod validators for all 15 message types |
nu_pos_hub | 12 | 129 | Storage, leasing, handlers, server, forwarder, adapter |
nu_pos_react | 24 | 391 | State machines, transports, reconcile, outbox, and existing POS tests |
Running tests
Always run from the correct package directory. Running from the repo root picks up test files from all packages, causing path alias resolution failures.
cd nu_pos_sync_protocol
npx vitest run
cd nu_pos_hub
npx vitest run
cd nu_pos_react
npx vitest run
Single test file
cd nu_pos_react && npx vitest run src/state/machines/__tests__/syncMachine.test.ts
cd nu_pos_hub && npx vitest run src/handlers/__tests__/orderHandler.test.ts
Watch mode
cd nu_pos_react && npm test
cd nu_pos_hub && npm test
Test architecture
Protocol tests
nu_pos_sync_protocol/src/__tests__/validators.test.ts (55 tests)
- Round-trip validation for all terminal and hub message types
- Rejection of malformed messages (missing fields, wrong types)
parseTerminalMessage(), parseHubMessage(), parseProtocolMessage() helpers
Hub tests
Storage layer (41 tests)
| File | Tests | Coverage |
|---|
orderStore.test.ts | 11 | Upsert with version auto-increment, get, getByTable, count |
leaseStore.test.ts | 11 | Grant, renew, release, getExpired, getByTerminal |
eventLog.test.ts | 11 | Append, getPending, markForwarded, getRecent, count |
tableStore.test.ts | 8 | Upsert, get, getAll, status transitions |
All storage tests use in-memory SQLite (:memory:) for speed and isolation.
Lease manager (25 tests)
- Acquire: new lease, re-entrant, denied (held by other), force override
- Release: by holder, by non-holder (rejected), with final snapshot
- Heartbeat: renewal, rejected for non-holder
- Tick: expired lease revocation, callback invocation
- Disconnect: grace period extension
Handlers (14 tests)
| File | Tests | Coverage |
|---|
orderHandler.test.ts | 7 | Snapshot without lease, with lease, version conflict, broadcast, event log, table status |
leaseHandler.test.ts | 7 | Acquire, release, heartbeat, force override, event logging |
Server (25 tests)
| File | Tests | Coverage |
|---|
wsServer.test.ts | 3 | WebSocket connection, auth flow, message routing |
messageRouter.test.ts | 9 | JSON parsing, schema validation, auth gating, message dispatch |
httpServer.test.ts | 13 | Health, status, events, dashboard, OPTIONS, 404, CORS |
Upstream (24 tests)
| File | Tests | Coverage |
|---|
forwarder.test.ts | 9 | Drain pending events, mark forwarded, skip non-order events, handle failure |
odooAdapter.test.ts | 15 | Auth, forward create/update, payload transformation, voided line filtering |
Frontend tests
Sync-specific (67 tests)
| File | Tests | Coverage |
|---|
syncMachine.test.ts | 35 | All 4 states, all 14 events, context updates, state transitions |
hubTransport.test.ts | 24 | Lease acquire/deny/timeout/revoke, message routing, offline fallback |
reconcile.test.ts | 8 | All reconcile strategies: accept_remote, merge, default fallback |
Transport infrastructure (31 tests)
| File | Tests | Coverage |
|---|
directTransport.test.ts | 18 | Local locks, outbox integration, state lifecycle |
createTransport.test.ts | 4 | Factory: returns direct when hub disabled, hub when enabled |
hubDiscovery.test.ts | 9 | Config extraction, URL resolution |
Testing patterns
Hub: in-memory SQLite
beforeEach(() => {
db = initDb(":memory:");
orderStore = createOrderStore(db);
});
Hub: mock WebSocket
function makeMockWs() {
return {
send: vi.fn(),
readyState: 1,
OPEN: 1,
} as unknown as import("ws").WebSocket;
}
Frontend: module mocking
vi.mock("../sync/outbox", () => ({
queueOutbound: vi.fn(),
flushOutbound: vi.fn().mockResolvedValue({ sent: 0, failed: 0 }),
listOutbound: vi.fn().mockReturnValue([]),
}));
Frontend: XState actor testing
const actor = createActor(syncMachine);
actor.start();
actor.send({ type: "TRANSPORT_RECONNECTING" });
expect(actor.getSnapshot().value).toBe("reconnecting");
What’s not tested
The following are intentionally untested (React components requiring DOM/render context):
SyncStatusIndicator — Read-only badge, tested visually
ConflictDialog — Radix UI dialog, tested visually
SyncOverlay — Toast integration, tested visually
SyncUIProvider — Simple React context with useState
RealtimeProvider — Tested indirectly through transport and machine tests