"use strict"; // The vocabularies copied from Amazon's pages: their sizes as counted on the pages on 2026-09-28, and how they // relate to the 1.x enums. const { test } = require("node:test"); const assert = require("node:assert/strict"); const { Actions, AlexaActions, AlexaErrorType, Assets, DisplayCategories, DisplayCategory, States, Units, } = require("alex2node"); const { ERROR_TYPES, RESERVED_WORDS, LIMITS } = require("../../dist/cjs/registry/catalog.js"); const unique = (list) => new Set(list).size === list.length; test("assets: the 103 ids of the global Alexa catalog, 23 of them units of measure", () => { assert.equal(Assets.length, 103); assert.ok(unique(Assets)); for (const id of Assets) assert.match(id, /^Alexa\.(Actions|Button|DeviceName|Gestures?|Setting|Shower|Unit|Value)\.[A-Za-z0-9.]+$/); assert.equal(Units.length, 23); assert.deepEqual(Units, Assets.filter((id) => id.startsWith("Alexa.Unit."))); assert.ok(Units.includes("Alexa.Unit.Percent")); // The page has "Gesture" seven times and "Gestures" once assert.deepEqual(Assets.filter((id) => id.startsWith("Alexa.Gestures.")), ["Alexa.Gestures.DoubleTap"]); }); test("semantics: six actions, the ones the AlexaActions enum of 1.x has, and nine states", () => { assert.deepEqual([...Actions].sort(), Object.values(AlexaActions).sort()); assert.deepEqual(States.map((id) => id.replace("Alexa.States.", "")), ["Open", "Closed", "EcoOn", "EcoOff", "Low", "Empty", "Full", "Done", "Stuck"]); }); test("display categories: the 56 of the page; the enum has them all and keeps VEHICLE", () => { assert.equal(DisplayCategories.length, 56); assert.ok(unique(DisplayCategories)); const inEnum = Object.values(DisplayCategory); assert.deepEqual(DisplayCategories.filter((category) => !inEnum.includes(category)), []); assert.deepEqual(inEnum.filter((category) => !DisplayCategories.includes(category)), ["VEHICLE"]); assert.equal(DisplayCategory.VACUUM, "VACUUM"); for (const [key, value] of Object.entries(DisplayCategory)) assert.equal(key, value); }); test("error types: the 73 of the error type table, each under the namespace of its interface", () => { assert.equal(Object.keys(ERROR_TYPES).length, 73); assert.equal(ERROR_TYPES.ENDPOINT_UNREACHABLE, "Alexa"); assert.equal(ERROR_TYPES.INVALID_VALUE, "Alexa"); assert.equal(ERROR_TYPES.THERMOSTAT_IS_OFF, "Alexa.ThermostatController"); assert.equal(ERROR_TYPES.UNAUTHORIZED, "Alexa.SecurityPanelController"); assert.equal(ERROR_TYPES.OBSTACLE_DETECTED, "Alexa.Safety"); assert.equal(ERROR_TYPES.TEMPERATURE_VALUE_OUT_OF_RANGE, "Alexa", "the generic one, not a thermostat error"); const namespaces = [...new Set(Object.values(ERROR_TYPES))].sort(); assert.equal(namespaces.length, 11); for (const namespace of namespaces) assert.match(namespace, /^Alexa(\.[A-Za-z]+)*$/); // AlexaErrorType of 1.x has every type of the table and two that the table does not list const inEnum = Object.values(AlexaErrorType); assert.deepEqual(Object.keys(ERROR_TYPES).filter((type) => !inEnum.includes(type)), []); assert.deepEqual(inEnum.filter((type) => !(type in ERROR_TYPES)).sort(), ["EXCEEDED_PIN_ATTEMPTS", "PIN_SETUP_REQUIRED"]); }); test("reserved words and limits", () => { assert.equal(RESERVED_WORDS.length, 22); assert.ok(unique(RESERVED_WORDS)); for (const word of RESERVED_WORDS) assert.equal(word, word.toLowerCase()); assert.deepEqual(LIMITS, { endpointsPerCustomer: 300, capabilitiesPerEndpoint: 100, endpointIdLength: 256, friendlyNameLength: 256, sceneFriendlyNameLength: 128, manufacturerNameLength: 128, descriptionLength: 128, additionalAttributeLength: 256, cookieBytes: 5000, }); });