-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathdevice-constants.test.js
More file actions
101 lines (91 loc) · 4.78 KB
/
Copy pathdevice-constants.test.js
File metadata and controls
101 lines (91 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
const assert = require('node:assert/strict');
const { readFileSync } = require('node:fs');
const path = require('node:path');
const { describe, it } = require('node:test');
const { DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES, DEVICE_FEATURE_UNITS } = require('../lib/device-constants');
const TYPINGS = readFileSync(path.join(__dirname, '..', 'index.d.ts'), 'utf8');
/**
* Reads back the `readonly KEY: 'value';` entries a constant is declared with in
* index.d.ts, as the same shape as the runtime object (one level of nesting for
* DEVICE_FEATURE_TYPES), so both can be compared key by key.
*/
function parseDeclaration(name) {
const start = TYPINGS.indexOf(`export declare const ${name}: {`);
assert.notEqual(start, -1, `${name} is not declared in index.d.ts`);
const end = TYPINGS.indexOf('\n};', start);
assert.notEqual(end, -1, `the declaration of ${name} is not terminated in index.d.ts`);
const declaration = {};
let group = null;
for (const line of TYPINGS.slice(start, end).split('\n').slice(1)) {
const entry = line.match(/^\s+readonly ([A-Z0-9_]+): '(.*)';$/);
if (entry) {
(group ?? declaration)[entry[1]] = entry[2];
continue;
}
const groupStart = line.match(/^\s+readonly ([A-Z0-9_]+): \{$/);
if (groupStart) {
group = {};
declaration[groupStart[1]] = group;
} else if (/^\s+\};$/.test(line)) {
group = null;
}
}
return declaration;
}
describe('device constants', () => {
it('should expose the canonical category strings', () => {
assert.equal(DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR, 'temperature-sensor');
assert.equal(DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR, 'motion-sensor');
assert.equal(DEVICE_FEATURE_CATEGORIES.SWITCH, 'switch');
assert.equal(DEVICE_FEATURE_CATEGORIES.LIGHT, 'light');
assert.equal(DEVICE_FEATURE_CATEGORIES.BATTERY_STORAGE, 'battery-storage');
assert.equal(DEVICE_FEATURE_CATEGORIES.WATER_VALVE, 'water-valve');
assert.equal(DEVICE_FEATURE_CATEGORIES.DOORBELL, 'doorbell');
assert.equal(DEVICE_FEATURE_CATEGORIES.CHARGING_STATION, 'charging-station');
assert.equal(DEVICE_FEATURE_CATEGORIES.WATER_HEATER, 'water-heater');
});
it('should expose the canonical type strings, grouped by category', () => {
assert.equal(DEVICE_FEATURE_TYPES.LIGHT.BINARY, 'binary');
assert.equal(DEVICE_FEATURE_TYPES.LIGHT.BRIGHTNESS, 'brightness');
assert.equal(DEVICE_FEATURE_TYPES.SENSOR.DECIMAL, 'decimal');
assert.equal(DEVICE_FEATURE_TYPES.SWITCH.POWER, 'power');
assert.equal(DEVICE_FEATURE_TYPES.BATTERY_STORAGE.CHARGE_POWER, 'charge-power');
assert.equal(DEVICE_FEATURE_TYPES.WATER_VALVE.FLOW, 'flow');
assert.equal(DEVICE_FEATURE_TYPES.DOORBELL.RING, 'ring');
assert.equal(DEVICE_FEATURE_TYPES.AIR_CONDITIONING.FAN_SPEED, 'fan-speed');
assert.equal(DEVICE_FEATURE_TYPES.AIR_CONDITIONING.SWING_HORIZONTAL, 'swing-horizontal');
assert.equal(DEVICE_FEATURE_TYPES.AIR_CONDITIONING.SWING_VERTICAL, 'swing-vertical');
assert.equal(DEVICE_FEATURE_TYPES.CHARGING_STATION.CONNECTOR_STATUS, 'connector-status');
assert.equal(DEVICE_FEATURE_TYPES.CHARGING_STATION.CHARGING_STATE, 'charging-state');
assert.equal(DEVICE_FEATURE_TYPES.THERMOSTAT.MODE, 'mode');
assert.equal(DEVICE_FEATURE_TYPES.THERMOSTAT.OPERATING_STATE, 'operating-state');
assert.equal(DEVICE_FEATURE_TYPES.WATER_HEATER.REMAINING_HOT_WATER, 'remaining-hot-water');
assert.equal(DEVICE_FEATURE_TYPES.WATER_HEATER.BOOST, 'boost');
});
it('should expose the canonical unit strings', () => {
assert.equal(DEVICE_FEATURE_UNITS.CELSIUS, 'celsius');
assert.equal(DEVICE_FEATURE_UNITS.FAHRENHEIT, 'fahrenheit');
assert.equal(DEVICE_FEATURE_UNITS.PERCENT, 'percent');
assert.equal(DEVICE_FEATURE_UNITS.WATT, 'watt');
assert.equal(DEVICE_FEATURE_UNITS.CUBIC_METER_PER_HOUR, 'cubic-meter-per-hour');
});
it('should only contain string values (categories and units)', () => {
for (const value of [...Object.values(DEVICE_FEATURE_CATEGORIES), ...Object.values(DEVICE_FEATURE_UNITS)]) {
assert.equal(typeof value, 'string');
}
});
it('should only contain string values, one level deep (types)', () => {
for (const group of Object.values(DEVICE_FEATURE_TYPES)) {
for (const value of Object.values(group)) {
assert.equal(typeof value, 'string');
}
}
});
it('should declare the very same constants in index.d.ts', () => {
// Resyncing with Gladys means editing both lib/device-constants.js and the
// typings: this fails whenever one of the two is forgotten.
assert.deepEqual(parseDeclaration('DEVICE_FEATURE_CATEGORIES'), DEVICE_FEATURE_CATEGORIES);
assert.deepEqual(parseDeclaration('DEVICE_FEATURE_TYPES'), DEVICE_FEATURE_TYPES);
assert.deepEqual(parseDeclaration('DEVICE_FEATURE_UNITS'), DEVICE_FEATURE_UNITS);
});
});