src/transport.ts has the Publisher interface, MqttPublisher (the client the bridge has at the time) and MemoryPublisher (tests without a broker); src/topics.ts names the four topics the library publishes to. Device, AlexaStatusMessage, AlexaErrorResponse and sendSceneResponse shared three copies of the publish-and-report code: they now call one send() that resolves the topic or "" and never rejects. registerDevice() and addDevice() work before connect(); a send() without a connection resolves "" and the "error" event says to call connect(). unregisterDevice() and clearDevices() take the publisher from the device. Device.setMqttClient() is gone, the first constructor argument of Device is ignored, and the message classes take a Publisher where they took the client. Tests: 108 -> 113. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
65 lines
3.3 KiB
JavaScript
65 lines
3.3 KiB
JavaScript
"use strict";
|
|
// Publishing without a broker: MemoryPublisher under a device, a device on no bridge, and the topics by name.
|
|
const { test } = require("node:test");
|
|
const assert = require("node:assert/strict");
|
|
const { Alex2MQTT, MemoryPublisher, PowerController, topics } = require("alex2node");
|
|
const { endpoint } = require("./helpers/endpoint.js");
|
|
|
|
test("the topics of the contract, \"alexaResponce\" spelt as the backend spells it", () => {
|
|
assert.equal(topics.discoverReply("root"), "root/discover_r");
|
|
assert.equal(topics.response("root", "lamp-1"), "root/lamp-1/alexaResponce");
|
|
assert.equal(topics.deferred("root", "lamp-1"), "root/lamp-1/deferredResponse");
|
|
assert.equal(topics.changeReport("root"), "root/changeReport");
|
|
});
|
|
|
|
test("MemoryPublisher: what a device sends, by topic, as a subscriber parses it", async () => {
|
|
const lamp = endpoint("lamp-1");
|
|
const sent = lamp.publisher = new MemoryPublisher();
|
|
|
|
assert.equal(await lamp.getStatusMessage("ct", true).addPowerControllerProp(PowerController.ON).send(), "root/lamp-1/alexaResponce");
|
|
assert.equal(await lamp.getErrorMessage("ct").send(true), "root/lamp-1/deferredResponse");
|
|
assert.equal(await lamp.sendSceneResponse("ct", true), "root/lamp-1/alexaResponce");
|
|
assert.equal(await lamp.getChangeReport().addPowerControllerProp(PowerController.OFF).send(), "root/changeReport");
|
|
assert.deepEqual(sent.published.map(({ topic, message }) => [topic, message.event.header.name]), [
|
|
["root/lamp-1/alexaResponce", "Response"],
|
|
["root/lamp-1/deferredResponse", "ErrorResponse"],
|
|
["root/lamp-1/alexaResponce", "ActivationStarted"],
|
|
["root/changeReport", "ChangeReport"],
|
|
]);
|
|
assert.deepEqual(await sent.publish("root/x", { a: 1, b: undefined }), { ok: true, topic: "root/x" });
|
|
assert.deepEqual(sent.published[4].message, { a: 1 });
|
|
});
|
|
|
|
test("MemoryPublisher.failWith: send() resolves \"\" and the error is reported, nothing is kept", async () => {
|
|
const lamp = endpoint("lamp-1");
|
|
const sent = lamp.publisher = new MemoryPublisher();
|
|
sent.failWith = new Error("broker gone");
|
|
const reported = [];
|
|
lamp.onPublishError = (err) => reported.push(err.message);
|
|
|
|
assert.equal(await lamp.sendSceneResponse("ct", false), "");
|
|
assert.equal(await lamp.getErrorMessage("ct").send(), "");
|
|
assert.deepEqual(reported, ["broker gone", "broker gone"]);
|
|
assert.deepEqual(sent.published, []);
|
|
});
|
|
|
|
test("a device on no bridge: send() resolves \"\" and the error says to register it", async () => {
|
|
const lamp = endpoint("lamp-1");
|
|
const reported = [];
|
|
lamp.onPublishError = (err) => reported.push(err.message);
|
|
assert.equal(await lamp.getStatusMessage("ct", true).send(), "");
|
|
assert.deepEqual(reported, [
|
|
"nothing was published to root/lamp-1/alexaResponce: the device is on no bridge, register it with addDevice() or registerDevice()",
|
|
]);
|
|
});
|
|
|
|
test("unregisterDevice and clearDevices take the publisher from the device", () => {
|
|
const bridge = new Alex2MQTT("u", "p", "root");
|
|
const lamp = bridge.registerDevice("Lamp", "lamp-1", null);
|
|
const plug = bridge.registerDevice("Plug", "plug-1", null);
|
|
assert.ok(lamp.publisher && lamp.publisher === plug.publisher, "one publisher for the devices of a bridge");
|
|
bridge.unregisterDevice("lamp-1");
|
|
assert.equal(lamp.publisher, null);
|
|
bridge.clearDevices();
|
|
assert.equal(plug.publisher, null);
|
|
});
|