registry: Lock, Color, ColorTemperature, Percentage, PowerLevel, Contact, Motion, Humidity

Eight descriptors written from their pages, each with its version, the value of its property and the payload of
every directive. Seven replace a stub; Alexa.HumiditySensor is new, as AlexaInterfaceType.HUMIDITY_SENSOR.
LockController is deferrable: defer() on a lock logs no warning.

A 1.x declaration of LockController, MotionSensor, PercentageController or PowerLevelController now lists its
property in discovery, where 1.5.2 listed none: the zoo's lock, motion sensor and heater come out as the JSON
Alexa accepted. A payload that does not fit (hue 361, 900 K) is answered with INVALID_VALUE.

48 examples of the eight pages are saved as fixtures. 191 tests pass, 168 before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 20:29:04 +00:00
parent feff828ec1
commit af1489696d
111 changed files with 2971 additions and 45 deletions

View file

@ -3,7 +3,7 @@
// and every interface name of 1.x resolves.
const { test } = require("node:test");
const assert = require("node:assert/strict");
const { registry, AlexaInterface, AlexaInterfaceType, DeclarationError } = require("alex2node");
const { registry, AlexaInterface, AlexaInterfaceType, DeclarationError, SchemaError } = require("alex2node");
const interfaces = require("../fixtures/interfaces.js");
const { doc, examples, capabilities, reported } = require("../helpers/fixtures.js");
@ -30,7 +30,7 @@ test("a descriptor of tier 1 or 2 has an entry in test/fixtures/interfaces.js, a
assert.deepEqual(described.map((descriptor) => descriptor.namespace), interfaces.map((entry) => entry.namespace).sort());
});
for (const { namespace, page, declared } of interfaces) {
for (const { namespace, page, declared, unfit = [] } of interfaces) {
test(`${namespace}: version, properties, directive payloads and property values of ${page}.html`, () => {
const descriptor = registry.get(namespace);
assert.ok(descriptor.doc.endsWith(`/${page}.html`), descriptor.doc);
@ -65,6 +65,9 @@ for (const { namespace, page, declared } of interfaces) {
assert.deepEqual(known.value.parse(property.value, property.name), property.value, example);
}
if (Object.keys(descriptor.properties).length > 0) assert.ok(values.length > 0, "the page reports no property of the interface");
for (const [name, value] of unfit) {
assert.throws(() => descriptor.properties[name].value.parse(value, name), SchemaError, `${name} ${JSON.stringify(value)}`);
}
});
}
@ -116,9 +119,10 @@ test("registry.get: the namespace and the AlexaInterfaceType member give the sam
assert.throws(() => registry.get(AlexaInterfaceType.UNKNOWN), DeclarationError);
});
test("every AlexaInterfaceType of 1.x is in the registry: described, or a stub with the version and properties of 1.5.2", () => {
test("every AlexaInterfaceType is in the registry: described, or a stub with the version and properties of 1.5.2", () => {
const names = Object.values(AlexaInterfaceType).filter((name) => name !== AlexaInterfaceType.UNKNOWN);
assert.equal(names.length, 69);
// The 69 of 1.x and HUMIDITY_SENSOR
assert.equal(names.length, 70);
assert.deepEqual(names.filter((name) => !registry.has(name)), []);
// "Alexa" is the one interface that was never in the enum
assert.deepEqual(registry.list().map((descriptor) => descriptor.namespace).filter((name) => !names.includes(name)), ["Alexa"]);