'use strict'; // Phase 10 rewrite: drives only the public BaseNodeAdapter surface. // The pre-refactor _registerChild method was renamed to // _scheduleRegistration inside BaseNodeAdapter and now fires automatically // 100ms after construction. We verify the emission by capturing the Port-2 // message on `node.sends` after the registration delay elapses. const test = require('node:test'); const assert = require('node:assert/strict'); const nodeClass = require('../../src/nodeClass'); const { makeUiConfig } = require('../helpers/factories'); function makeRED() { return { nodes: { getNode: () => null } }; } 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() {}, }; } function closeNode(node) { if (node.handlers.close) node.handlers.close(() => {}); } test('scheduled child.register message lands on Port 2 after construction', async () => { const node = makeNode(); const inst = new nodeClass( makeUiConfig({ positionVsParent: 'downstream' }), makeRED(), node, 'reactor', ); try { // BaseNodeAdapter._scheduleRegistration uses a 100ms setTimeout; wait // slightly longer to let it fire. await new Promise((r) => setTimeout(r, 130)); // The registration send is the [null, null, {child.register}] triple. const regSends = node.sends.filter( (s) => Array.isArray(s) && s[0] === null && s[1] === null && s[2] && s[2].topic === 'child.register', ); assert.equal(regSends.length, 1, 'exactly one child.register message expected'); const msg = regSends[0][2]; assert.equal(msg.topic, 'child.register'); assert.equal(msg.payload, node.id); assert.equal(msg.positionVsParent, 'downstream'); // After construction the source is exposed on the node for sibling lookup. assert.strictEqual(node.source, inst.source); } finally { closeNode(node); } }); test('child.register handler ignores unknown child ids without throwing', async () => { const node = makeNode(); const inst = 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); // No child should have been registered into the engine's registry. const registered = inst.source.engine.childRegistrationUtils; assert.ok(registered, 'childRegistrationUtils exists on engine'); } finally { closeNode(node); } });