"use strict"; // readme.md says what the code does: its table of interfaces is the one the registry gives, a program it shows is // the text of a file that a test runs, and the other code blocks compile. const { test } = require("node:test"); const assert = require("node:assert/strict"); const fs = require("node:fs"); const path = require("node:path"); const { run, ROOT } = require("./helpers/examples.js"); const { table, update, shown, BEGIN, END, DRIVEN, README } = require("../scripts/capability-table.js"); const alex2node = require(".."); const readme = fs.readFileSync(README, "utf8"); const AsyncFunction = (async () => {}).constructor; // The js code blocks, each with the file its marker line names const blocks = [...readme.matchAll(/(?:\n)?```js\n([\s\S]*?)\n```/g)] .map(([, file, code]) => ({ file, code })); const loads = (code) => /require\("alex2node"\)|from "alex2node"/.test(code); test("the table of interfaces and the files in the readme are the ones of the code: npm run docs", () => { assert.equal(update(readme), readme); }); test("the table has a row for every described interface, and a line for the others", () => { const text = table(); for (const { namespace, tier } of alex2node.registry.list()) { const row = text.split("\n").filter((line) => line.startsWith(`| [${namespace}](`)); assert.equal(row.length, tier === 3 ? 0 : 1, namespace); assert.ok(text.includes(`[${namespace}](`), namespace); } assert.ok(readme.indexOf(BEGIN) < readme.indexOf(END)); }); test("an interface is said to be driven through Alexa only when a run is recorded for it", () => { // The run of 2026-09-28 with 33 test devices on the 2.0 API. A name is added here with the record of its run. assert.deepEqual(Object.keys(DRIVEN).sort(), [ "Alexa", "Alexa.BrightnessController", "Alexa.ColorController", "Alexa.ColorTemperatureController", "Alexa.ContactSensor", "Alexa.DoorbellEventSource", "Alexa.InventoryLevelSensor", "Alexa.LockController", "Alexa.ModeController", "Alexa.MotionSensor", "Alexa.PercentageController", "Alexa.PowerController", "Alexa.PowerLevelController", "Alexa.RangeController", "Alexa.SceneController", "Alexa.SecurityPanelController", "Alexa.SimpleEventSource", "Alexa.TemperatureSensor", "Alexa.ThermostatController", "Alexa.ThermostatController.Schedule", "Alexa.ToggleController", ]); const rows = table().split("\n").filter((line) => line.startsWith("| [Alexa")); for (const line of rows) { const cells = line.split(" | "); const namespace = cells[0].slice(3, cells[0].indexOf("]")); assert.equal(cells[cells.length - 1].replace(/ \|$/, ""), DRIVEN[namespace] ?? "-", namespace); } }); test("a program in the readme is a file, and a test runs the file", () => { assert.deepEqual(shown(readme), ["examples/lamp.js", "examples/testing/lamp.test.js", "examples/legacy/ExamplePowerController.js"]); // More than the line that loads the library: a program, which has to be one of the files const programs = blocks.filter(({ code }) => loads(code) && code.split("\n").length > 1); assert.deepEqual(programs.map(({ file }) => file), shown(readme)); const examples = fs.readFileSync(path.join(__dirname, "examples.test.js"), "utf8"); assert.ok(examples.includes('start("lamp.js"')); assert.ok("ExamplePowerController.js" in require("./fixtures/legacy-examples/discovery-1.5.2.json")); // examples/testing/lamp.test.js: the next test }); test("examples/testing/lamp.test.js passes, without a broker", async () => { // LOOPBACK_PORT 1, where nothing listens: a connection would fail const example = await run(path.join("testing", "lamp.test.js")); assert.equal(await example.exited, 0, example.output()); assert.match(example.output(), /pass 4\n/); assert.match(example.output(), /fail 0\n/); }); test("the other code blocks of the readme compile, and load what the library exports", () => { const fragments = blocks.filter(({ file }) => !file); assert.ok(fragments.length >= 8); for (const { code } of fragments) { for (const [, names] of code.matchAll(/(?:const|import) \{([^}]+)\} (?:= require\("alex2node"\)|from "alex2node")/g)) { for (const name of names.split(",").map((part) => part.trim())) assert.ok(name in alex2node, `${name} is not an export`); } const body = code.split("\n").filter((line) => !/^import .* from "alex2node";$/.test(line)).join("\n"); assert.doesNotThrow(() => new AsyncFunction(body), `this block does not compile:\n${code}`); } }); test("what the readme calls on AlexaErrors and on the registry is there", () => { for (const [, helper] of readme.matchAll(/AlexaErrors\.(\w+)\(/g)) assert.equal(typeof alex2node.AlexaErrors[helper], "function", helper); for (const [, namespace] of readme.matchAll(/registry\.get\("([^"]+)"\)/g)) assert.ok(alex2node.registry.has(namespace), namespace); assert.equal(Object.keys(require("../dist/cjs/registry/catalog.js").ERROR_TYPES).length, 73); });