import { describe, it } from 'node:test'; import assert from 'node:assert/strict'; import { translateAddNumberError } from '../src/webex/locations.js'; // The exact JSON Webex returns when a freshly-purchased number is // still being provisioned by the carrier. Kept verbatim from a real // error so this test breaks loudly if Webex ever changes the payload // shape (and we can update our detection to match). const PENDING_ORDERS_BODY = '[{"errors":[{"errorType":"VERIFICATION","errorCode":"ERR.V.TRM.TMN60027","errorMessage":"Number has pending orders.","errorTitle":"NUMBER_HAS_PENDING_ORDERS"}]}]'; function fakeHttpError(status, body) { const err = new Error(`HTTP ${status} for POST /whatever\n${body}`); err.status = status; err.body = body; return err; } describe('translateAddNumberError', () => { // Regression: without the translation, the raw Webex error was // propagated through runStep, cascaded into a Caller-ID failure // (LOCATION_NUMBER unavailable) and an auto-attendant failure // (number "used in another location"), and the actionable root // cause was buried under three stack traces. it('rewrites NUMBER_HAS_PENDING_ORDERS into an actionable operator message', () => { const raw = fakeHttpError(400, PENDING_ORDERS_BODY); const translated = translateAddNumberError(raw, '+14045551212'); assert.notEqual(translated, raw, 'should be a new Error instance'); assert.match(translated.message, /pending order/i); assert.match(translated.message, /re-run \/finalizeStore/); assert.match(translated.message, /\+14045551212/); assert.equal(translated.status, 400); assert.equal(translated.cause, raw, 'raw error should be preserved as .cause'); }); it('returns unrelated errors unchanged (same instance, no message rewrite)', () => { const raw = fakeHttpError(400, '{"message":"Nope","errorCode":9999}'); const result = translateAddNumberError(raw, '+14045551212'); assert.equal(result, raw, 'must be same instance so callers can rethrow'); assert.doesNotMatch(result.message, /pending order/i); }); it('tolerates errors with no body property (e.g. transport failures)', () => { const raw = new Error('ENOTFOUND webexapis.com'); const result = translateAddNumberError(raw, '+14045551212'); assert.equal(result, raw); }); it('does not misfire on other 400 payloads that happen to be arrays', () => { // Same array-of-errors shape but a different error code. const raw = fakeHttpError( 400, '[{"errors":[{"errorCode":"ERR.OTHER","errorMessage":"unrelated"}]}]', ); const result = translateAddNumberError(raw, '+14045551212'); assert.equal(result, raw); }); });