import { expect, tap } from '@git.zone/tstest/tapbundle'; import { DucoClient, DucoConfigFlow, DucoIntegration, DucoMapper, HomeAssistantDucoIntegration, createDucoDiscoveryDescriptor, ducoProfile, type IDucoSnapshot } from '../../ts/integrations/duco/index.js'; const rawData = { ventilation_state: 'cnt2', target_flow_level: 66, rssi_wifi: -48, }; tap.test('matches manual Duco candidates and creates config flow output', async () => { const descriptor = createDucoDiscoveryDescriptor(); const matcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'duco-manual-match'); const result = await matcher!.matches({ host: 'duco.local', name: 'Duco Ventilation', metadata: { rawData } }, {}); expect(result.matched).toBeTrue(); expect(result.candidate?.integrationDomain).toEqual('duco'); const validation = await descriptor.getValidators()[0].validate(result.candidate!, {}); expect(validation.matched).toBeTrue(); const done = await (await new DucoConfigFlow().start(result.candidate!, {})).submit!({}); expect(done.kind).toEqual('done'); expect(done.config?.host).toEqual('duco.local'); }); tap.test('maps Duco raw snapshots to runtime devices and entities', async () => { const client = new DucoClient({ name: 'Duco Test', rawData }); const snapshot = await client.getSnapshot(); const devices = DucoMapper.toDevices(snapshot); const entities = DucoMapper.toEntities(snapshot); expect(snapshot.online).toBeTrue(); expect(snapshot.source).toEqual('manual'); expect(devices[0].integrationDomain).toEqual('duco'); expect(devices[0].manufacturer).toEqual('Duco'); expect(entities.length).toEqual(3); }); tap.test('exposes Duco runtime services without fake live control', async () => { const integration = new HomeAssistantDucoIntegration(); expect(integration.domain).toEqual('duco'); expect(integration.status).toEqual('control-runtime'); expect(ducoProfile.metadata.qualityScale).toEqual('platinum'); expect(ducoProfile.metadata.requirements).toEqual(['python-duco-client==0.4.0']); const runtime = await new DucoIntegration().setup({ name: 'Duco Runtime', rawData }, {}); const status = await runtime.callService!({ domain: 'duco', service: 'status', target: {} }); const snapshot = status.data as IDucoSnapshot; expect(status.success).toBeTrue(); expect(snapshot.online).toBeTrue(); expect((await runtime.devices())[0].name).toEqual('Duco Runtime'); const liveCommand = await runtime.callService!({ domain: 'fan', service: 'set_percentage', target: {}, data: { percentage: 66 } }); expect(liveCommand.success).toBeFalse(); expect(Boolean(liveCommand.error)).toBeTrue(); await runtime.destroy(); const executorRuntime = await new DucoIntegration().setup({ name: 'Duco Executor', rawData, commandExecutor: { execute: async (requestArg) => ({ success: true, data: { service: requestArg.service } }), }, }, {}); const executed = await executorRuntime.callService!({ domain: 'fan', service: 'set_preset_mode', target: {}, data: { preset_mode: 'auto' } }); expect(executed.success).toBeTrue(); expect((executed.data as { service: string }).service).toEqual('set_preset_mode'); await executorRuntime.destroy(); }); export default tap.start();