Files
appRobotFileservice/test/driverClient.test.js
2026-06-15 09:22:41 +02:00

137 lines
4.7 KiB
JavaScript

// Tests für src/driverClient.js
// Mockt das 'ws'-Modul vollständig — keine echte Netzwerkverbindung.
jest.mock('ws');
function makeMockWs(readyState = 1 /*OPEN*/) {
return {
readyState,
send: jest.fn(),
once: jest.fn(),
on: jest.fn(),
};
}
describe('driverClient', () => {
// Nach jedem resetModules() zeigt 'WebSocket' auf die frische Auto-Mock-Instanz.
// Deshalb wird MockWebSocket in beforeEach neu geladen, nicht oben auf dem Modul.
let MockWebSocket;
let cfg;
let dc;
beforeEach(() => {
jest.resetModules();
jest.clearAllMocks();
MockWebSocket = require('ws');
MockWebSocket.OPEN = 1;
MockWebSocket.CLOSED = 3;
cfg = require('../src/config');
cfg.driverWsUrl = 'wss://test-driver:9999';
cfg.driverTimeoutMs = 500;
dc = require('../src/driverClient');
});
// ─── Fehler: nicht konfiguriert ────────────────────────────────────────────
test('send() rejects mit NOT_CONFIGURED wenn DRIVER_WS_URL leer ist', async () => {
cfg.driverWsUrl = '';
await expect(dc.send('G90 G1 x0')).rejects.toMatchObject({
driverCode: 'NOT_CONFIGURED',
});
});
// ─── Erfolg: M114-Antwort ──────────────────────────────────────────────────
test('send() resolved mit M114-Objekt bei Erfolg', async () => {
const mockWs = makeMockWs();
MockWebSocket.mockImplementation(() => mockWs);
let capturedHandler;
mockWs.once.mockImplementation((event, handler) => {
if (event === 'message') capturedHandler = handler;
});
const promise = dc.send('G90 G1 x10');
const m114 = { position: { x: 10, y: 300, z: 0, a: 0 }, motorCounts: { x: 1 } };
capturedHandler(Buffer.from(JSON.stringify(m114)));
const result = await promise;
expect(result).toMatchObject({ position: { x: 10 } });
expect(mockWs.send).toHaveBeenCalledWith('G90 G1 x10');
});
// ─── Fehler: Driver meldet GCODE_ERROR ────────────────────────────────────
test('send() rejects mit driverCode=GCODE_ERROR wenn Driver Fehler schickt', async () => {
const mockWs = makeMockWs();
MockWebSocket.mockImplementation(() => mockWs);
let capturedHandler;
mockWs.once.mockImplementation((event, handler) => {
if (event === 'message') capturedHandler = handler;
});
const promise = dc.send('UNGUELTIG');
const errMsg = { type: 'error', code: 'GCODE_ERROR', message: 'inverse kinematics failed', input: 'UNGUELTIG' };
capturedHandler(Buffer.from(JSON.stringify(errMsg)));
await expect(promise).rejects.toMatchObject({
message: 'inverse kinematics failed',
driverCode: 'GCODE_ERROR',
});
});
// ─── Fehler: Timeout ───────────────────────────────────────────────────────
test('send() rejects mit TIMEOUT wenn Driver nicht antwortet', async () => {
jest.useFakeTimers();
const mockWs = makeMockWs();
MockWebSocket.mockImplementation(() => mockWs);
mockWs.once.mockImplementation(() => {}); // handler nie aufrufen → Timeout tritt ein
cfg.driverTimeoutMs = 5000;
const promise = dc.send('G90 G1 x0');
// Fake-Timer vorschiessen damit der Timeout feuert
jest.runAllTimers();
await expect(promise).rejects.toMatchObject({ driverCode: 'TIMEOUT' });
jest.useRealTimers();
});
// ─── Unbekanntes Antwort-Format → trotzdem Erfolg ────────────────────────
test('send() resolved auch bei unbekanntem (nicht-JSON) Antwort-Format', async () => {
const mockWs = makeMockWs();
MockWebSocket.mockImplementation(() => mockWs);
let capturedHandler;
mockWs.once.mockImplementation((event, handler) => {
if (event === 'message') capturedHandler = handler;
});
const promise = dc.send('G28');
capturedHandler(Buffer.from('ok'));
const result = await promise;
expect(result).toMatchObject({ raw: 'ok' });
});
// ─── configured() ──────────────────────────────────────────────────────────
test('configured() ist true wenn DRIVER_WS_URL gesetzt', () => {
expect(dc.configured()).toBe(true);
});
test('configured() ist false wenn DRIVER_WS_URL leer', () => {
cfg.driverWsUrl = '';
expect(dc.configured()).toBe(false);
});
});