const test = require('node:test'); const assert = require('node:assert/strict'); const { EventEmitter } = require('node:events'); // A stand-in for the MQTT client, so no network is involved. const clients = []; const live = require('../lib/printerLive'); live.setConnector((url, options) => { const c = new EventEmitter(); Object.assign(c, { url, options, connected: false, reconnecting: false, published: [], ended: false, subscribe: (_topic, cb) => cb(null), publish: (topic, body) => c.published.push({ topic, body: JSON.parse(body) }), end: () => { c.ended = true; }, reconnect: () => {}, }); clients.push(c); return c; }); const report = (print) => Buffer.from(JSON.stringify({ print })); const printerRow = { id: 1, host: '10.0.0.5', serial: 'SER1', access_code: 'code1' }; const tray = (id, type, colour) => ({ id: String(id), tray_type: type, tray_color: colour, tray_uuid: type ? `U${id}` : '0' }); test('live status merges partial reports, and a tray change syncs spools once', async (t) => { t.after(() => live.stopAll()); const synced = []; live.setTraysHandler(async (id, trays) => { synced.push({ id, trays }); return { updated: trays.length }; }); live.reconcile([printerRow, { id: 2, host: '', serial: 'X', access_code: 'y' }]); assert.equal(clients.length, 1, 'a printer missing its address isn’t connected'); const c = clients[0]; assert.equal(c.options.password, 'code1'); c.connected = true; c.emit('connect'); assert.equal(c.published[0].topic, 'device/SER1/request'); assert.equal(c.published[0].body.pushing.command, 'pushall'); c.emit('message', 'device/SER1/report', report({ gcode_state: 'RUNNING', mc_percent: 10, nozzle_temper: 220, ams: { ams: [{ id: '0', tray: [tray(0, 'PLA', 'FF0000FF'), tray(1, '', '')] }] }, })); c.emit('message', 'device/SER1/report', report({ mc_percent: 11 })); const snap = live.snapshot(1); assert.equal(snap.connected, true); assert.equal(snap.status.state, 'RUNNING'); assert.equal(snap.status.progress, 11); assert.equal(snap.status.nozzle, 220, 'kept from the earlier report'); assert.deepEqual(snap.loaded.map((l) => [l.slot, l.empty, l.colour, l.tagged]), [[0, false, '#FF0000', true], [1, true, null, false]]); assert.equal(JSON.stringify(snap).includes('code1'), false, 'no access code in a snapshot'); // "Test & sync" asks again and syncs straight away. const pending = live.refresh(1, 3000); c.emit('message', 'device/SER1/report', report({ ams: { ams: [{ id: '0', tray: [tray(0, 'PLA', 'FF0000FF'), tray(1, '', '')] }] } })); const result = await pending; assert.equal(result.connected, true); assert.equal(result.sync.updated, 2); assert.equal(synced.length, 1); assert.equal(c.published.at(-1).body.pushing.command, 'pushall'); }); test('changing a printer’s code reopens its connection; removing it closes it', () => { clients.length = 0; live.reconcile([printerRow]); live.reconcile([printerRow]); assert.equal(clients.length, 1, 'no change, no new connection'); live.reconcile([{ ...printerRow, access_code: 'code2' }]); assert.equal(clients.length, 2); assert.equal(clients[0].ended, true); live.reconcile([]); assert.equal(clients[1].ended, true); assert.deepEqual(live.snapshot(1), { live: false }); });