From 79e72251b8016f48396eddaf205c1e2bcfed4b51 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Mon, 9 Jun 2025 12:48:23 -0600 Subject: [PATCH 1/2] feat: adds message class and unit tests --- src/__tests__/IterableEmbeddedMessage.test.ts | 163 ++++++++++++++++++ .../classes/IterableEmbeddedMessage.ts | 58 +++++++ 2 files changed, 221 insertions(+) create mode 100644 src/__tests__/IterableEmbeddedMessage.test.ts create mode 100644 src/embedded/classes/IterableEmbeddedMessage.ts diff --git a/src/__tests__/IterableEmbeddedMessage.test.ts b/src/__tests__/IterableEmbeddedMessage.test.ts new file mode 100644 index 000000000..64385e99f --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessage.test.ts @@ -0,0 +1,163 @@ +import { IterableEmbeddedMessage } from '../embedded/classes/IterableEmbeddedMessage'; +import { IterableEmbeddedMessageMetadata } from '../embedded/classes/IterableEmbeddedMessageMetadata'; +import { IterableEmbeddedMessageElements } from '../embedded/classes/IterableEmbeddedMessageElements'; +import { Iterable } from '../core/classes/Iterable'; + +describe('IterableEmbeddedMessage', () => { + it('should create an instance with all properties', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_all_properties'); + + const dict = { + metadata: { + messageId: 'msg-123', + placementId: 1, + campaignId: 456, + isProof: false, + }, + elements: { + title: 'Awesome Title', + body: 'Radical Body Text', + mediaUrl: 'https://example.com/image.jpg', + mediaUrlCaption: 'Check out this sick image!', + defaultAction: { + type: 'openUrl', + data: 'https://example.com', + }, + buttons: [ + { + id: 'button-1', + title: 'Click Me!', + action: { + type: 'openUrl', + data: 'https://example.com/button1', + }, + }, + ], + text: [ + { + id: 'text-1', + text: 'Some cool text', + type: 'body', + }, + ], + }, + payload: { + customKey: 'customValue', + anotherKey: 123, + }, + }; + + const message = IterableEmbeddedMessage.fromDict(dict); + + expect(message).toBeInstanceOf(IterableEmbeddedMessage); + + // Check metadata + expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.metadata.messageId).toBe('msg-123'); + expect(message.metadata.placementId).toBe(1); + expect(message.metadata.campaignId).toBe(456); + expect(message.metadata.isProof).toBe(false); + + // Check elements + expect(message.elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(message.elements?.title).toBe('Awesome Title'); + expect(message.elements?.body).toBe('Radical Body Text'); + expect(message.elements?.mediaUrl).toBe('https://example.com/image.jpg'); + expect(message.elements?.mediaUrlCaption).toBe( + 'Check out this sick image!' + ); + + // Check payload + expect(message.payload).toEqual({ + customKey: 'customValue', + anotherKey: 123, + }); + }); + + it('should create an instance with only required metadata', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_required_only'); + + const dict = { + metadata: { + messageId: 'msg-123', + placementId: 1, + isProof: false, + }, + }; + + const message = IterableEmbeddedMessage.fromDict(dict); + + expect(message).toBeInstanceOf(IterableEmbeddedMessage); + expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.metadata.messageId).toBe('msg-123'); + expect(message.metadata.placementId).toBe(1); + expect(message.metadata.campaignId).toBeUndefined(); + expect(message.metadata.isProof).toBe(false); + expect(message.elements).toBeUndefined(); + expect(message.payload).toBeUndefined(); + }); + + it('should throw an error if metadata is missing', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_missing_metadata'); + + const dict = { + elements: { + title: 'Some Title', + body: 'Some Body', + }, + }; + + expect(() => IterableEmbeddedMessage.fromDict(dict)).toThrow( + 'metadata is required' + ); + }); + + it('should create an instance with elements but no payload', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_elements_only'); + + const dict = { + metadata: { + messageId: 'msg-123', + placementId: 1, + isProof: false, + }, + elements: { + title: 'Elements Only', + body: 'No payload here', + }, + }; + + const message = IterableEmbeddedMessage.fromDict(dict); + + expect(message).toBeInstanceOf(IterableEmbeddedMessage); + expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.elements).toBeInstanceOf(IterableEmbeddedMessageElements); + expect(message.elements?.title).toBe('Elements Only'); + expect(message.elements?.body).toBe('No payload here'); + expect(message.payload).toBeUndefined(); + }); + + it('should create an instance with payload but no elements', () => { + Iterable.logger.log('iterableEmbeddedMessage_fromDict_payload_only'); + + const dict = { + metadata: { + messageId: 'msg-123', + placementId: 1, + isProof: false, + }, + payload: { + someData: 'someValue', + }, + }; + + const message = IterableEmbeddedMessage.fromDict(dict); + + expect(message).toBeInstanceOf(IterableEmbeddedMessage); + expect(message.metadata).toBeInstanceOf(IterableEmbeddedMessageMetadata); + expect(message.elements).toBeUndefined(); + expect(message.payload).toEqual({ + someData: 'someValue', + }); + }); +}); diff --git a/src/embedded/classes/IterableEmbeddedMessage.ts b/src/embedded/classes/IterableEmbeddedMessage.ts new file mode 100644 index 000000000..47adb916a --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMessage.ts @@ -0,0 +1,58 @@ +import { IterableEmbeddedMessageMetadata } from './IterableEmbeddedMessageMetadata'; +import { IterableEmbeddedMessageElements } from './IterableEmbeddedMessageElements'; + +/** + * IterableEmbeddedMessage represents an embedded message. + */ +export class IterableEmbeddedMessage { + /** The metadata of the embedded message */ + metadata: IterableEmbeddedMessageMetadata; + /** The elements of the embedded message */ + elements?: IterableEmbeddedMessageElements; + /** The custom payload of the embedded message */ + payload?: Record; + + /** + * Creates an instance of `IterableEmbeddedMessage`. + * + * @param metadata - The metadata of the embedded message. + * @param elements - The elements of the embedded message. + * @param payload - The custom payload of the embedded message. + */ + constructor( + metadata: IterableEmbeddedMessageMetadata, + elements?: IterableEmbeddedMessageElements, + payload?: Record + ) { + this.metadata = metadata; + this.elements = elements; + this.payload = payload; + } + + /** + * Creates an instance of `IterableEmbeddedMessage` from a dictionary object. + * + * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessage` instance. + * @returns A new instance of `IterableEmbeddedMessage` initialized with the provided dictionary properties. + */ + static fromDict(dict: Partial): IterableEmbeddedMessage { + if (!dict.metadata) { + throw new Error('metadata is required'); + } + const metadata = IterableEmbeddedMessageMetadata.fromDict(dict.metadata); + const elements = dict.elements + ? IterableEmbeddedMessageElements.fromDict(dict.elements) + : undefined; + const payload = dict.payload; + return new IterableEmbeddedMessage(metadata, elements, payload); + } +} + +/** + * An interface defining the dictionary object containing the properties for the embedded message. + */ +interface EmbeddedMessageDict { + metadata: IterableEmbeddedMessageMetadata; + elements: IterableEmbeddedMessageElements; + payload: Record; +} From 84e6a6883689666b2ab64babf9564c262467a17d Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Tue, 24 Jun 2025 18:17:53 -0600 Subject: [PATCH 2/2] chore: adds comments to props --- src/embedded/classes/IterableEmbeddedMessage.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/embedded/classes/IterableEmbeddedMessage.ts b/src/embedded/classes/IterableEmbeddedMessage.ts index 47adb916a..c264bf262 100644 --- a/src/embedded/classes/IterableEmbeddedMessage.ts +++ b/src/embedded/classes/IterableEmbeddedMessage.ts @@ -52,7 +52,10 @@ export class IterableEmbeddedMessage { * An interface defining the dictionary object containing the properties for the embedded message. */ interface EmbeddedMessageDict { + /** The metadata of the embedded message */ metadata: IterableEmbeddedMessageMetadata; + /** The elements of the embedded message */ elements: IterableEmbeddedMessageElements; + /** The custom payload of the embedded message */ payload: Record; }