import { describe, it, beforeEach } from 'node:test'; import assert from 'node:assert/strict'; import { runStep } from '../src/flows/stepRunner.js'; // Minimal bot double: records every `say` call so we can assert on the // success/failure blockquote UX without touching a real Webex framework. function makeBot() { const said = []; return { said, say(format, text) { said.push({ format, text }); }, }; } describe('runStep', () => { let bot; beforeEach(() => { bot = makeBot(); }); it('returns the resolved value and shows a success blockquote', async () => { const result = await runStep(bot, 'Did the thing', async () => 42); assert.equal(result, 42); assert.equal(bot.said.length, 1); assert.match(bot.said[0].text, /success.*Did the thing/); }); it('honors an override success message', async () => { await runStep(bot, 'internal-desc', async () => 'ok', { successMessage: 'Nice.' }); assert.match(bot.said[0].text, /success.*Nice\./); }); it('swallows non-critical failures, returns undefined, and shows a failure blockquote', async () => { const result = await runStep(bot, 'That step', async () => { throw new Error('nope'); }); assert.equal(result, undefined); assert.equal(bot.said.length, 1); assert.match(bot.said[0].text, /failure.*Error: That step/); // Non-critical failures MUST NOT tag the message as aborting. assert.doesNotMatch(bot.said[0].text, /aborting/); }); it('re-throws on a critical failure and annotates the message', async () => { await assert.rejects( runStep( bot, 'Enabled location for Webex Calling', async () => { throw new Error('cascade'); }, { critical: true }, ), /cascade/, ); assert.equal(bot.said.length, 1); assert.match(bot.said[0].text, /aborting \(critical step\)/); }); it('works when bot is undefined (script/CLI usage)', async () => { const result = await runStep(undefined, 'headless', async () => 'ok'); assert.equal(result, 'ok'); }); });