Tests und Mock
This commit is contained in:
68
test/helpers/TestFluidNCClient.js
Normal file
68
test/helpers/TestFluidNCClient.js
Normal file
@@ -0,0 +1,68 @@
|
||||
const WebSocket = require("ws");
|
||||
const EventEmitter = require("events");
|
||||
|
||||
class TestFluidNCClient extends EventEmitter {
|
||||
constructor(cfg) {
|
||||
super();
|
||||
|
||||
this.host = cfg.host;
|
||||
this.port = cfg.port || 81;
|
||||
|
||||
this.ws = null;
|
||||
this.connect();
|
||||
}
|
||||
|
||||
connect() {
|
||||
const url = `ws://${this.host}:${this.port}`;
|
||||
|
||||
this.ws = new WebSocket(url);
|
||||
|
||||
this.ws.on("open", () => {
|
||||
console.log("[TestFluidNC] Connected (WS)");
|
||||
});
|
||||
|
||||
this.ws.on("message", (msg) => {
|
||||
this.emit("message", msg.toString());
|
||||
});
|
||||
|
||||
this.ws.on("close", () => {
|
||||
console.log("[TestFluidNC] Disconnected");
|
||||
});
|
||||
|
||||
this.ws.on("error", (err) => {
|
||||
console.log("[TestFluidNC] WS Error:", err.message);
|
||||
});
|
||||
}
|
||||
|
||||
sendLine(cmd) {
|
||||
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
||||
this.ws.send(cmd + "\n");
|
||||
}
|
||||
}
|
||||
|
||||
requestStatus() {
|
||||
this.sendLine("?");
|
||||
}
|
||||
|
||||
jog(relative, axis, value) {
|
||||
const cmd = relative? `$J=G91 G1 ${axis}${value} F2000\r\n`: `$J=G90 G1 ${axis}${value} F2000\r\n`;
|
||||
this.sendLine(cmd);
|
||||
}
|
||||
|
||||
sendGcode(cmd) {
|
||||
this.sendLine(cmd);
|
||||
}
|
||||
|
||||
onMessage(fn) {
|
||||
this.on("message", fn);
|
||||
}
|
||||
|
||||
close() {
|
||||
if (this.ws) {
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TestFluidNCClient;
|
||||
146
test/helpers/mockFluidNC.js
Normal file
146
test/helpers/mockFluidNC.js
Normal file
@@ -0,0 +1,146 @@
|
||||
const WebSocket = require("ws");
|
||||
|
||||
/**
|
||||
* Mock FluidNC WebSocket Server für Tests
|
||||
* Ermöglicht es, FluidNCClient in Tests gegen einen echten WS-Server zu testen
|
||||
*/
|
||||
class MockFluidNC {
|
||||
constructor(host = "localhost", port = 9000) {
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.server = null;
|
||||
this.clients = [];
|
||||
this.messageHandlers = [];
|
||||
this.receivedCommands = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Startet den Mock-Server
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
start() {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.server = new WebSocket.Server({ host: this.host, port: this.port }, () => {
|
||||
console.log(`[MockFluidNC] Server started on ws://${this.host}:${this.port}`);
|
||||
resolve();
|
||||
});
|
||||
|
||||
this.server.on("connection", (ws) => {
|
||||
console.log("[MockFluidNC] Client connected");
|
||||
this.clients.push(ws);
|
||||
|
||||
ws.on("message", (msg) => {
|
||||
const msgStr = msg.toString().trim();
|
||||
console.log(`[MockFluidNC] Received: ${msgStr}`);
|
||||
|
||||
// Befehl zur Historie hinzufügen
|
||||
this.receivedCommands.push(msgStr);
|
||||
|
||||
// Handler aufrufen, die registriert wurden
|
||||
this.messageHandlers.forEach(handler => handler(msgStr));
|
||||
|
||||
// Automatische Responses für spezielle Befehle
|
||||
this._handleCommand(msgStr, ws);
|
||||
});
|
||||
|
||||
ws.on("close", () => {
|
||||
console.log("[MockFluidNC] Client disconnected");
|
||||
this.clients = this.clients.filter(c => c !== ws);
|
||||
});
|
||||
|
||||
ws.on("error", (err) => {
|
||||
console.log("[MockFluidNC] Client error:", err.message);
|
||||
});
|
||||
});
|
||||
|
||||
this.server.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Stoppt den Mock-Server
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
stop() {
|
||||
return new Promise((resolve) => {
|
||||
if (this.server) {
|
||||
// Alle Clients disconnecten
|
||||
this.clients.forEach(client => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.close();
|
||||
}
|
||||
});
|
||||
this.clients = [];
|
||||
|
||||
this.server.close(() => {
|
||||
console.log("[MockFluidNC] Server stopped");
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sendet eine Nachricht an alle verbundenen Clients
|
||||
* @param {string} msg
|
||||
*/
|
||||
broadcast(msg) {
|
||||
this.clients.forEach(client => {
|
||||
if (client.readyState === WebSocket.OPEN) {
|
||||
client.send(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Registriert einen Handler, der bei jeder empfangenen Nachricht aufgerufen wird
|
||||
* @param {Function} handler - (msg: string) => void
|
||||
*/
|
||||
onMessage(handler) {
|
||||
this.messageHandlers.push(handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* Behandelt spezielle G-Code Befehle mit Auto-Responses
|
||||
* @private
|
||||
*/
|
||||
_handleCommand(cmd, ws) {
|
||||
if (cmd === "?") {
|
||||
// Status request - sende eine Status-Antwort
|
||||
ws.send("<Idle|MPos:0.000,0.000,0.000|FS:0,0>\n");
|
||||
} else if (cmd.startsWith("$J=")) {
|
||||
// Jog command - sende OK
|
||||
ws.send("ok\n");
|
||||
} else if (cmd.includes("G1") || cmd.includes("G0")) {
|
||||
// G-Code command - sende OK
|
||||
ws.send("ok\n");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt die Anzahl verbundener Clients zurück
|
||||
*/
|
||||
getConnectedClientCount() {
|
||||
return this.clients.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt alle empfangenen Befehle zurück und leert die Liste
|
||||
*/
|
||||
getReceivedCommands() {
|
||||
const commands = [...this.receivedCommands];
|
||||
this.receivedCommands = [];
|
||||
return commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gibt den letzten empfangenen Befehl zurück
|
||||
*/
|
||||
getLastReceivedCommand() {
|
||||
return this.receivedCommands[this.receivedCommands.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MockFluidNC;
|
||||
91
test/mockFluidNC.test.js
Normal file
91
test/mockFluidNC.test.js
Normal file
@@ -0,0 +1,91 @@
|
||||
const MockFluidNC = require("./helpers/mockFluidNC");
|
||||
const TestFluidNCClient = require("./helpers/TestFluidNCClient");
|
||||
|
||||
describe("FluidNCClient with MockFluidNC", () => {
|
||||
let mock;
|
||||
let client;
|
||||
|
||||
beforeAll(async () => {
|
||||
// Mock-Server starten
|
||||
mock = new MockFluidNC("localhost", 9003);
|
||||
await mock.start();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
// Mock-Server stoppen - das stoppt alle Verbindungen
|
||||
await mock.stop();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
// Neuen Test-Client für jeden Test erstellen
|
||||
client = new TestFluidNCClient({
|
||||
host: "localhost",
|
||||
port: 9003
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Client sauber schließen
|
||||
if (client) {
|
||||
client.close();
|
||||
}
|
||||
});
|
||||
|
||||
test("sollte sich mit Mock-Server verbinden", async () => {
|
||||
// Warten bis verbunden
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
expect(mock.getConnectedClientCount()).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("sollte Status Request senden", async () => {
|
||||
// Warten bis verbunden
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
|
||||
const messagePromise = new Promise((resolve) => {
|
||||
client.onMessage((msg) => {
|
||||
resolve(msg);
|
||||
});
|
||||
});
|
||||
|
||||
client.requestStatus();
|
||||
|
||||
const response = await messagePromise;
|
||||
expect(response).toContain("Idle");
|
||||
});
|
||||
|
||||
test("sollte Jog Command verarbeiten", async () => {
|
||||
// Warten bis verbunden
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
|
||||
const messagePromise = new Promise((resolve) => {
|
||||
client.onMessage((msg) => {
|
||||
resolve(msg);
|
||||
});
|
||||
});
|
||||
|
||||
client.jog(true, "X", 10);
|
||||
|
||||
const response = await messagePromise;
|
||||
expect(response.trim()).toBe("ok");
|
||||
});
|
||||
|
||||
test("sollte G-Code Command verarbeiten", async () => {
|
||||
// Warten bis verbunden
|
||||
await new Promise(resolve => setTimeout(resolve, 300));
|
||||
|
||||
const messagePromise = new Promise((resolve) => {
|
||||
client.onMessage((msg) => {
|
||||
resolve(msg);
|
||||
});
|
||||
});
|
||||
|
||||
client.sendGcode("G0 X10 Y20");
|
||||
|
||||
const response = await messagePromise;
|
||||
expect(response.trim()).toBe("ok");
|
||||
|
||||
// Zusätzlich prüfen, dass der korrekte Befehl empfangen wurde
|
||||
const receivedCommands = mock.getReceivedCommands();
|
||||
expect(receivedCommands).toContain("G0 X10 Y20");
|
||||
});
|
||||
}, 10000);
|
||||
13
test/setup.js
Normal file
13
test/setup.js
Normal file
@@ -0,0 +1,13 @@
|
||||
// Jest Setup für alle Tests
|
||||
const originalConsoleLog = console.log;
|
||||
|
||||
// Mock console.log um Warnings nach Tests zu vermeiden
|
||||
beforeAll(() => {
|
||||
console.log = jest.fn();
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
console.log = originalConsoleLog;
|
||||
// Warten bis alle async Operationen fertig sind
|
||||
await new Promise(resolve => setTimeout(resolve, 200));
|
||||
});
|
||||
Reference in New Issue
Block a user