import { expect, tap } from '@git.zone/tstest/tapbundle'; import * as devicemanager from '../ts/index.js'; // Test core exports tap.test('should export DeviceManager', async () => { expect(devicemanager.DeviceManager).toBeDefined(); expect(typeof devicemanager.DeviceManager).toEqual('function'); }); tap.test('should export UniversalDevice', async () => { expect(devicemanager.UniversalDevice).toBeDefined(); expect(typeof devicemanager.UniversalDevice).toEqual('function'); }); tap.test('should export Features', async () => { expect(devicemanager.ScanFeature).toBeDefined(); expect(devicemanager.PrintFeature).toBeDefined(); expect(devicemanager.PlaybackFeature).toBeDefined(); expect(devicemanager.VolumeFeature).toBeDefined(); expect(devicemanager.PowerFeature).toBeDefined(); expect(devicemanager.SnmpFeature).toBeDefined(); }); tap.test('should export device factories', async () => { expect(devicemanager.createScanner).toBeDefined(); expect(devicemanager.createPrinter).toBeDefined(); expect(devicemanager.createSpeaker).toBeDefined(); expect(devicemanager.createUpsDevice).toBeDefined(); expect(typeof devicemanager.createScanner).toEqual('function'); expect(typeof devicemanager.createPrinter).toEqual('function'); }); tap.test('should export protocol implementations', async () => { expect(devicemanager.EsclProtocol).toBeDefined(); expect(devicemanager.SaneProtocol).toBeDefined(); expect(devicemanager.IppProtocol).toBeDefined(); expect(devicemanager.SnmpProtocol).toBeDefined(); }); tap.test('should export retry helpers', async () => { expect(devicemanager.withRetry).toBeDefined(); expect(devicemanager.createRetryable).toBeDefined(); expect(devicemanager.defaultRetryOptions).toBeDefined(); }); // Test DeviceManager creation tap.test('should create DeviceManager instance', async () => { const dm = new devicemanager.DeviceManager({ autoDiscovery: false, }); expect(dm).toBeInstanceOf(devicemanager.DeviceManager); expect(dm.isDiscovering).toEqual(false); expect(dm.getScanners()).toEqual([]); expect(dm.getPrinters()).toEqual([]); expect(dm.getDevices()).toEqual([]); }); // Test device selector tap.test('should support device selection with IDeviceSelector', async () => { const dm = new devicemanager.DeviceManager({ autoDiscovery: false, }); // Empty manager should return empty array expect(dm.getDevices({ hasFeature: 'scan' })).toEqual([]); expect(dm.getDevices({ name: 'Test' })).toEqual([]); // selectDevice should throw when no devices match let error: Error | null = null; try { dm.selectDevice({ address: '192.168.1.100' }); } catch (e) { error = e as Error; } expect(error).not.toBeNull(); expect(error?.message).toContain('No device found'); }); // Test retry helper tap.test('withRetry should succeed on first try', async () => { let callCount = 0; const result = await devicemanager.withRetry(async () => { callCount++; return 'success'; }); expect(result).toEqual('success'); expect(callCount).toEqual(1); }); tap.test('withRetry should retry on failure', async () => { let callCount = 0; const result = await devicemanager.withRetry( async () => { callCount++; if (callCount < 3) { throw new Error('Temporary failure'); } return 'success after retries'; }, { maxRetries: 5, baseDelay: 10, maxDelay: 100 } ); expect(result).toEqual('success after retries'); expect(callCount).toEqual(3); }); tap.test('withRetry should throw after max retries', async () => { let callCount = 0; let error: Error | null = null; try { await devicemanager.withRetry( async () => { callCount++; throw new Error('Persistent failure'); }, { maxRetries: 2, baseDelay: 10, maxDelay: 100 } ); } catch (e) { error = e as Error; } expect(error).not.toBeNull(); expect(error?.message).toEqual('Persistent failure'); expect(callCount).toEqual(3); // Initial + 2 retries }); // Test discovery (non-blocking) tap.test('should start and stop discovery', async () => { const dm = new devicemanager.DeviceManager(); // Track events let discoveryStarted = false; let discoveryStopped = false; dm.on('discovery:started', () => { discoveryStarted = true; }); dm.on('discovery:stopped', () => { discoveryStopped = true; }); await dm.startDiscovery(); expect(dm.isDiscovering).toEqual(true); expect(discoveryStarted).toEqual(true); // Wait a bit for potential device discovery await new Promise((resolve) => setTimeout(resolve, 2000)); // Log discovered devices using new API const scanners = dm.getDevices({ hasFeature: 'scan' }); const printers = dm.getDevices({ hasFeature: 'print' }); console.log(`Discovered ${scanners.length} scanner(s) and ${printers.length} printer(s)`); for (const scanner of scanners) { const scanFeature = scanner.getFeature('scan'); console.log(` Scanner: ${scanner.name} (${scanner.address}) - ${scanFeature?.protocol || 'unknown'}`); } for (const printer of printers) { console.log(` Printer: ${printer.name} (${printer.address})`); } await dm.stopDiscovery(); expect(dm.isDiscovering).toEqual(false); expect(discoveryStopped).toEqual(true); await dm.shutdown(); }); // Test Scanner creation using factory tap.test('should create Scanner device using factory', async () => { const scanner = devicemanager.createScanner({ id: 'test:scanner:1', name: 'Test Scanner', address: '192.168.1.100', port: 443, protocol: 'escl', txtRecords: { 'ty': 'HP LaserJet MFP', 'pdl': 'image/jpeg,application/pdf', 'cs': 'color,grayscale', 'is': 'platen,adf', }, }); expect(scanner).toBeInstanceOf(devicemanager.UniversalDevice); expect(scanner.name).toEqual('Test Scanner'); expect(scanner.address).toEqual('192.168.1.100'); expect(scanner.hasFeature('scan')).toEqual(true); const scanFeature = scanner.selectFeature('scan'); expect(scanFeature).toBeInstanceOf(devicemanager.ScanFeature); expect(scanFeature.protocol).toEqual('escl'); }); // Test Printer creation using factory tap.test('should create Printer device using factory', async () => { const printer = devicemanager.createPrinter({ id: 'test:printer:1', name: 'Test Printer', address: '192.168.1.101', port: 631, ippPath: '/ipp/print', txtRecords: { 'ty': 'Brother HL-L2350DW', 'Color': 'T', 'Duplex': 'T', }, }); expect(printer).toBeInstanceOf(devicemanager.UniversalDevice); expect(printer.name).toEqual('Test Printer'); expect(printer.address).toEqual('192.168.1.101'); expect(printer.hasFeature('print')).toEqual(true); const printFeature = printer.selectFeature('print'); expect(printFeature).toBeInstanceOf(devicemanager.PrintFeature); }); // Test UniversalDevice feature management tap.test('should manage features on UniversalDevice', async () => { const device = new devicemanager.UniversalDevice('192.168.1.50', 80, { name: 'Test Device', }); expect(device.name).toEqual('Test Device'); expect(device.address).toEqual('192.168.1.50'); expect(device.featureCount).toEqual(0); expect(device.hasFeature('scan')).toEqual(false); // selectFeature should throw when feature doesn't exist let error: Error | null = null; try { device.selectFeature('scan'); } catch (e) { error = e as Error; } expect(error).not.toBeNull(); expect(error?.message).toContain("does not have feature 'scan'"); // getFeature should return undefined expect(device.getFeature('scan')).toBeUndefined(); }); // Test IP helpers tap.test('should export IP helper utilities', async () => { expect(devicemanager.isValidIp).toBeDefined(); expect(devicemanager.cidrToIps).toBeDefined(); expect(devicemanager.getLocalSubnet).toBeDefined(); // Test isValidIp expect(devicemanager.isValidIp('192.168.1.1')).toEqual(true); expect(devicemanager.isValidIp('invalid')).toEqual(false); expect(devicemanager.isValidIp('256.1.1.1')).toEqual(false); }); export default tap.start();