inbound-processor-outer-catch.test.js
1 /** 2 * Tests for Inbound Processor - outer catch blocks 3 * Lines 69-71 (pollAllChannels) and 113-115 (processAllReplies) 4 * 5 * These outer catch blocks fire when a successful handler return value 6 * causes the post-processing code (e.g. results.sms.stored) to throw. 7 * We achieve this by mocking handlers to return null so that accessing 8 * .stored / .sent on null throws a TypeError in the outer try block. 9 */ 10 11 import { test, mock } from 'node:test'; 12 import assert from 'node:assert/strict'; 13 14 // Mock SMS to return null (not throw) so results.sms = null 15 // Then results.sms.stored at line 62 throws TypeError (outer catch, lines 69-71) 16 mock.module('../../src/inbound/sms.js', { 17 namedExports: { 18 pollInboundSMS: async () => null, 19 processPendingReplies: async () => null, 20 }, 21 }); 22 23 // Mock email to return null similarly 24 mock.module('../../src/inbound/email.js', { 25 namedExports: { 26 pollInboundEmails: async () => null, 27 processPendingReplies: async () => null, 28 }, 29 }); 30 31 const { pollAllChannels, processAllReplies } = await import('../../src/inbound/processor.js'); 32 33 test('pollAllChannels outer catch: throws when handler returns null (results.sms.stored fails)', async () => { 34 // When pollInboundSMS returns null, results.sms = null 35 // Then results.sms.stored at line 62 throws TypeError 36 // This triggers the outer catch at lines 69-71 which re-throws 37 await assert.rejects( 38 () => pollAllChannels(), 39 err => { 40 // Should be a TypeError from null.stored 41 assert.ok(err instanceof TypeError, `Expected TypeError, got: ${err.constructor.name}`); 42 return true; 43 } 44 ); 45 }); 46 47 test('processAllReplies outer catch: throws when handler returns null (results.sms.sent fails)', async () => { 48 // When processPendingReplies returns null, results.sms = null 49 // Then results.sms.sent at line 106 throws TypeError 50 // This triggers the outer catch at lines 113-115 which re-throws 51 await assert.rejects( 52 () => processAllReplies(), 53 err => { 54 assert.ok(err instanceof TypeError, `Expected TypeError, got: ${err.constructor.name}`); 55 return true; 56 } 57 ); 58 }); 59 60 test('pollAllChannels outer catch: error is a TypeError about null property access', async () => { 61 try { 62 await pollAllChannels(); 63 assert.fail('Should have thrown'); 64 } catch (err) { 65 assert.ok(err instanceof TypeError); 66 // Error message should mention null/undefined property access 67 assert.ok( 68 err.message.includes('null') || 69 err.message.includes('undefined') || 70 err.message.includes('Cannot'), 71 `Unexpected error message: ${err.message}` 72 ); 73 } 74 }); 75 76 test('processAllReplies outer catch: error is a TypeError about null property access', async () => { 77 try { 78 await processAllReplies(); 79 assert.fail('Should have thrown'); 80 } catch (err) { 81 assert.ok(err instanceof TypeError); 82 assert.ok( 83 err.message.includes('null') || 84 err.message.includes('undefined') || 85 err.message.includes('Cannot'), 86 `Unexpected error message: ${err.message}` 87 ); 88 } 89 });