Skip to content

Commit eb52a19

Browse files
STRATCONN-6008 - [Twilio Messaging] - RCS (#3129)
* WIP adding RCS - do not deploy * saving progress * saving progress * Adding unit tests * Another test
1 parent 9403c71 commit eb52a19

File tree

4 files changed

+90
-7
lines changed

4 files changed

+90
-7
lines changed

packages/destination-actions/src/destinations/twilio-messaging/sendMessage/__tests__/index.test.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,27 @@ describe('TwilioMessaging.sendMessage', () => {
256256
})
257257
})
258258

259+
it('should send RCS with messaging service and scheduled send', async () => {
260+
nock('https://api.twilio.com').post(`/2010-04-01/Accounts/${defaultSettings.accountSID}/Messages.json`, "To=%2B1234567890&SendAt=2025-12-31T23%3A59%3A59Z&MessagingServiceSid=MG5555555555bbbbbb5555555555bbbbbb&Body=Scheduled+message+with+media&MediaUrl=https%3A%2F%2Fexample.com%2Fscheduled-image.png").reply(200, {
261+
sid: 'SM1234567890abcdef1234567890abcdef',
262+
status: 'scheduled'
263+
})
264+
265+
await testDestination.testAction('sendMessage', {
266+
settings: defaultSettings,
267+
mapping: {
268+
channel: CHANNELS.RCS,
269+
senderType: SENDER_TYPE.MESSAGING_SERVICE,
270+
toPhoneNumber: '+1234567890',
271+
messagingServiceSid: 'Scheduled Service [MG5555555555bbbbbb5555555555bbbbbb]',
272+
contentTemplateType: 'Inline',
273+
inlineBody: 'Scheduled message with media',
274+
inlineMediaUrls: ['https://example.com/scheduled-image.png'],
275+
sendAt: '2025-12-31T23:59:59Z'
276+
}
277+
})
278+
})
279+
259280
it('should throw error for invalid phone number format', async () => {
260281
await expect(
261282
testDestination.testAction('sendMessage', {
@@ -320,4 +341,52 @@ describe('TwilioMessaging.sendMessage', () => {
320341
})
321342
).rejects.toThrow(PayloadValidationError)
322343
})
344+
345+
it('should throw error if RCS send attempted with a phone number (i.e without a Messaging Service)', async () => {
346+
await expect(
347+
testDestination.testAction('sendMessage', {
348+
settings: defaultSettings,
349+
mapping: {
350+
channel: CHANNELS.RCS,
351+
senderType: SENDER_TYPE.PHONE_NUMBER,
352+
toPhoneNumber: '+1234567890',
353+
fromPhoneNumber: '+19876543210',
354+
contentTemplateType: 'Inline',
355+
inlineBody: 'Hello World!'
356+
}
357+
})
358+
).rejects.toThrow("The root value is missing the required field 'messagingServiceSid'. The root value must match \"then\" schema.")
359+
})
360+
361+
it('should send RCS messsage with tags', async () => {
362+
const body = "To=%2B1234567890&SendAt=2025-12-31T23%3A59%3A59Z&MessagingServiceSid=MG5555555555bbbbbb5555555555bbbbbb&Body=Scheduled+message+with+media&MediaUrl=https%3A%2F%2Fexample.com%2Fscheduled-image.png&Tags=%7B%22campaign_name%22%3A%22Spring+Sale+2022%22%2C%22message_type%22%3A%22cart_abandoned%22%2C%22number_tag%22%3A%2212345%22%2C%22boolean_tag%22%3A%22true%22%7D"
363+
nock('https://api.twilio.com')
364+
.post(`/2010-04-01/Accounts/${defaultSettings.accountSID}/Messages.json`, body)
365+
.reply(200, {
366+
sid: 'SM1234567890abcdef1234567890abcdef',
367+
status: 'sent'
368+
})
369+
370+
await testDestination.testAction('sendMessage', {
371+
settings: defaultSettings,
372+
mapping: {
373+
channel: CHANNELS.RCS,
374+
senderType: SENDER_TYPE.MESSAGING_SERVICE,
375+
toPhoneNumber: '+1234567890',
376+
messagingServiceSid: 'Scheduled Service [MG5555555555bbbbbb5555555555bbbbbb]',
377+
contentTemplateType: 'Inline',
378+
inlineBody: 'Scheduled message with media',
379+
inlineMediaUrls: ['https://example.com/scheduled-image.png'],
380+
sendAt: '2025-12-31T23:59:59Z',
381+
tags: {
382+
campaign_name: 'Spring Sale 2022',
383+
message_type: 'cart_abandoned',
384+
number_tag: 12345,
385+
boolean_tag: true,
386+
null_tag: null,
387+
empty_string_tag: ''
388+
}
389+
}
390+
})
391+
})
323392
})

packages/destination-actions/src/destinations/twilio-messaging/sendMessage/dynamic-fields.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ export async function dynamicSenderType(payload: Payload): Promise<DynamicFieldR
6666
return createErrorResponse("Select from 'Channel' field first.")
6767
}
6868

69+
if (channel === CHANNELS.RCS) {
70+
return {
71+
choices: [{ label: SENDER_TYPE.MESSAGING_SERVICE, value: SENDER_TYPE.MESSAGING_SERVICE }]
72+
}
73+
}
74+
6975
return {
7076
choices: [
7177
{ label: SENDER_TYPE.PHONE_NUMBER, value: SENDER_TYPE.PHONE_NUMBER },

packages/destination-actions/src/destinations/twilio-messaging/sendMessage/fields.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export const fields: Record<string, InputField> = {
1010
choices: [
1111
{ label: 'SMS', value: CHANNELS.SMS },
1212
{ label: 'MMS', value: CHANNELS.MMS },
13-
{ label: 'WhatsApp', value: CHANNELS.WHATSAPP }
14-
//{ label: 'RCS', value: CHANNELS.RCS } Will be hidden for private beta
13+
{ label: 'WhatsApp', value: CHANNELS.WHATSAPP },
14+
{ label: 'RCS', value: CHANNELS.RCS }
1515
]
1616
},
1717
senderType: {
@@ -106,7 +106,15 @@ export const fields: Record<string, InputField> = {
106106
description: 'The SID of the messaging service to use. If not in the dropdown, enter it directly.',
107107
type: 'string',
108108
dynamic: true,
109-
required: false,
109+
required: {
110+
conditions: [
111+
{
112+
fieldKey: 'channel',
113+
operator: 'is',
114+
value: CHANNELS.RCS
115+
}
116+
]
117+
},
110118
default: undefined,
111119
allowNull: false,
112120
disabledInputMethods: ['literal', 'variable', 'function', 'freeform', 'enrichment'],

packages/destination-actions/src/destinations/twilio-messaging/sendMessage/utils.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,9 @@ export async function send(request: RequestClient, payload: Payload, settings: S
3232

3333
const getTo = (): string => {
3434
switch (channel) {
35-
case 'SMS':
36-
case 'MMS':
37-
case 'RCS': {
35+
case CHANNELS.SMS:
36+
case CHANNELS.MMS:
37+
case CHANNELS.RCS: {
3838
toPhoneNumber = toPhoneNumber?.trim() ?? ''
3939
if (!(E164_REGEX.test(toPhoneNumber) || TWILIO_SHORT_CODE_REGEX.test(toPhoneNumber))) {
4040
throw new PayloadValidationError(
@@ -43,7 +43,7 @@ export async function send(request: RequestClient, payload: Payload, settings: S
4343
}
4444
return toPhoneNumber
4545
}
46-
case 'Whatsapp': {
46+
case CHANNELS.WHATSAPP: {
4747
toPhoneNumber = toPhoneNumber?.trim() ?? ''
4848
if (!E164_REGEX.test(toPhoneNumber)) {
4949
throw new PayloadValidationError("'To' field should be a valid phone number in E.164 format")

0 commit comments

Comments
 (0)