From 87abffc211f8522f109acf9f642d0423061cb208 Mon Sep 17 00:00:00 2001 From: Stephen Hand Date: Fri, 27 Sep 2024 11:51:31 +0100 Subject: [PATCH 1/5] Guess what? Logging --- ...ErrorMessageForUnsupportedMedia.private.ts | 11 +++++++--- .../serviceConversationListener.protected.ts | 22 +++++++++++-------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/functions/helpers/sendErrorMessageForUnsupportedMedia.private.ts b/functions/helpers/sendErrorMessageForUnsupportedMedia.private.ts index 5b33479d..5d486587 100644 --- a/functions/helpers/sendErrorMessageForUnsupportedMedia.private.ts +++ b/functions/helpers/sendErrorMessageForUnsupportedMedia.private.ts @@ -21,7 +21,6 @@ export type ConversationSid = `CH${string}`; type SendErrorMessageForUnsupportedMediaEvent = { Body?: string; ConversationSid: ConversationSid; - EventType?: string; Media?: Record; DateCreated: Date; }; @@ -56,17 +55,19 @@ export const sendConversationMessage = async ( }); export const sendErrorMessageForUnsupportedMedia = async (context: Context, event: Event) => { - const { EventType, Body, Media, ConversationSid } = event; + const { Body, Media, ConversationSid } = event; /* Valid message will have either a body/media. A message with no body or media implies that there was an error sending such message */ - if (EventType === 'onMessageAdded' && !Body && !Media) { + if (!Body && !Media) { + console.debug('Message has no text body or media, sending error.', ConversationSid); let messageText = FALLBACK_ERROR_MESSAGE; const serviceConfig = await context.getTwilioClient().flexApi.configuration.get().fetch(); const helplineLanguage = serviceConfig.attributes.helplineLanguage ?? 'en-US'; + console.debug('Helpline language to send error message: ', helplineLanguage, ConversationSid); if (helplineLanguage) { try { const response = await fetch( @@ -74,10 +75,13 @@ export const sendErrorMessageForUnsupportedMedia = async (context: Context, even ); const translation = await response.json(); const { [ERROR_MESSAGE_TRANSLATION_KEY]: translatedMessage } = translation; + + console.debug('Translated error message: ', translatedMessage, ConversationSid); messageText = translatedMessage || messageText; } catch { console.warn( `Couldn't retrieve ${ERROR_MESSAGE_TRANSLATION_KEY} message translation for ${helplineLanguage}`, + ConversationSid, ); } } @@ -87,6 +91,7 @@ export const sendErrorMessageForUnsupportedMedia = async (context: Context, even author: 'Bot', messageText, }); + console.info('Sent error message: ', messageText, ConversationSid); } }; diff --git a/functions/webhooks/serviceConversationListener.protected.ts b/functions/webhooks/serviceConversationListener.protected.ts index 5d37b44e..c367049a 100644 --- a/functions/webhooks/serviceConversationListener.protected.ts +++ b/functions/webhooks/serviceConversationListener.protected.ts @@ -22,17 +22,21 @@ import { } from '../helpers/sendErrorMessageForUnsupportedMedia.private'; export const handler = async (context: Context, event: Event, callback: ServerlessCallback) => { + console.info(`===== Service Conversation Listener (event: ${event.EventType})=====`); const response = responseWithCors(); const resolve = bindResolve(callback)(response); - // eslint-disable-next-line global-require,import/no-dynamic-require - const sendErrorMessageForUnsupportedMedia = require(Runtime.getFunctions()[ - 'helpers/sendErrorMessageForUnsupportedMedia' - ].path).sendErrorMessageForUnsupportedMedia as SendErrorMessageForUnsupportedMedia; + if (event.EventType === 'onMessageAdded') { + // eslint-disable-next-line global-require,import/no-dynamic-require + const sendErrorMessageForUnsupportedMedia = require(Runtime.getFunctions()[ + 'helpers/sendErrorMessageForUnsupportedMedia' + ].path).sendErrorMessageForUnsupportedMedia as SendErrorMessageForUnsupportedMedia; - try { - await sendErrorMessageForUnsupportedMedia(context, event); - } catch (err) { - if (err instanceof Error) resolve(error500(err)); - else resolve(error500(new Error(String(err)))); + try { + console.debug('New message, checking if we need to send error.'); + await sendErrorMessageForUnsupportedMedia(context, event); + } catch (err) { + if (err instanceof Error) resolve(error500(err)); + else resolve(error500(new Error(String(err)))); + } } }; From 10db4631180c23930e32ab72760fbb6a7d0e8a35 Mon Sep 17 00:00:00 2001 From: Stephen Hand Date: Fri, 27 Sep 2024 12:29:41 +0100 Subject: [PATCH 2/5] Fix unit test --- .../helpers/sendErrorMessageForUnsupportedMedia.private.ts | 5 +++-- tests/webhooks/serviceConversationListener.test.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/functions/helpers/sendErrorMessageForUnsupportedMedia.private.ts b/functions/helpers/sendErrorMessageForUnsupportedMedia.private.ts index 5d486587..1f3033a7 100644 --- a/functions/helpers/sendErrorMessageForUnsupportedMedia.private.ts +++ b/functions/helpers/sendErrorMessageForUnsupportedMedia.private.ts @@ -18,14 +18,15 @@ import { Context } from '@twilio-labs/serverless-runtime-types/types'; export type ConversationSid = `CH${string}`; -type SendErrorMessageForUnsupportedMediaEvent = { +type OnMessageAddedEvent = { + EventType: 'onMessageAdded'; Body?: string; ConversationSid: ConversationSid; Media?: Record; DateCreated: Date; }; -export type Event = SendErrorMessageForUnsupportedMediaEvent; +export type Event = OnMessageAddedEvent; const FALLBACK_ERROR_MESSAGE = 'Unsupported message type.'; const ERROR_MESSAGE_TRANSLATION_KEY = 'UnsupportedMediaErrorMsg'; diff --git a/tests/webhooks/serviceConversationListener.test.ts b/tests/webhooks/serviceConversationListener.test.ts index b7ee0c4f..56ab2567 100644 --- a/tests/webhooks/serviceConversationListener.test.ts +++ b/tests/webhooks/serviceConversationListener.test.ts @@ -72,7 +72,7 @@ describe('serviceConversationListener', () => { EventType: undefined, Media: {}, DateCreated: new Date(), - }; + } as any; const callback: ServerlessCallback = (err, result) => { expect(result).toBeDefined(); From f58ba51730281fd26b6f4dfccc55e409a7d9b2f9 Mon Sep 17 00:00:00 2001 From: Stephen Hand Date: Fri, 27 Sep 2024 12:53:08 +0100 Subject: [PATCH 3/5] Resolve service conversation listener on success --- functions/webhooks/serviceConversationListener.protected.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/functions/webhooks/serviceConversationListener.protected.ts b/functions/webhooks/serviceConversationListener.protected.ts index c367049a..27c3206a 100644 --- a/functions/webhooks/serviceConversationListener.protected.ts +++ b/functions/webhooks/serviceConversationListener.protected.ts @@ -15,7 +15,7 @@ */ import { Context, ServerlessCallback } from '@twilio-labs/serverless-runtime-types/types'; -import { responseWithCors, bindResolve, error500 } from '@tech-matters/serverless-helpers'; +import { responseWithCors, bindResolve, error500, success } from '@tech-matters/serverless-helpers'; import { Event, SendErrorMessageForUnsupportedMedia, @@ -38,5 +38,6 @@ export const handler = async (context: Context, event: Event, callback: Serverle if (err instanceof Error) resolve(error500(err)); else resolve(error500(new Error(String(err)))); } + resolve(success(event)); } }; From c16e9e9912d7341cff86bdee632f1728f665b79f Mon Sep 17 00:00:00 2001 From: Stephen Hand Date: Fri, 27 Sep 2024 13:06:19 +0100 Subject: [PATCH 4/5] Resolve service conversation listener on success --- functions/webhooks/serviceConversationListener.protected.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/functions/webhooks/serviceConversationListener.protected.ts b/functions/webhooks/serviceConversationListener.protected.ts index 27c3206a..f9840b8e 100644 --- a/functions/webhooks/serviceConversationListener.protected.ts +++ b/functions/webhooks/serviceConversationListener.protected.ts @@ -35,9 +35,9 @@ export const handler = async (context: Context, event: Event, callback: Serverle console.debug('New message, checking if we need to send error.'); await sendErrorMessageForUnsupportedMedia(context, event); } catch (err) { - if (err instanceof Error) resolve(error500(err)); - else resolve(error500(new Error(String(err)))); + if (err instanceof Error) return resolve(error500(err)); + return resolve(error500(new Error(String(err)))); } - resolve(success(event)); } + return resolve(success(event)); }; From cb3e1b71e1062c82b1a0f10264b3a31727e24b57 Mon Sep 17 00:00:00 2001 From: Stephen Hand Date: Fri, 27 Sep 2024 13:57:08 +0100 Subject: [PATCH 5/5] Remove useless tests --- .../serviceConversationListener.test.ts | 72 +------------------ 1 file changed, 2 insertions(+), 70 deletions(-) diff --git a/tests/webhooks/serviceConversationListener.test.ts b/tests/webhooks/serviceConversationListener.test.ts index 56ab2567..9e01bd0f 100644 --- a/tests/webhooks/serviceConversationListener.test.ts +++ b/tests/webhooks/serviceConversationListener.test.ts @@ -49,77 +49,9 @@ describe('serviceConversationListener', () => { helpers.teardown(); }); - test('Should return status 400 if Body, Media or EventType are undefined', async () => { - const event1: Body = { - Body: undefined, - ConversationSid: 'CHxxxxxxx34EWS', - EventType: 'onMessageAdded', - Media: {}, - DateCreated: new Date(), - }; - - const event2: Body = { - Body: 'Test word', - ConversationSid: 'CHxxxxxxx34EWS', - EventType: 'onMessageAdded', - Media: undefined, - DateCreated: new Date(), - }; - - const event3: Body = { - Body: 'Test word', - ConversationSid: 'CHxxxxxxx34EWS', - EventType: undefined, - Media: {}, - DateCreated: new Date(), - } as any; - - const callback: ServerlessCallback = (err, result) => { - expect(result).toBeDefined(); - const response = result as MockedResponse; - expect(response.getStatus()).toBe(400); - }; - - await serviceConversationListener(baseContext, event1, callback); - await serviceConversationListener(baseContext, event2, callback); - await serviceConversationListener(baseContext, event3, callback); - }); - - test('Should return status 500 if object response is undefined', async () => { - const event1: Body = { - Body: 'Test word', - ConversationSid: 'CHxxxxxxx34EWS', - EventType: 'onMessageAdded', - Media: {}, - DateCreated: new Date(), - }; - - const callback1: ServerlessCallback = (err, result) => { - expect(result).toBeDefined(); - const response = result as MockedResponse; - expect(response.getStatus()).toBe(500); - }; - - await serviceConversationListener({ ...baseContext }, event1, callback1); - - const event2: Body = { - Body: 'Test word', - ConversationSid: 'CHxxxxxxx34EWS', - EventType: 'onMessageAdded', - Media: {}, - DateCreated: new Date(), - }; - - const callback2: ServerlessCallback = (err, result) => { - expect(result).toBeDefined(); - const response = result as MockedResponse; - expect(response.getStatus()).toBe(500); - }; - - await serviceConversationListener(baseContext, event2, callback2); - }); + // TODO: Test coverage for sending error message - test('Should return status 200', async () => { + test('Should return status 200 for valid message', async () => { const event1: Body = { Body: 'Test word', ConversationSid: 'CHxxxxxxx34EWS',