amaran-light-cli
Version:
Command line tool for controlling Aputure Amaran lights via WebSocket to a local Amaran desktop app.
195 lines • 8.82 kB
JavaScript
import { Command } from 'commander';
import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import registerCommands from '../../commands.js';
import LightController from '../../deviceControl/lightControl.js';
import { MockLightServer } from '../../test/MockLightServer.js';
const TEST_PORT = 8091; // Use a different port to avoid conflicts
const WS_URL = `ws://localhost:${TEST_PORT}`;
describe('New CLI Commands Integration Tests', () => {
let server;
beforeAll(async () => {
server = new MockLightServer(TEST_PORT);
await new Promise((resolve) => setTimeout(resolve, 500));
});
afterAll(async () => {
await new Promise((resolve) => {
server.close(() => resolve());
});
await new Promise((resolve) => setTimeout(resolve, 100));
});
beforeEach(() => {
server.resetState();
vi.clearAllMocks();
});
const createDeps = () => {
const controller = new LightController(WS_URL, 'test-cli-new', undefined, false);
return {
createController: async () => {
await new Promise((resolve, reject) => {
const ws = controller.getWebSocket();
const fetchDevices = () => {
controller.getDeviceList((success) => {
if (success)
resolve();
else
reject(new Error('Failed to fetch devices'));
});
};
if (ws.readyState === 1) {
fetchDevices();
}
else {
ws.once('open', () => {
setTimeout(fetchDevices, 50);
});
ws.once('error', reject);
setTimeout(() => reject(new Error('Timeout connecting')), 2000);
}
});
return controller;
},
findDevice: (ctrl, deviceQuery) => {
const devices = ctrl.getDevices();
let device = devices.find((d) => d.node_id === deviceQuery || d.id === deviceQuery);
if (!device) {
const q = deviceQuery.toLowerCase();
device = devices.find((d) => {
const nm = (d.device_name || d.name || '').toLowerCase();
return nm.includes(q);
});
}
return device || null;
},
asyncCommand: (fn) => (...args) => fn(...args),
loadConfig: () => ({}),
saveWsUrl: vi.fn(),
saveConfig: vi.fn(),
};
};
it('should list scenes', async () => {
const program = new Command();
program.exitOverride();
const deps = createDeps();
registerCommands(program, deps);
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {
/* no-op */
});
await program.parseAsync(['node', 'test', 'scene', 'list']);
await new Promise((resolve) => setTimeout(resolve, 100));
// Mock server returns empty list by default, so "No scenes found"
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('No scenes found'));
consoleSpy.mockRestore();
});
it('should save a scene', async () => {
const program = new Command();
program.exitOverride();
const deps = createDeps();
registerCommands(program, deps);
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {
/* no-op */
});
await program.parseAsync(['node', 'test', 'scene', 'save', 'MyScene']);
await new Promise((resolve) => setTimeout(resolve, 100));
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Scene "MyScene" saved successfully'));
consoleSpy.mockRestore();
});
it('should recall a scene', async () => {
const program = new Command();
program.exitOverride();
const deps = createDeps();
registerCommands(program, deps);
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {
/* no-op */
});
await program.parseAsync(['node', 'test', 'scene', 'recall', 'scene-123']);
await new Promise((resolve) => setTimeout(resolve, 100));
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Scene scene-123 recalled successfully'));
consoleSpy.mockRestore();
});
it('should create a group', async () => {
const program = new Command();
program.exitOverride();
const deps = createDeps();
registerCommands(program, deps);
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {
/* no-op */
});
await program.parseAsync(['node', 'test', 'group', 'create', 'A']);
await new Promise((resolve) => setTimeout(resolve, 100));
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Group "A" created successfully'));
consoleSpy.mockRestore();
});
it('should set fan mode', async () => {
const program = new Command();
program.exitOverride();
const deps = createDeps();
registerCommands(program, deps);
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {
/* no-op */
});
await program.parseAsync(['node', 'test', 'fan', 'mode', '400J5-F2C008', '1']); // Mode 1
await new Promise((resolve) => setTimeout(resolve, 100));
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Fan mode set to 1'));
// Verify state in mock server
const state = server.getDeviceState('400J5-F2C008');
expect(state?.fan_mode).toBe(1); // Args are typically strings via CLI, mock handles appropriately
consoleSpy.mockRestore();
});
it('should set effect', async () => {
const program = new Command();
program.exitOverride();
const deps = createDeps();
registerCommands(program, deps);
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {
/* no-op */
});
await program.parseAsync(['node', 'test', 'effect', 'set', '400J5-F2C008', 'fire']);
await new Promise((resolve) => setTimeout(resolve, 100));
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Effect fire set'));
const state = server.getDeviceState('400J5-F2C008');
expect(state?.work_mode).toBe('EFFECT');
expect(state?.effect_type).toBe('fire');
consoleSpy.mockRestore();
});
it('should check firmware info', async () => {
const program = new Command();
program.exitOverride();
const deps = createDeps();
registerCommands(program, deps);
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {
/* no-op */
});
await program.parseAsync(['node', 'test', 'firmware', 'check', '400J5-F2C008']);
await new Promise((resolve) => setTimeout(resolve, 100));
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Firmware Status'));
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Firmware is up to date'));
consoleSpy.mockRestore();
});
it('should apply quickshot', async () => {
const program = new Command();
program.exitOverride();
const deps = createDeps();
registerCommands(program, deps);
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {
/* no-op */
});
await program.parseAsync(['node', 'test', 'quickshot', 'set', 'qs-999']);
await new Promise((resolve) => setTimeout(resolve, 100));
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Quickshot qs-999 applied'));
consoleSpy.mockRestore();
});
it('should recall preset', async () => {
const program = new Command();
program.exitOverride();
const deps = createDeps();
registerCommands(program, deps);
const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {
/* no-op */
});
await program.parseAsync(['node', 'test', 'preset', 'recall', '400J5-F2C008', 'p1']);
await new Promise((resolve) => setTimeout(resolve, 100));
expect(consoleSpy).toHaveBeenCalledWith(expect.stringContaining('Preset p1 recalled'));
consoleSpy.mockRestore();
});
});
//# sourceMappingURL=newCommands.test.js.map