'use strict'; const ShellyEmergencyStop = require('../robot/ShellyEmergencyStop'); const OFF_URL = 'http://shelly.local/rpc/Switch.Set?id=0&on=false'; const ON_URL = 'http://shelly.local/rpc/Switch.Set?id=0&on=true'; const STATUS_URL = 'http://shelly.local/rpc/Switch.GetStatus?id=0'; function makeHttpGetJson(data, statusCode = 200) { return jest.fn(() => Promise.resolve({ ok: statusCode >= 200 && statusCode < 300, status: statusCode, data })); } function makeHttpGet(statusCode = 200) { return jest.fn(() => Promise.resolve({ ok: statusCode >= 200 && statusCode < 300, status: statusCode })); } describe('ShellyEmergencyStop — Konstruktor', () => { test('url wird korrekt gesetzt', () => { const s = new ShellyEmergencyStop(OFF_URL); expect(s.url).toBe(OFF_URL); }); test('_onUrl ersetzt on=false durch on=true', () => { const s = new ShellyEmergencyStop(OFF_URL); expect(s._onUrl).toBe(ON_URL); }); test('_statusUrl zeigt auf Switch.GetStatus', () => { const s = new ShellyEmergencyStop(OFF_URL); expect(s._statusUrl).toBe(STATUS_URL); }); test('null-URL → _offUrl, _onUrl und _statusUrl sind null', () => { const s = new ShellyEmergencyStop(null); expect(s._offUrl).toBeNull(); expect(s._onUrl).toBeNull(); expect(s._statusUrl).toBeNull(); }); test('Initialzustand ist ready', () => { const s = new ShellyEmergencyStop(OFF_URL); expect(s.state).toBe('ready'); expect(s.error).toBeNull(); }); }); describe('ShellyEmergencyStop — SenderInterface', () => { test('connect() gibt Instanz zurück', async () => { const s = new ShellyEmergencyStop(OFF_URL); await expect(s.connect()).resolves.toBe(s); }); test('send() gibt false zurück (kein GCode-Empfänger)', () => { const s = new ShellyEmergencyStop(OFF_URL); expect(s.send('G1 X10')).toBe(false); }); test('getStatus() enthält state und url', () => { const s = new ShellyEmergencyStop(OFF_URL); const st = s.getStatus(); expect(st.state).toBe('ready'); expect(st.url).toBe(OFF_URL); }); test('alarmUnlock() gibt {ok:true, skipped:true} zurück', async () => { const s = new ShellyEmergencyStop(OFF_URL); await expect(s.alarmUnlock()).resolves.toEqual({ ok: true, skipped: true }); }); }); describe('ShellyEmergencyStop — emergencyStop()', () => { test('ruft _offUrl auf', async () => { const httpGet = makeHttpGet(200); const s = new ShellyEmergencyStop(OFF_URL, { httpGetFn: httpGet }); await s.emergencyStop(); expect(httpGet).toHaveBeenCalledWith(OFF_URL); }); test('setzt state=stopped bei HTTP 200', async () => { const s = new ShellyEmergencyStop(OFF_URL, { httpGetFn: makeHttpGet(200) }); const result = await s.emergencyStop(); expect(result.ok).toBe(true); expect(s.state).toBe('stopped'); expect(s.error).toBeNull(); }); test('setzt state=error bei HTTP 500', async () => { const s = new ShellyEmergencyStop(OFF_URL, { httpGetFn: makeHttpGet(500) }); const result = await s.emergencyStop(); expect(result.ok).toBe(false); expect(s.state).toBe('error'); expect(s.error).toBe('HTTP 500'); }); test('setzt state=error bei Netzwerkfehler', async () => { const httpGet = jest.fn(() => Promise.reject(new Error('ECONNREFUSED'))); const s = new ShellyEmergencyStop(OFF_URL, { httpGetFn: httpGet }); const result = await s.emergencyStop(); expect(result.ok).toBe(false); expect(result.error).toBe('ECONNREFUSED'); expect(s.state).toBe('error'); }); test('gibt {ok:false} wenn url null ist', async () => { const s = new ShellyEmergencyStop(null); const result = await s.emergencyStop(); expect(result.ok).toBe(false); expect(result.error).toMatch(/no shelly url/); }); }); describe('ShellyEmergencyStop — powerOn()', () => { test('ruft _onUrl auf (on=true)', async () => { const httpGet = makeHttpGet(200); const s = new ShellyEmergencyStop(OFF_URL, { httpGetFn: httpGet }); await s.powerOn(); expect(httpGet).toHaveBeenCalledWith(ON_URL); }); test('setzt state=ready bei HTTP 200', async () => { const s = new ShellyEmergencyStop(OFF_URL, { httpGetFn: makeHttpGet(200) }); const result = await s.powerOn(); expect(result.ok).toBe(true); expect(s.state).toBe('ready'); }); test('setzt state=error bei HTTP 503', async () => { const s = new ShellyEmergencyStop(OFF_URL, { httpGetFn: makeHttpGet(503) }); const result = await s.powerOn(); expect(result.ok).toBe(false); expect(s.state).toBe('error'); }); test('gibt {ok:false} wenn url null ist', async () => { const s = new ShellyEmergencyStop(null); const result = await s.powerOn(); expect(result.ok).toBe(false); }); }); describe('ShellyEmergencyStop — getArmed()', () => { const SHELLY_ON = { id: 0, source: 'WS_in', output: true, apower: 15.5, voltage: 234.9, freq: 50.1, current: 0.144 }; const SHELLY_OFF = { id: 0, source: 'WS_in', output: false, apower: 0.0, voltage: 235.2, freq: 50.1, current: 0.000 }; test('ruft _statusUrl (Switch.GetStatus?id=0) auf', async () => { const httpGetJson = makeHttpGetJson(SHELLY_ON); const s = new ShellyEmergencyStop(OFF_URL, { httpGetJsonFn: httpGetJson }); await s.getArmed(); expect(httpGetJson).toHaveBeenCalledWith(STATUS_URL); }); test('armed=true wenn output:true', async () => { const s = new ShellyEmergencyStop(OFF_URL, { httpGetJsonFn: makeHttpGetJson(SHELLY_ON) }); const result = await s.getArmed(); expect(result.ok).toBe(true); expect(result.armed).toBe(true); expect(result.voltage).toBe(234.9); expect(result.power).toBe(15.5); }); test('armed=false wenn output:false', async () => { const s = new ShellyEmergencyStop(OFF_URL, { httpGetJsonFn: makeHttpGetJson(SHELLY_OFF) }); const result = await s.getArmed(); expect(result.ok).toBe(true); expect(result.armed).toBe(false); }); test('armed=false bei HTTP-Fehler (503)', async () => { const s = new ShellyEmergencyStop(OFF_URL, { httpGetJsonFn: makeHttpGetJson(null, 503) }); const result = await s.getArmed(); expect(result.ok).toBe(false); expect(result.armed).toBe(false); }); test('armed=false bei Netzwerkfehler', async () => { const httpGetJson = jest.fn(() => Promise.reject(new Error('ECONNREFUSED'))); const s = new ShellyEmergencyStop(OFF_URL, { httpGetJsonFn: httpGetJson }); const result = await s.getArmed(); expect(result.ok).toBe(false); expect(result.armed).toBe(false); expect(result.error).toBe('ECONNREFUSED'); }); test('armed=false wenn url null ist', async () => { const s = new ShellyEmergencyStop(null); const result = await s.getArmed(); expect(result.ok).toBe(false); expect(result.armed).toBe(false); expect(result.error).toMatch(/no shelly url/); }); });