From 4ab37b04633b38e63da72c9100ee5309173c9f32 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Tue, 3 Jun 2025 16:48:03 -0600 Subject: [PATCH 1/3] feat: creates IterableEmbeddedMessageElementsButton and associated classes --- .../IterableEmbeddedMessageElementsButton.ts | 35 +++++++++++++++++++ ...ableEmbeddedMessageElementsButtonAction.ts | 26 ++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 src/embedded/classes/IterableEmbeddedMessageElementsButton.ts create mode 100644 src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts new file mode 100644 index 000000000..b4efff426 --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts @@ -0,0 +1,35 @@ +import { IterableEmbeddedMessageElementsButtonAction } from './IterableEmbeddedMessageElementsButtonAction'; + +export class IterableEmbeddedMessageButton { + readonly id: string; + readonly title?: string; + readonly action?: IterableEmbeddedMessageElementsButtonAction; + + constructor( + id: string, + title?: string, + action?: IterableEmbeddedMessageElementsButtonAction + ) { + this.id = id; + this.title = title; + this.action = action; + } + + static fromDict( + dict: Partial + ): IterableEmbeddedMessageButton { + if (!dict.id) { + throw new Error('id is required'); + } + const action = dict.action + ? IterableEmbeddedMessageElementsButtonAction.fromDict(dict.action) + : undefined; + return new IterableEmbeddedMessageButton(dict.id, dict.title, action); + } +} + +export interface EmbeddedMessageButtonDict { + id: string; + title?: string; + action?: IterableEmbeddedMessageElementsButtonAction; +} diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts new file mode 100644 index 000000000..6c997bdfc --- /dev/null +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts @@ -0,0 +1,26 @@ +export class IterableEmbeddedMessageElementsButtonAction { + readonly type: string; + readonly data?: string; + + constructor(type: string, data?: string) { + this.type = type; + this.data = data; + } + + static fromDict( + dict: Partial + ): IterableEmbeddedMessageElementsButtonAction { + if (!dict.type) { + throw new Error('type is required'); + } + return new IterableEmbeddedMessageElementsButtonAction( + dict.type, + dict.data + ); + } +} + +export interface EmbeddedMessageButtonActionDict { + type: string; + data?: string; +} From fba2cbdeb1a4ebccba7a52d143ad8b9bdfd83d20 Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Tue, 3 Jun 2025 19:39:07 -0600 Subject: [PATCH 2/3] feat: adds unit tests --- ...rableEmbeddedMessageElementsButton.test.ts | 91 +++++++++++++++++++ ...mbeddedMessageElementsButtonAction.test.ts | 40 ++++++++ 2 files changed, 131 insertions(+) create mode 100644 src/__tests__/IterableEmbeddedMessageElementsButton.test.ts create mode 100644 src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts diff --git a/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts b/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts new file mode 100644 index 000000000..365bf96ab --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts @@ -0,0 +1,91 @@ +import { IterableEmbeddedMessageButton } from '../embedded/classes/IterableEmbeddedMessageElementsButton'; +import { IterableEmbeddedMessageElementsButtonAction } from '../embedded/classes/IterableEmbeddedMessageElementsButtonAction'; +import { Iterable } from '../core/classes/Iterable'; + +describe('IterableEmbeddedMessageButton', () => { + it('should create an instance with all properties including button action', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageButton_fromDict_all_properties' + ); + + const dict = { + id: 'button-123', + title: 'Click Me!', + action: { type: 'openUrl', data: 'https://example.com' }, + }; + + const button = IterableEmbeddedMessageButton.fromDict(dict); + + expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); + expect(button.id).toBe('button-123'); + expect(button.title).toBe('Click Me!'); + expect(button.action).toBeInstanceOf( + IterableEmbeddedMessageElementsButtonAction + ); + expect(button.action?.type).toBe('openUrl'); + expect(button.action?.data).toBe('https://example.com'); + }); + + it('should create an instance with only required properties', () => { + Iterable.logger.log('iterableEmbeddedMessageButton_fromDict_required_only'); + + const dict = { id: 'button-123' }; + + const button = IterableEmbeddedMessageButton.fromDict(dict); + + expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); + expect(button.id).toBe('button-123'); + expect(button.title).toBeUndefined(); + expect(button.action).toBeUndefined(); + }); + + it('should create an instance with title but no action', () => { + Iterable.logger.log('iterableEmbeddedMessageButton_fromDict_title_only'); + + const dict = { + id: 'button-123', + title: 'Click Me!', + }; + + const button = IterableEmbeddedMessageButton.fromDict(dict); + + expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); + expect(button.id).toBe('button-123'); + expect(button.title).toBe('Click Me!'); + expect(button.action).toBeUndefined(); + }); + + it('should throw an error if id is missing in fromDict', () => { + Iterable.logger.log('iterableEmbeddedMessageButton_fromDict_missing_id'); + + const dict = { + title: 'Click Me!', + action: { type: 'openUrl', data: 'https://example.com' }, + }; + + expect(() => IterableEmbeddedMessageButton.fromDict(dict)).toThrow( + 'id is required' + ); + }); + + it('should handle button action with only type', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageButton_fromDict_action_type_only' + ); + + const dict = { + id: 'button-123', + action: { type: 'close' }, + }; + + const button = IterableEmbeddedMessageButton.fromDict(dict); + + expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); + expect(button.id).toBe('button-123'); + expect(button.action).toBeInstanceOf( + IterableEmbeddedMessageElementsButtonAction + ); + expect(button.action?.type).toBe('close'); + expect(button.action?.data).toBeUndefined(); + }); +}); diff --git a/src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts b/src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts new file mode 100644 index 000000000..fa172cb7c --- /dev/null +++ b/src/__tests__/IterableEmbeddedMessageElementsButtonAction.test.ts @@ -0,0 +1,40 @@ +import { IterableEmbeddedMessageElementsButtonAction } from '../embedded/classes/IterableEmbeddedMessageElementsButtonAction'; +import { Iterable } from '../core/classes/Iterable'; + +describe('IterableEmbeddedMessageDefaultAction', () => { + it('should create an instance with the correct properties', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElementsButtonAction_fromDict_valid_dictionary' + ); + + const dict = { type: 'openUrl', data: 'https://example.com' }; + const action = IterableEmbeddedMessageElementsButtonAction.fromDict(dict); + expect(action).toBeInstanceOf(IterableEmbeddedMessageElementsButtonAction); + expect(action.type).toBe('openUrl'); + expect(action.data).toBe('https://example.com'); + }); + + it('should create an instance from a dictionary with data omitted', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElementsButtonAction_fromDict_valid_dictionary_with_data_omitted' + ); + + const dict = { type: 'action://join', data: '' }; + const action = IterableEmbeddedMessageElementsButtonAction.fromDict(dict); + expect(action).toBeInstanceOf(IterableEmbeddedMessageElementsButtonAction); + expect(action.type).toBe('action://join'); + expect(action.data).toBe(''); + }); + + it('should throw an error if type is missing in fromDict', () => { + Iterable.logger.log( + 'iterableEmbeddedMessageElementsButtonAction_fromDict_invalid_dictionary_missing_type' + ); + + const dict = { data: 'foo' }; + + expect(() => + IterableEmbeddedMessageElementsButtonAction.fromDict(dict) + ).toThrow('type is required'); + }); +}); From c350008f3373de20f14191c61fe9a440c93d54da Mon Sep 17 00:00:00 2001 From: Evan Greer Date: Tue, 3 Jun 2025 20:26:19 -0600 Subject: [PATCH 3/3] feat: adds documentation --- ...rableEmbeddedMessageElementsButton.test.ts | 20 +++++------ .../IterableEmbeddedMessageElementsButton.ts | 36 ++++++++++++++++--- ...ableEmbeddedMessageElementsButtonAction.ts | 28 +++++++++++++++ 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts b/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts index 365bf96ab..1524d1c5b 100644 --- a/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts +++ b/src/__tests__/IterableEmbeddedMessageElementsButton.test.ts @@ -1,4 +1,4 @@ -import { IterableEmbeddedMessageButton } from '../embedded/classes/IterableEmbeddedMessageElementsButton'; +import { IterableEmbeddedMessageElementsButton } from '../embedded/classes/IterableEmbeddedMessageElementsButton'; import { IterableEmbeddedMessageElementsButtonAction } from '../embedded/classes/IterableEmbeddedMessageElementsButtonAction'; import { Iterable } from '../core/classes/Iterable'; @@ -14,9 +14,9 @@ describe('IterableEmbeddedMessageButton', () => { action: { type: 'openUrl', data: 'https://example.com' }, }; - const button = IterableEmbeddedMessageButton.fromDict(dict); + const button = IterableEmbeddedMessageElementsButton.fromDict(dict); - expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); + expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); expect(button.id).toBe('button-123'); expect(button.title).toBe('Click Me!'); expect(button.action).toBeInstanceOf( @@ -31,9 +31,9 @@ describe('IterableEmbeddedMessageButton', () => { const dict = { id: 'button-123' }; - const button = IterableEmbeddedMessageButton.fromDict(dict); + const button = IterableEmbeddedMessageElementsButton.fromDict(dict); - expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); + expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); expect(button.id).toBe('button-123'); expect(button.title).toBeUndefined(); expect(button.action).toBeUndefined(); @@ -47,9 +47,9 @@ describe('IterableEmbeddedMessageButton', () => { title: 'Click Me!', }; - const button = IterableEmbeddedMessageButton.fromDict(dict); + const button = IterableEmbeddedMessageElementsButton.fromDict(dict); - expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); + expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); expect(button.id).toBe('button-123'); expect(button.title).toBe('Click Me!'); expect(button.action).toBeUndefined(); @@ -63,7 +63,7 @@ describe('IterableEmbeddedMessageButton', () => { action: { type: 'openUrl', data: 'https://example.com' }, }; - expect(() => IterableEmbeddedMessageButton.fromDict(dict)).toThrow( + expect(() => IterableEmbeddedMessageElementsButton.fromDict(dict)).toThrow( 'id is required' ); }); @@ -78,9 +78,9 @@ describe('IterableEmbeddedMessageButton', () => { action: { type: 'close' }, }; - const button = IterableEmbeddedMessageButton.fromDict(dict); + const button = IterableEmbeddedMessageElementsButton.fromDict(dict); - expect(button).toBeInstanceOf(IterableEmbeddedMessageButton); + expect(button).toBeInstanceOf(IterableEmbeddedMessageElementsButton); expect(button.id).toBe('button-123'); expect(button.action).toBeInstanceOf( IterableEmbeddedMessageElementsButtonAction diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts index b4efff426..b1481c9e6 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButton.ts @@ -1,10 +1,23 @@ import { IterableEmbeddedMessageElementsButtonAction } from './IterableEmbeddedMessageElementsButtonAction'; -export class IterableEmbeddedMessageButton { +/** + * IterableEmbeddedMessageElementsButton represents a button in an embedded message. + */ +export class IterableEmbeddedMessageElementsButton { + /** The ID for the embedded message button */ readonly id: string; + /** The title for the embedded message button */ readonly title?: string; + /** The action for the embedded message button */ readonly action?: IterableEmbeddedMessageElementsButtonAction; + /** + * Creates an instance of IterableEmbeddedMessageButton. + * + * @param id - The ID for the embedded message button. + * @param title - The title for the embedded message button. + * @param action - The action for the embedded message button. + */ constructor( id: string, title?: string, @@ -15,20 +28,33 @@ export class IterableEmbeddedMessageButton { this.action = action; } + /** + * Creates an instance of `IterableEmbeddedMessageButton` from a dictionary object. + * + * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageButton` instance. + * @returns A new instance of `IterableEmbeddedMessageButton` initialized with the provided dictionary properties. + */ static fromDict( - dict: Partial - ): IterableEmbeddedMessageButton { + dict: Partial + ): IterableEmbeddedMessageElementsButton { if (!dict.id) { throw new Error('id is required'); } const action = dict.action ? IterableEmbeddedMessageElementsButtonAction.fromDict(dict.action) : undefined; - return new IterableEmbeddedMessageButton(dict.id, dict.title, action); + return new IterableEmbeddedMessageElementsButton( + dict.id, + dict.title, + action + ); } } -export interface EmbeddedMessageButtonDict { +/** + * An interface defining the dictionary object containing the properties for the embedded message button. + */ +export interface EmbeddedMessageElementsButtonDict { id: string; title?: string; action?: IterableEmbeddedMessageElementsButtonAction; diff --git a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts index 6c997bdfc..c8dd24708 100644 --- a/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts +++ b/src/embedded/classes/IterableEmbeddedMessageElementsButtonAction.ts @@ -1,12 +1,37 @@ +/** + * IterableEmbeddedMessageElementsButtonAction represents an action defined as a response to user events + * for an embedded message button. + */ export class IterableEmbeddedMessageElementsButtonAction { + /** + * The type of iterable action + * For custom actions, the type is `action://` prefix followed by a custom action name + */ readonly type: string; + + /** + * The url for the action when the type is `openUrl` + * For custom actions, data is empty + */ readonly data?: string; + /** + * Creates an instance of IterableEmbeddedMessageElementsButtonAction. + * + * @param type - The type of the action. + * @param data - Optional data associated with the action. + */ constructor(type: string, data?: string) { this.type = type; this.data = data; } + /** + * Creates an instance of `IterableEmbeddedMessageElementsButtonAction` from a dictionary object. + * + * @param dict - The dictionary object containing the properties to initialize the `IterableEmbeddedMessageElementsButtonAction` instance. + * @returns A new instance of `IterableEmbeddedMessageElementsButtonAction` initialized with the provided dictionary properties. + */ static fromDict( dict: Partial ): IterableEmbeddedMessageElementsButtonAction { @@ -20,6 +45,9 @@ export class IterableEmbeddedMessageElementsButtonAction { } } +/** + * An interface defining the dictionary object containing the properties for the embedded message button action. + */ export interface EmbeddedMessageButtonActionDict { type: string; data?: string;