chatwoot/app/javascript/dashboard/services/TemplateNormalizer.spec.js
Muhsin Keloth 517b67dfd6
feat: Add rich template preview for WhatsApp & Twilio Templates (#13206)
This PR introduces a comprehensive, display-only template preview system
for both WhatsApp and Twilio templates rendering of all supported
template types.

This lays the foundation for rich template previews across:
- Template selection modals
- Campaign creation flows
- Message composer
- Message screen.

<img width="1818" height="2058" alt="template-preview"
src="https://github.com/user-attachments/assets/9833b28c-f824-4568-8f74-6da09ac61f62"
/>

---------

Co-authored-by: Sivin Varghese <[email protected]>
Co-authored-by: iamsivin <[email protected]>
Co-authored-by: Muhsin <[email protected]>
2026-04-30 18:54:34 +04:00

144 lines
3.8 KiB
JavaScript

// @vitest-environment node
import { describe, it, expect } from 'vitest';
import { TemplateNormalizer } from './TemplateNormalizer';
describe('TemplateNormalizer', () => {
it('normalizes Twilio call-to-action templates with hyphenated keys', () => {
const template = {
types: {
'twilio/call-to-action': {
body: 'CTA body for {{date}}',
actions: [
{
id: null,
title: 'Pay now',
type: 'URL',
url: 'https://payments.example.com/pay',
},
],
},
},
variables: {
date: '01-Jan-2026',
},
content_sid: 'HX123',
friendly_name: 'cta_example',
template_type: 'call-to-action',
};
const normalized = TemplateNormalizer.normalizeTwilio(template);
expect(normalized.type).toBe('twilio-call-to-action');
expect(normalized.body).toBe('CTA body for {{date}}');
expect(normalized.actions).toHaveLength(1);
expect(normalized.variables).toEqual({ date: '01-Jan-2026' });
});
it('normalizes Twilio quick replies', () => {
const template = {
template_type: 'quick_reply',
types: {
'twilio/quick-reply': {
body: 'Pick an option',
actions: [{ id: 'a', title: 'Option A' }],
},
},
variables: {},
};
const normalized = TemplateNormalizer.normalizeTwilio(template);
expect(normalized.type).toBe('twilio-quick-reply');
expect(normalized.body).toBe('Pick an option');
expect(normalized.actions).toEqual([{ id: 'a', title: 'Option A' }]);
});
it('normalizes Twilio media templates', () => {
const template = {
template_type: 'media',
body: 'Media body {{1}}',
types: {
'twilio/media': {
body: 'Media body {{1}}',
media: ['https://example.com/image.jpg'],
},
},
variables: { 1: 'value' },
};
const normalized = TemplateNormalizer.normalizeTwilio(template);
expect(normalized.type).toBe('twilio-media');
expect(normalized.media).toEqual(['https://example.com/image.jpg']);
expect(normalized.body).toBe('Media body {{1}}');
});
it('extracts WhatsApp named variables', () => {
const template = {
parameter_format: 'NAMED',
components: [
{
type: 'BODY',
text: 'Hi {{name}}',
example: {
body_text_named_params: [{ param_name: 'name', example: 'John' }],
},
},
],
};
const variables = TemplateNormalizer.extractWhatsAppVariables(template);
expect(variables).toMatchObject({
name: 'John',
});
});
it('extracts WhatsApp positional variables', () => {
const template = {
parameter_format: 'POSITIONAL',
components: [
{
type: 'BODY',
text: 'Hi {{1}}',
example: {
body_text: [['positional']],
},
},
],
};
const variables = TemplateNormalizer.extractWhatsAppVariables(template);
expect(variables).toMatchObject({
1: 'positional',
});
});
it('normalizes WhatsApp media image templates', () => {
const template = {
id: '1',
name: 'order_confirmation',
parameter_format: 'POSITIONAL',
components: [
{
type: 'HEADER',
format: 'IMAGE',
example: { header_handle: ['https://example.com/image.jpg'] },
},
{ type: 'BODY', text: 'Hi {{1}}', example: { body_text: [['John']] } },
],
language: 'en',
};
const normalized = TemplateNormalizer.normalizeWhatsApp(template);
expect(normalized.type).toBe('whatsapp-media-image');
expect(normalized.header.format).toBe('IMAGE');
expect(normalized.body.text).toBe('Hi {{1}}');
expect(normalized.variables).toMatchObject({ 1: 'John' });
});
});