import { afterEach, beforeEach, describe, expect, it } from "vitest"; import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { escposDriver } from "./printer-generic.js"; import { renderTicket } from "./printer-escpos.js"; // End-to-end transport routing through the real driver: a USB-configured generic // ESC/POS printer (Cashino / ICS XP-K200L family) must // resolve to the char-device transport and write the SAME ESC/POS bytes the TCP path // would. (The TCP path is exercised by the routing/escpos suites and on hardware.) describe("escposDriver (generic ESC/POS) — USB transport", () => { let dir: string; let devicePath: string; beforeEach(() => { dir = mkdtempSync(join(tmpdir(), "escpos-usb-")); devicePath = join(dir, "lp0"); // Stand in for an enumerated usblp node (the kernel creates it; we only open it). writeFileSync(devicePath, ""); }); afterEach(() => { rmSync(dir, { recursive: true, force: true }); }); it("prints a ticket to the configured USB device path", async () => { const printer = escposDriver.create({ transport: "usb", devicePath, timeoutMs: 1000 }); const data = { ticketId: "12345678901", issuedAt: "2026-06-21T10:00:00.000Z" }; await printer.printTicket(data); const written = readFileSync(devicePath); expect(written.equals(renderTicket(data))).toBe(true); }); it("healthCheck reports ready when the node exists, offline when it doesn't", async () => { const present = escposDriver.create({ transport: "usb", devicePath, timeoutMs: 1000 }); expect((await present.healthCheck()).status).toBe("ready"); // An absent device node (printer unplugged / not enumerated) → offline. const absent = escposDriver.create({ transport: "usb", devicePath: join(dir, "absent-lp0"), timeoutMs: 1000, }); expect((await absent.healthCheck()).status).toBe("offline"); }); it("advertises both transports", () => { expect(escposDriver.transports).toContain("usb"); expect(escposDriver.transports).toContain("tcp-ip"); }); });