P11.6 wiki regen + Phase 10 private-test rewrites where applicable
For all 11 nodes with auto-gen markers: wiki/Home.md sections 5 (topic contract) and 9 (data model) regenerated via npm run wiki:all. New Unit column shows '<measure> (default <unit>)' for declared topics, '—' otherwise. Effect column now uses descriptor.description (P11.2 field) overriding the generic per-prefix fallback. For rotatingMachine + reactor: Phase 10 test rewrites — 3 + 8 files moved off private nodeClass internals (_attachInputHandler, _commands, _pendingExtras, _registerChild, _tick, etc.) to the public BaseNodeAdapter surface (node.handlers.input, node.source.*). +6 / +7 net new tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,29 +1,91 @@
|
||||
'use strict';
|
||||
|
||||
// Phase 10 rewrite: drives only the public BaseNodeAdapter surface.
|
||||
// A child.register / registerChild msg with an unknown id should resolve
|
||||
// to no-op (the handler logs warn, no throw) and still call done.
|
||||
|
||||
const test = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
|
||||
const NodeClass = require('../../src/nodeClass');
|
||||
const commands = require('../../src/commands');
|
||||
const { createRegistry } = require('generalFunctions');
|
||||
const { makeNodeStub, makeREDStub } = require('../helpers/factories');
|
||||
const nodeClass = require('../../src/nodeClass');
|
||||
const { makeUiConfig } = require('../helpers/factories');
|
||||
|
||||
test('registerChild with unknown node id is ignored without throwing', async () => {
|
||||
const inst = Object.create(NodeClass.prototype);
|
||||
const node = makeNodeStub();
|
||||
function makeRED(nodeMap = {}) {
|
||||
return { nodes: { getNode: (id) => nodeMap[id] || null } };
|
||||
}
|
||||
|
||||
inst.node = node;
|
||||
inst.RED = makeREDStub();
|
||||
inst.source = {
|
||||
logger: { warn: () => {}, info: () => {}, debug: () => {}, error: () => {} },
|
||||
childRegistrationUtils: { registerChild() {} },
|
||||
function makeNode(id = 'reactor-node-1') {
|
||||
const sends = [];
|
||||
const statuses = [];
|
||||
const handlers = {};
|
||||
return {
|
||||
id, sends, statuses, handlers,
|
||||
send(arr) { sends.push(arr); },
|
||||
status(b) { statuses.push(b); },
|
||||
on(ev, fn) { handlers[ev] = fn; },
|
||||
warn() {}, error() {},
|
||||
};
|
||||
inst._commands = createRegistry(commands, { logger: inst.source.logger });
|
||||
inst._attachInputHandler();
|
||||
}
|
||||
|
||||
await assert.doesNotReject(async () => {
|
||||
await node._handlers.input(
|
||||
{ topic: 'registerChild', payload: 'missing-child', positionVsParent: 'upstream' },
|
||||
() => {},
|
||||
() => {},
|
||||
);
|
||||
});
|
||||
function closeNode(node) {
|
||||
if (node.handlers.close) node.handlers.close(() => {});
|
||||
}
|
||||
|
||||
test('registerChild alias with unknown id is ignored without throwing', async () => {
|
||||
const node = makeNode();
|
||||
new nodeClass(makeUiConfig(), makeRED(), node, 'reactor');
|
||||
|
||||
try {
|
||||
let done = 0;
|
||||
await assert.doesNotReject(async () => {
|
||||
await node.handlers.input(
|
||||
{ topic: 'registerChild', payload: 'missing-child', positionVsParent: 'upstream' },
|
||||
() => {},
|
||||
() => { done += 1; },
|
||||
);
|
||||
});
|
||||
assert.equal(done, 1);
|
||||
} finally {
|
||||
closeNode(node);
|
||||
}
|
||||
});
|
||||
|
||||
test('child.register canonical topic with unknown id is ignored without throwing', async () => {
|
||||
const node = makeNode();
|
||||
new nodeClass(makeUiConfig(), makeRED(), node, 'reactor');
|
||||
|
||||
try {
|
||||
let done = 0;
|
||||
await assert.doesNotReject(async () => {
|
||||
await node.handlers.input(
|
||||
{ topic: 'child.register', payload: 'missing-child', positionVsParent: 'upstream' },
|
||||
() => {},
|
||||
() => { done += 1; },
|
||||
);
|
||||
});
|
||||
assert.equal(done, 1);
|
||||
} finally {
|
||||
closeNode(node);
|
||||
}
|
||||
});
|
||||
|
||||
test('child.register with a child that has no .source is ignored without throwing', async () => {
|
||||
const node = makeNode();
|
||||
// The looked-up RED node exists but lacks a `.source` — the handler
|
||||
// guards against this and logs warn.
|
||||
new nodeClass(makeUiConfig(), makeRED({ orphan: {} }), node, 'reactor');
|
||||
|
||||
try {
|
||||
let done = 0;
|
||||
await assert.doesNotReject(async () => {
|
||||
await node.handlers.input(
|
||||
{ topic: 'child.register', payload: 'orphan', positionVsParent: 'upstream' },
|
||||
() => {},
|
||||
() => { done += 1; },
|
||||
);
|
||||
});
|
||||
assert.equal(done, 1);
|
||||
} finally {
|
||||
closeNode(node);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user