Files
integrations/test/daikin/test.daikin.discovery.node.ts
T

71 lines
3.8 KiB
TypeScript

import { expect, tap } from '@git.zone/tstest/tapbundle';
import { DaikinConfigFlow, DaikinMapper, createDaikinDiscoveryDescriptor, type IDaikinRawData } from '../../ts/integrations/daikin/index.js';
tap.test('matches Daikin zeroconf records and creates config flow output', async () => {
const descriptor = createDaikinDiscoveryDescriptor();
const matcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'daikin-zeroconf-match');
const result = await matcher!.matches({ type: '_dkapi._tcp.local.', name: 'Living Daikin._dkapi._tcp.local.', host: 'daikin.local', port: 80, properties: { mac: 'AABBCCDDEEFF', name: 'Living Daikin' } }, {});
expect(result.matched).toBeTrue();
expect(result.candidate?.integrationDomain).toEqual('daikin');
expect(result.candidate?.host).toEqual('daikin.local');
expect(result.candidate?.macAddress).toEqual('aa:bb:cc:dd:ee:ff');
const done = await (await new DaikinConfigFlow().start(result.candidate!, {})).submit!({});
expect(done.kind).toEqual('done');
expect(done.config?.host).toEqual('daikin.local');
expect(done.config?.port).toEqual(80);
expect(done.config?.macAddress).toEqual('aa:bb:cc:dd:ee:ff');
});
tap.test('matches UDP discovery payloads from pydaikin basic_info', async () => {
const descriptor = createDaikinDiscoveryDescriptor();
const matcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'daikin-udp-match');
const result = await matcher!.matches({ host: '192.0.2.10', port: 30050, data: 'ret=OK,type=aircon,name=Office%20Daikin,mac=112233445566,ver=1_0_0' }, {});
expect(result.matched).toBeTrue();
expect(result.normalizedDeviceId).toEqual('11:22:33:44:55:66');
expect(result.candidate?.host).toEqual('192.0.2.10');
expect(result.candidate?.port).toEqual(80);
expect(result.candidate?.metadata?.discoveryProtocol).toEqual('udp');
});
tap.test('matches manual snapshots without requiring live HTTP credentials', async () => {
const rawData: Partial<IDaikinRawData> = {
basicInfo: { name: 'Manual%20Daikin', mac: 'AABBCCDDEEFF' },
controlInfo: { pow: '0', mode: '3', stemp: '22' },
sensorInfo: { htemp: '20' },
};
const snapshot = DaikinMapper.toSnapshot({ config: { name: 'Manual Daikin' }, rawData, online: true, source: 'manual' });
const descriptor = createDaikinDiscoveryDescriptor();
const manualMatcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'daikin-manual-match');
const match = await manualMatcher!.matches({ name: 'Manual Daikin', snapshot }, {});
expect(match.matched).toBeTrue();
expect(match.candidate?.metadata?.snapshot).toEqual(snapshot);
const validation = await descriptor.getValidators()[0].validate(match.candidate!, {});
expect(validation.matched).toBeTrue();
const done = await (await new DaikinConfigFlow().start(match.candidate!, {})).submit!({});
expect(done.kind).toEqual('done');
expect(done.config?.snapshot?.climate.hvacMode).toEqual('off');
});
tap.test('rejects mixed API key and password authentication', async () => {
const done = await (await new DaikinConfigFlow().start({ source: 'manual', integrationDomain: 'daikin', host: 'daikin.local' }, {})).submit!({ apiKey: 'key', password: 'pass' });
expect(done.kind).toEqual('error');
expect(done.error).toContain('either API key or password');
});
tap.test('rejects candidates without Daikin hints or usable data', async () => {
const descriptor = createDaikinDiscoveryDescriptor();
const matcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'daikin-manual-match');
const result = await matcher!.matches({ name: 'Generic service' }, {});
expect(result.matched).toBeFalse();
const validation = await descriptor.getValidators()[0].validate({ source: 'manual', name: 'Daikin without host' }, {});
expect(validation.matched).toBeFalse();
});
export default tap.start();