← back to Desktop Dotbar

test/ticket-states.test.js

53 lines

'use strict';
// ticket-states: the bar must ALWAYS carry all five ticket states plus the dw / non-dw pair
// (Steve 2026-09-25 x2), and an unreachable board must read as NOT-MEASURED — never as hidden,
// never as a fake 0. Zero deps.
const test = require('node:test');
const assert = require('node:assert');
const { ticketStates, TICKET_STATES } = require('../ticket-states');

const KEYS = ['blocked', 'open', 'idle', 'doing', 'parked', 'dw', 'nondw'];

test('healthy board: every state + the dw/non-dw pair, with measured counts, zeros kept', () => {
  const s = ticketStates({ updated: Date.now(), ok: true, blocked: 78, open: 33, idle: 0, doing: 20, parked: 5, dw: 115, nondw: 21 });
  assert.deepEqual(s.map(x => x.key), KEYS);
  assert.deepEqual(s.map(x => x.n), [78, 33, 0, 20, 5, 115, 21]);
  assert.equal(s.find(x => x.key === 'dw').section, 'dw');
  assert.equal(s.find(x => x.key === 'nondw').section, 'nondw', 'non-dw drills into the board Non-DW section');
  const idle = s.find(x => x.key === 'idle');
  assert.equal(idle.zero, true, 'a zero state is KEPT (dimmed), not dropped');
  assert.equal(s.find(x => x.key === 'idle').section, 'stopped', 'idle opens the board stopped section');
});

// NEGATIVE (fault-injection): the exact 2026-09-25 failure — ticket-board down after a reboot.
test('NEGATIVE: never-fetched board -> every chip NOT-measured (null, not 0), dw/non-dw included', () => {
  const s = ticketStates({ updated: 0, ok: false, blocked: 0, open: 0, idle: 0, doing: 0, parked: 0, dw: 0, nondw: 0 });
  assert.equal(s.length, KEYS.length, 'row must not disappear when the board is down');
  for (const x of s) {
    assert.strictEqual(x.n, null, `${x.key} must be null (unmeasured), got ${x.n}`);
    assert.equal(x.measured, false);
  }
});

test('NEGATIVE: board went down after a good fetch -> stale counts are NOT presented as measured', () => {
  const s = ticketStates({ updated: Date.now() - 60000, ok: false, blocked: 78, open: 33, idle: 4, doing: 20, parked: 5, dw: 115, nondw: 21 });
  assert.ok(s.every(x => x.n === null), 'ok:false must blank the counts to "–"');
});

// The dw/non-dw pair is a SECOND cut of the same population, so it must reconcile with the first.
// If it ever does not, one of the two is counting a different set and the row is lying.
test('dw + non-dw reconciles with the five state counts', () => {
  const snap = { updated: Date.now(), ok: true, blocked: 78, open: 33, idle: 4, doing: 20, parked: 5, dw: 115, nondw: 25 };
  const s = ticketStates(snap);
  const byState = ['blocked', 'open', 'idle', 'doing', 'parked'].reduce((a, k) => a + snap[k], 0);
  const bySeg = s.filter(x => x.key === 'dw' || x.key === 'nondw').reduce((a, x) => a + x.n, 0);
  assert.equal(bySeg, byState, 'dw + non-dw must partition exactly the population the states count');
});

test('missing/garbage snapshot never throws and still yields every chip', () => {
  for (const snap of [undefined, null, {}, { updated: 1, ok: true, blocked: 'x' }]) {
    const s = ticketStates(snap);
    assert.equal(s.length, TICKET_STATES.length);
  }
});