test: split the 1.5.2 suite into a harness and per-topic files

test/helpers/harness.js holds the aedes broker, the Alexa-side watcher, until() and the cleanups, plus directive(),
connected() and setup(), which the old file spelled out in each test. test/alex2node.test.js (194 lines, 8 tests)
becomes connection, discovery, directives, change-report and typings.

The 50-line round-trip test is cut at its topic boundaries and the duplicate-endpointId test no longer carries the
thermostat discovery check, so a failure names a case: 8 tests become 15, every 1.5.2 assertion kept. Four checks
are stricter: the "directive" event is compared whole, the StateReport is checked for its token and properties, the
Celsius conversion covers lowerSetpoint as well as temperature, and a duplicate endpointId is listed once.

No change to src/ or dist/. npm test: 15 pass in 0.9 s.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 13:45:38 +00:00
parent 275f00f8a7
commit 58869d44c1
7 changed files with 447 additions and 194 deletions

37
test/typings.test.js Normal file
View file

@ -0,0 +1,37 @@
"use strict";
// The declarations tracked in dist/: what a TypeScript consumer compiles against.
const { test } = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const { ActionMapping, AlexaActions, AlexaStatusMessage, EndpointHealth } = require("../dist/index.js");
const DIST = path.join(__dirname, "..", "dist");
const MODULES = [
"index", "Alex2Node", "Device", "AlexaInterface", "AlexaStatusMessage", "AlexaErrorResponse", "ActionMapping",
"DisplayCategory",
];
const declaration = (name) => fs.readFileSync(path.join(DIST, `${name}.d.ts`), "utf8");
test("1.5.2 typings: dist ships declarations, ActionMapping's payload is optional, addHealthProp takes the enum or the string", () => {
for (const name of MODULES) assert.ok(fs.existsSync(path.join(DIST, `${name}.d.ts`)), `dist/${name}.d.ts`);
// The declaration text itself: a revert in src/ would rebuild narrower types, and the runtime checks below would
// not notice.
assert.match(declaration("ActionMapping"), /constructor\(actions: AlexaActions\[\], directiveName: string, directivePayload\?: string\);/);
assert.match(declaration("AlexaStatusMessage"), /addHealthProp\(health: EndpointHealth \| `\$\{EndpointHealth\}`, uncertaintyInMs\?: number\): this;/);
assert.match(declaration("AlexaInterface"), /addSupportedModes\(modes: Array<string \| SupportedMode>\): void;/);
assert.match(declaration("index"), /export type \{ SupportedMode \} from "\.\/AlexaInterface";/);
assert.deepEqual(new ActionMapping([AlexaActions.Close], "TurnOn").toJSON(), {
"@type": "ActionsToDirective",
actions: ["Alexa.Actions.Close"],
directive: { name: "TurnOn" },
});
const health = (h) => {
const message = new AlexaStatusMessage("ct", "root", "e", null).addHealthProp(h).toJSON();
return message.context.properties[0].value;
};
assert.deepEqual(health(EndpointHealth.OK), { value: "OK" });
assert.deepEqual(health("UNREACHABLE"), { value: "UNREACHABLE" });
});