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:
parent
275f00f8a7
commit
58869d44c1
7 changed files with 447 additions and 194 deletions
104
test/discovery.test.js
Normal file
104
test/discovery.test.js
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
"use strict";
|
||||
// Discovery: a message on <root>/discover is answered on <root>/discover_r with one JSON array, an endpoint object
|
||||
// per registered device.
|
||||
const { test } = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const { Alex2MQTT, AlexaInterfaceType, DisplayCategory } = require("../dist/index.js");
|
||||
const { setup, connected, until } = require("./helpers/harness.js");
|
||||
|
||||
// Ask as Alex2MQTT does and return the endpoints of the one answer.
|
||||
async function discover(alexa, root) {
|
||||
alexa.publish(`${root}/discover`, { namespace: "Alexa.Discovery", name: "Discover" });
|
||||
await until(() => alexa.on(`${root}/discover_r`).length === 1, 3000, "discovery reply");
|
||||
return alexa.on(`${root}/discover_r`)[0];
|
||||
}
|
||||
|
||||
test("discovery answers with every registered device and its capabilities", async () => {
|
||||
const { alexa, bridge } = await setup(Alex2MQTT, "root");
|
||||
const discovered = [];
|
||||
bridge.on("discover", (n) => discovered.push(n));
|
||||
const lamp = bridge.registerDevice("Dining Room Light", "5020AA", DisplayCategory.LIGHT);
|
||||
lamp.addCapability(AlexaInterfaceType.POWER_CONTROLLER, { proactivelyReported: true });
|
||||
lamp.addCapability(AlexaInterfaceType.BRIGHTNESS_CONTROLLER);
|
||||
const scene = bridge.registerDevice("Evening", "scene-1", DisplayCategory.SCENE_TRIGGER);
|
||||
scene.addCapability(AlexaInterfaceType.SCENE_CONTROLLER);
|
||||
|
||||
const endpoints = await discover(alexa, "root");
|
||||
assert.equal(endpoints.length, 2);
|
||||
assert.equal(endpoints[0].friendlyName, "Dining Room Light");
|
||||
assert.deepEqual(endpoints[0].displayCategories, ["LIGHT"]);
|
||||
|
||||
const power = endpoints[0].capabilities.find((c) => c.interface === "Alexa.PowerController");
|
||||
assert.equal(power.properties.proactivelyReported, true);
|
||||
assert.deepEqual(power.properties.supported, [{ name: "powerState" }]);
|
||||
|
||||
// Alexa.SceneController has no properties block
|
||||
const activation = endpoints[1].capabilities.find((c) => c.interface === "Alexa.SceneController");
|
||||
assert.equal(activation.supportsDeactivation, true);
|
||||
assert.equal(activation.version, "3");
|
||||
assert.equal(activation.properties, undefined);
|
||||
|
||||
await until(() => discovered.length === 1, 3000, "the discover event");
|
||||
assert.deepEqual(discovered, [2]);
|
||||
assert.notEqual(bridge.lastDiscoveryAt, null);
|
||||
});
|
||||
|
||||
test("unregisterDevice: the device is gone from the next discovery answer", async () => {
|
||||
const { alexa, bridge } = await setup(Alex2MQTT, "root");
|
||||
const lamp = bridge.registerDevice("Dining Room Light", "5020AA", DisplayCategory.LIGHT);
|
||||
lamp.addCapability(AlexaInterfaceType.POWER_CONTROLLER);
|
||||
const scene = bridge.registerDevice("Evening", "scene-1", DisplayCategory.SCENE_TRIGGER);
|
||||
scene.addCapability(AlexaInterfaceType.SCENE_CONTROLLER);
|
||||
|
||||
assert.equal(bridge.unregisterDevice("scene-1"), true);
|
||||
assert.equal(bridge.unregisterDevice("scene-1"), false);
|
||||
assert.equal(bridge.getDevices().length, 1);
|
||||
|
||||
const endpoints = await discover(alexa, "root");
|
||||
assert.deepEqual(endpoints.map((e) => e.endpointId), ["5020AA"]);
|
||||
});
|
||||
|
||||
test("registerDevice with an endpointId already registered returns the existing device and warns", async () => {
|
||||
const logs = [];
|
||||
const { url, alexa, bridge } = await setup(Alex2MQTT, "root", { log: (m) => logs.push(m) });
|
||||
const first = bridge.registerDevice("Lamp A", "same", DisplayCategory.LIGHT);
|
||||
first.addCapability(AlexaInterfaceType.POWER_CONTROLLER);
|
||||
const again = bridge.registerDevice("Lamp B", "same", DisplayCategory.SWITCH);
|
||||
assert.equal(again, first);
|
||||
assert.equal(again.name, "Lamp A");
|
||||
assert.equal(bridge.getDevices().length, 1);
|
||||
assert.ok(logs.some((m) => /warning: registerDevice\("same"\)/.test(m)), "warned through the log hook");
|
||||
|
||||
const endpoints = await discover(alexa, "root");
|
||||
assert.deepEqual(endpoints.map((e) => e.endpointId), ["same"]);
|
||||
|
||||
// Without a log hook (the examples and the Quick Start set none) the warning falls back to console.warn.
|
||||
const quiet = await connected(new Alex2MQTT("u", "p", "root-quiet", false, { host: url }));
|
||||
const warned = [];
|
||||
const realWarn = console.warn;
|
||||
console.warn = (...args) => warned.push(args.join(" "));
|
||||
try {
|
||||
quiet.registerDevice("Q", "same", null);
|
||||
assert.equal(quiet.registerDevice("Q again", "same", null).name, "Q");
|
||||
} finally {
|
||||
console.warn = realWarn;
|
||||
}
|
||||
assert.ok(warned.some((m) => /warning: registerDevice\("same"\)/.test(m)), "console.warn without a log hook");
|
||||
});
|
||||
|
||||
test("ThermostatController discovery: version 3.2, targetSetpoint listed with both setpoints and the mode", async () => {
|
||||
const { alexa, bridge } = await setup(Alex2MQTT, "root");
|
||||
const lamp = bridge.registerDevice("Lamp", "lamp-1", DisplayCategory.LIGHT);
|
||||
lamp.addCapability(AlexaInterfaceType.POWER_CONTROLLER);
|
||||
const thermostat = bridge.registerDevice("Thermostat", "thermo-1", DisplayCategory.THERMOSTAT);
|
||||
thermostat.addCapability(AlexaInterfaceType.THERMOSTAT_CONTROLLER);
|
||||
|
||||
const endpoints = await discover(alexa, "root");
|
||||
assert.deepEqual(endpoints.map((e) => e.endpointId), ["lamp-1", "thermo-1"]);
|
||||
const capability = endpoints[1].capabilities.find((c) => c.interface === "Alexa.ThermostatController");
|
||||
assert.equal(capability.version, "3.2");
|
||||
assert.deepEqual(
|
||||
capability.properties.supported.map((p) => p.name),
|
||||
["targetSetpoint", "lowerSetpoint", "upperSetpoint", "thermostatMode"]
|
||||
);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue