messages: DoorbellPress is sent with the empty context of its page

proactiveEvent() built every proactive event without a context, so doorbellPress() and
device.raise(DoorbellEventSource, "DoorbellPress") left out the "context": {} that the example of
alexa-doorbelleventsource.html has. The Event of Alexa.SimpleEventSource is printed without one, so
the event descriptor says which it is (emptyContext) and raise() passes it on to the builder.

A raised DoorbellPress is now { event, context: {} }, 13 bytes longer; the Event of a button is
unchanged. The tests compare the keys and the context of the built message with the fixture of the
page, for the builder, the descriptor and raise(). 267 tests pass.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 21:08:10 +00:00
parent 3a07c861b1
commit 4a3dd81bcf
20 changed files with 86 additions and 18 deletions

View file

@ -30,7 +30,8 @@ const refused = (raise, problem) => assert.throws(raise, (err) => err instanceof
test("raise() publishes the event on <root>/event, with the endpoint, a new messageId, the time and the usual cause", async () => {
const { device, sent } = doorbell();
const printed = doc("alexa-doorbelleventsource", "DoorbellPress.event").event;
const example = doc("alexa-doorbelleventsource", "DoorbellPress.event");
const printed = example.event;
const before = Date.now();
assert.deepEqual(await device.raise(DoorbellEventSource, "DoorbellPress"), { ok: true, topic: "root/event" });
@ -39,6 +40,10 @@ test("raise() publishes the event on <root>/event, with the endpoint, a new mess
assert.equal(topics.event("root"), "root/event");
assert.deepEqual(sent.published.map(({ topic }) => topic), ["root/event", "root/event", "root/event"]);
for (const { message } of sent.published) {
assert.deepEqual(Object.keys(message).sort(), Object.keys(example).sort());
assert.deepEqual(message.context, example.context);
}
const [first, second, third] = sent.published.map(({ message }) => message.event);
for (const event of [first, second, third]) {
assert.deepEqual(event.endpoint, { endpointId: "door-1" });
@ -62,7 +67,8 @@ test("raise() for an instance: the Event of a button has the instance in its hea
remote.publisher = sent;
const top = remote.add(SimpleEventSource, button("TopButton", ["SinglePush", "DoublePush"]));
remote.add(SimpleEventSource, button("BottomButton", ["SinglePush"]));
const printed = doc("alexa-simpleeventsource", "Event.event").event;
const example = doc("alexa-simpleeventsource", "Event.event");
const printed = example.event;
await remote.raise(SimpleEventSource, "Event", printed.payload, { instance: top.instance, messageId: "push-1" });
assert.deepEqual(sent.published, [{
@ -76,6 +82,7 @@ test("raise() for an instance: the Event of a button has the instance in its hea
},
}]);
assert.equal(printed.header.payloadVersion, "1.0");
assert.deepEqual(Object.keys(sent.published[0].message), Object.keys(example));
const raised = "remote-1: Alexa.SimpleEventSource.Event was not raised: ";
assert.throws(() => remote.raise(SimpleEventSource, "Event", { id: "Button.SinglePush.1" }), {
@ -117,7 +124,7 @@ test("raise() refuses an event the device has no capability for, and one that wo
);
refused(
() => device.raise(DoorbellEventSource, "DoorbellPress", { picture: "x".repeat(topics.EVENT_BYTES) }),
`${was("Alexa.DoorbellEventSource.DoorbellPress")}it is 16296 bytes as JSON, Alex2MQTT takes 16000`
`${was("Alexa.DoorbellEventSource.DoorbellPress")}it is 16309 bytes as JSON, Alex2MQTT takes 16000`
);
assert.deepEqual(sent.published, []);
});

View file

@ -4,6 +4,7 @@
const { test } = require("node:test");
const assert = require("node:assert/strict");
const { messages, MessageError } = require("alex2node");
const { doc } = require("../helpers/fixtures.js");
const { UUID_V4 } = require("../helpers/harness.js");
const AT = "2026-09-28T10:00:00.000Z";
@ -134,17 +135,21 @@ test("sceneEvent: ActivationStarted and DeactivationStarted with the cause and t
assert.deepEqual(stopped.event.payload, { cause: { type: "APP_INTERACTION" }, timestamp: AT });
});
test("doorbellPress: an event without a correlationToken and without a context", () => {
assert.deepEqual(messages.doorbellPress({ endpointId: "door", messageId, timestamp: AT }), {
test("doorbellPress: an event without a correlationToken, with the empty context of the page", () => {
const built = messages.doorbellPress({ endpointId: "door", messageId, timestamp: AT });
assert.deepEqual(built, {
event: {
header: { namespace: "Alexa.DoorbellEventSource", name: "DoorbellPress", messageId, payloadVersion: "3" },
endpoint: { endpointId: "door" },
payload: { cause: { type: "PHYSICAL_INTERACTION" }, timestamp: AT },
},
context: {},
});
assert.deepEqual(built.context, doc("alexa-doorbelleventsource", "DoorbellPress.event").context);
});
test("simpleEvent: the instance in the header, payloadVersion 1.0", () => {
test("simpleEvent: the instance in the header, payloadVersion 1.0, no context as on the page", () => {
assert.equal("context" in doc("alexa-simpleeventsource", "Event.event"), false);
assert.deepEqual(messages.simpleEvent({ endpointId: "button", instance: "Button.Front", id: "Button.SinglePush.1", messageId, timestamp: AT }), {
event: {
header: { namespace: "Alexa.SimpleEventSource", name: "Event", instance: "Button.Front", messageId, payloadVersion: "1.0" },

View file

@ -30,9 +30,15 @@ test("the events of the pages fit the payload of their descriptor, and come back
["Alexa.WakeOnLANController", "alexa-wakeonlancontroller", "WakeUp", "response"],
];
for (const [namespace, page, name, topic] of printed) {
const { header, payload } = doc(page, `${name}.event`).event;
const example = doc(page, `${name}.event`);
const { header, payload } = example.event;
const descriptor = registry.get(namespace);
const event = descriptor.events[name];
// raise() sends a context where the page prints one, and the pages print an empty one or none
if (topic === "proactive") {
assert.equal(event.emptyContext === true, "context" in example, name);
assert.deepEqual(example.context ?? {}, {}, name);
}
assert.deepEqual([header.namespace, header.name, header.payloadVersion], [namespace, event.name, descriptor.version]);
assert.equal(event.topic, topic, name);
assert.equal("correlationToken" in header, topic === "response", name);