From 156d995cd62c7bf68f02cd58e40dd992bb37568a Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Wed, 28 Aug 2024 14:51:25 -0700 Subject: [PATCH 01/10] Modified `getMeetingDetailsVerbose` API return interface --- .../teams-test-app/e2e-test-data/meeting.json | 4 ++-- packages/teams-js/src/public/meeting.ts | 19 ++++++++++++++++++- packages/teams-js/test/public/meeting.spec.ts | 10 ++++++++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/apps/teams-test-app/e2e-test-data/meeting.json b/apps/teams-test-app/e2e-test-data/meeting.json index 2742b772dc..4325b8de16 100644 --- a/apps/teams-test-app/e2e-test-data/meeting.json +++ b/apps/teams-test-app/e2e-test-data/meeting.json @@ -35,11 +35,11 @@ }, { "title": "getMeetingDetailsVerbose API Call - Success", - "version": ">2.22.0", + "version": ">2.26.0", "type": "callResponse", "boxSelector": "#box_getMeetingDetailsVerbose", "expectedAlertValue": "getMeetingDetails called with shouldGetVerboseDetails: true", - "expectedTestAppValue": "{\"details\":{\"scheduledStartTime\":\"testStartTime\",\"joinUrl\":\"testJoinUrl\",\"type\":\"oneOnOneCall\",\"originalCaller\":\"testCallerId\",\"dialedEntity\":\"testDnis\",\"trackingId\":\"testTrackingId\"},\"conversation\":{\"id\":\"testConversationId\"},\"organizer\":{\"id\":\"testOrganizerId\",\"tenantId\":\"testTenantId\"}}" + "expectedTestAppValue": "{\"details\":{\"scheduledStartTime\":\"testStartTime\",\"joinUrl\":\"testJoinUrl\",\"type\":\"oneOnOneCall\",\"originalCaller\":{\"phoneNumber\":\"testCallerPhoneNumber\",\"email\":\"testCallerEmail\"},\"dialedEntity\":{\"phoneNumber\":\"testCalleePhoneNumber\",\"email\":\"testCalleeEmail\"},\"trackingId\":\"testTrackingId\"},\"conversation\":{\"id\":\"testConversationId\"},\"organizer\":{\"id\":\"testOrganizerId\",\"tenantId\":\"testTenantId\"}}" }, { "title": "getAuthenticationTokenForAnonymousUser API Call - Success", diff --git a/packages/teams-js/src/public/meeting.ts b/packages/teams-js/src/public/meeting.ts index e44aea1dba..bf5f1fe3ac 100644 --- a/packages/teams-js/src/public/meeting.ts +++ b/packages/teams-js/src/public/meeting.ts @@ -94,6 +94,23 @@ export namespace meeting { type?: T; } + /** + * @hidden + * Hide from docs + * Data structure to represent call participant identifiers + */ + interface ICallParticipantIdentifiers { + /** + * Phone number of a PSTN caller + */ + phoneNumber?: string; + + /** + * Email of a VoIP caller + */ + email?: string; + } + /** * @hidden * Hide from docs @@ -104,7 +121,7 @@ export namespace meeting { * @hidden * Phone number of a PSTN caller or email of a VoIP caller */ - originalCaller?: string; + originalCaller?: ICallParticipantIdentifiers; /** * @hidden diff --git a/packages/teams-js/test/public/meeting.spec.ts b/packages/teams-js/test/public/meeting.spec.ts index c0b615fb40..436388ea7a 100644 --- a/packages/teams-js/test/public/meeting.spec.ts +++ b/packages/teams-js/test/public/meeting.spec.ts @@ -277,7 +277,10 @@ describe('meeting', () => { 'https://teams.microsoft.com/l/meetup-join/19%3ameeting_qwertyuiop[phgfdsasdfghjkjbvcxcvbnmyt1234567890!@#$%^&*(%40thread.v2/0?context=%7b%22Tid%22%3a%2272f988bf-86f1-41af-91ab-2d7cd011db47%22%2c%22Oid%22%3a%226b33ac33-85ae-4995-be29-1d38a77aa8e3%22%7d', type: meeting.CallType.OneOnOneCall, // Verbose details - originalCaller: 'testCallerId', + originalCaller: { + phoneNumber: 'testCallerPhoneNumber', + email: 'testCallerEmail', + }, }; const organizer: meeting.IOrganizer = { id: '8:orgid:6b33ac33-85ae-4995-be29-1d38a77aa8e3', @@ -627,7 +630,10 @@ describe('meeting', () => { 'https://teams.microsoft.com/l/meetup-join/19%3ameeting_qwertyuiop[phgfdsasdfghjkjbvcxcvbnmyt1234567890!@#$%^&*(%40thread.v2/0?context=%7b%22Tid%22%3a%2272f988bf-86f1-41af-91ab-2d7cd011db47%22%2c%22Oid%22%3a%226b33ac33-85ae-4995-be29-1d38a77aa8e3%22%7d', type: meeting.CallType.OneOnOneCall, // Verbose details - originalCaller: 'testCallerId', + originalCaller: { + phoneNumber: 'testCallerPhoneNumber', + email: 'testCallerEmail', + }, }; const organizer: meeting.IOrganizer = { id: '8:orgid:6b33ac33-85ae-4995-be29-1d38a77aa8e3', From f0f43d76539c4bfb1a5f37b457ebb553de63ce26 Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Fri, 30 Aug 2024 10:59:38 -0700 Subject: [PATCH 02/10] Add changefile --- ...soft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@microsoft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json diff --git a/change/@microsoft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json b/change/@microsoft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json new file mode 100644 index 0000000000..cba96d2364 --- /dev/null +++ b/change/@microsoft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Modified `getMeetingDetailsVerbose` API return interface so that the `originalCaller` and `dialedEntity` properties are of a new type `ICallParticipantIdentifiers", + "packageName": "@microsoft/teams-js", + "email": "johnsle@microsoft.com", + "dependentChangeType": "patch" +} From 964ed7a576111c37db3d07d7a4c16bc1395109a9 Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Fri, 30 Aug 2024 11:59:58 -0700 Subject: [PATCH 03/10] Update property comments --- packages/teams-js/src/public/meeting.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/teams-js/src/public/meeting.ts b/packages/teams-js/src/public/meeting.ts index bf5f1fe3ac..9c60324551 100644 --- a/packages/teams-js/src/public/meeting.ts +++ b/packages/teams-js/src/public/meeting.ts @@ -119,13 +119,13 @@ export namespace meeting { export interface ICallDetails extends IMeetingOrCallDetailsBase { /** * @hidden - * Phone number of a PSTN caller or email of a VoIP caller + * originalCaller object */ originalCaller?: ICallParticipantIdentifiers; /** * @hidden - * Phone number of a PSTN callee or email of a VoIP callee + * dialedEntity object */ dialedEntity?: never; From e80ae3e21dab7d7ef7d208b6519a55795fb3b060 Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Wed, 25 Sep 2024 11:39:37 -0700 Subject: [PATCH 04/10] Update test version --- apps/teams-test-app/e2e-test-data/meeting.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/teams-test-app/e2e-test-data/meeting.json b/apps/teams-test-app/e2e-test-data/meeting.json index 4325b8de16..4988e716cd 100644 --- a/apps/teams-test-app/e2e-test-data/meeting.json +++ b/apps/teams-test-app/e2e-test-data/meeting.json @@ -35,7 +35,7 @@ }, { "title": "getMeetingDetailsVerbose API Call - Success", - "version": ">2.26.0", + "version": ">2.28.0", "type": "callResponse", "boxSelector": "#box_getMeetingDetailsVerbose", "expectedAlertValue": "getMeetingDetails called with shouldGetVerboseDetails: true", From d3158fb45a3d1e0e8c8d31f22091bec7ceec65fc Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Fri, 27 Sep 2024 13:50:38 -0700 Subject: [PATCH 05/10] Added new properties `originalCallerInfo` and `dialedEntityInfo` --- .../teams-test-app/e2e-test-data/meeting.json | 2 +- packages/teams-js/src/public/meeting.ts | 51 +++++++++++++++++-- packages/teams-js/test/public/meeting.spec.ts | 12 ++--- 3 files changed, 53 insertions(+), 12 deletions(-) diff --git a/apps/teams-test-app/e2e-test-data/meeting.json b/apps/teams-test-app/e2e-test-data/meeting.json index 4988e716cd..7971423cd2 100644 --- a/apps/teams-test-app/e2e-test-data/meeting.json +++ b/apps/teams-test-app/e2e-test-data/meeting.json @@ -39,7 +39,7 @@ "type": "callResponse", "boxSelector": "#box_getMeetingDetailsVerbose", "expectedAlertValue": "getMeetingDetails called with shouldGetVerboseDetails: true", - "expectedTestAppValue": "{\"details\":{\"scheduledStartTime\":\"testStartTime\",\"joinUrl\":\"testJoinUrl\",\"type\":\"oneOnOneCall\",\"originalCaller\":{\"phoneNumber\":\"testCallerPhoneNumber\",\"email\":\"testCallerEmail\"},\"dialedEntity\":{\"phoneNumber\":\"testCalleePhoneNumber\",\"email\":\"testCalleeEmail\"},\"trackingId\":\"testTrackingId\"},\"conversation\":{\"id\":\"testConversationId\"},\"organizer\":{\"id\":\"testOrganizerId\",\"tenantId\":\"testTenantId\"}}" + "expectedTestAppValue": "{\"details\":{\"scheduledStartTime\":\"testStartTime\",\"joinUrl\":\"testJoinUrl\",\"type\":\"oneOnOneCall\",\"originalCallerInfo\":{\"phoneNumber\":\"1234567890\",\"email\":{\"val\":\"calleremail@somedomain.com\"}},\"dialedEntityInfo\":{\"phoneNumber\":\"1234567890\",\"email\":{\"val\":\"calleeemail@somedomain.com\"}},\"trackingId\":\"testTrackingId\",\"callId\":\"testCallId\"},\"conversation\":{\"id\":\"testConversationId\"},\"organizer\":{\"id\":\"testOrganizerId\",\"tenantId\":\"testTenantId\"}}" }, { "title": "getAuthenticationTokenForAnonymousUser API Call - Success", diff --git a/packages/teams-js/src/public/meeting.ts b/packages/teams-js/src/public/meeting.ts index 9c60324551..5546cbd76a 100644 --- a/packages/teams-js/src/public/meeting.ts +++ b/packages/teams-js/src/public/meeting.ts @@ -108,7 +108,7 @@ export namespace meeting { /** * Email of a VoIP caller */ - email?: string; + email?: EmailAddress; } /** @@ -118,22 +118,44 @@ export namespace meeting { */ export interface ICallDetails extends IMeetingOrCallDetailsBase { /** + * @deprecated please use {@link ICallDetails.originalCallerInfo} instead + * * @hidden - * originalCaller object + * Phone number of a PSTN caller or email of a VoIP caller */ - originalCaller?: ICallParticipantIdentifiers; + originalCaller?: string; /** * @hidden - * dialedEntity object + * Object representing the original caller + */ + originalCallerInfo?: ICallParticipantIdentifiers; + + /** + * @deprecated please use {@link ICallDetails.dialedEntityInfo} instead + * + * @hidden + * Phone number of a PSTN callee or email of a VoIP callee */ dialedEntity?: never; + /** + * @hidden + * Object representing the entity the caller dialed + */ + dialedEntityInfo?: never; + /** * @hidden * Tracking identifier for grouping related calls */ trackingId?: never; + + /** + * @hidden + * Identifier for the current call + */ + callId?: never; } /** @@ -555,6 +577,25 @@ export namespace meeting { ScreenShare = 'ScreenShare', } + /** + * Represents a validated email. + * + * @hidden + * Hide from docs. + */ + export class EmailAddress { + public constructor(private readonly val: string) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(this.val)) { + throw new Error('Input email address does not have the correct format.'); + } + } + + public toString(): string { + return this.val; + } + } + /** * Allows an app to get the incoming audio speaker setting for the meeting user. * To learn more, visit https://aka.ms/teamsjs/getIncomingClientAudioState @@ -682,7 +723,7 @@ export namespace meeting { if ( (response.details?.type == CallType.GroupCall || response.details?.type == CallType.OneOnOneCall) && - !response.details.originalCaller + !response.details.originalCallerInfo ) { throw new Error(ErrorCode.NOT_SUPPORTED_ON_PLATFORM.toString()); } diff --git a/packages/teams-js/test/public/meeting.spec.ts b/packages/teams-js/test/public/meeting.spec.ts index 436388ea7a..e4e8fedc49 100644 --- a/packages/teams-js/test/public/meeting.spec.ts +++ b/packages/teams-js/test/public/meeting.spec.ts @@ -277,9 +277,9 @@ describe('meeting', () => { 'https://teams.microsoft.com/l/meetup-join/19%3ameeting_qwertyuiop[phgfdsasdfghjkjbvcxcvbnmyt1234567890!@#$%^&*(%40thread.v2/0?context=%7b%22Tid%22%3a%2272f988bf-86f1-41af-91ab-2d7cd011db47%22%2c%22Oid%22%3a%226b33ac33-85ae-4995-be29-1d38a77aa8e3%22%7d', type: meeting.CallType.OneOnOneCall, // Verbose details - originalCaller: { - phoneNumber: 'testCallerPhoneNumber', - email: 'testCallerEmail', + originalCallerInfo: { + phoneNumber: '1234567890', + email: new meeting.EmailAddress('calleremail@somedomain.com'), }, }; const organizer: meeting.IOrganizer = { @@ -630,9 +630,9 @@ describe('meeting', () => { 'https://teams.microsoft.com/l/meetup-join/19%3ameeting_qwertyuiop[phgfdsasdfghjkjbvcxcvbnmyt1234567890!@#$%^&*(%40thread.v2/0?context=%7b%22Tid%22%3a%2272f988bf-86f1-41af-91ab-2d7cd011db47%22%2c%22Oid%22%3a%226b33ac33-85ae-4995-be29-1d38a77aa8e3%22%7d', type: meeting.CallType.OneOnOneCall, // Verbose details - originalCaller: { - phoneNumber: 'testCallerPhoneNumber', - email: 'testCallerEmail', + originalCallerInfo: { + phoneNumber: '1234567890', + email: new meeting.EmailAddress('calleeemail@somedomain.com'), }, }; const organizer: meeting.IOrganizer = { From 3c0ac76c74ade3af74d03834bedb2be01bafa479 Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Fri, 27 Sep 2024 14:00:30 -0700 Subject: [PATCH 06/10] Update change file --- ...microsoft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/change/@microsoft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json b/change/@microsoft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json index cba96d2364..09b008e35c 100644 --- a/change/@microsoft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json +++ b/change/@microsoft-teams-js-4c2cf5b3-6661-4e5f-925b-7a8a49ad9d91.json @@ -1,6 +1,6 @@ { "type": "minor", - "comment": "Modified `getMeetingDetailsVerbose` API return interface so that the `originalCaller` and `dialedEntity` properties are of a new type `ICallParticipantIdentifiers", + "comment": "Added three properties to `ICallDetails`, `originalCallerInfo`, `dialedEntityInfo`, and `callId`, created a new type `ICallParticipantIdentifiers`, and deprecated the `originalCaller` and `dialedEntity` properties", "packageName": "@microsoft/teams-js", "email": "johnsle@microsoft.com", "dependentChangeType": "patch" From 753866fa9498d97f494ad2342a5a3c414ddbc157 Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Fri, 27 Sep 2024 16:40:48 -0700 Subject: [PATCH 07/10] Re-include original test case --- apps/teams-test-app/e2e-test-data/meeting.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/apps/teams-test-app/e2e-test-data/meeting.json b/apps/teams-test-app/e2e-test-data/meeting.json index 7971423cd2..63e9be7d3e 100644 --- a/apps/teams-test-app/e2e-test-data/meeting.json +++ b/apps/teams-test-app/e2e-test-data/meeting.json @@ -33,6 +33,14 @@ "expectedAlertValue": "getMeetingDetails called with shouldGetVerboseDetails: undefined", "expectedTestAppValue": "{\"details\":{\"id\":\"testDetailsId\",\"scheduledStartTime\":\"testStartTime\",\"scheduledEndTime\":\"testEndTime\",\"joinUrl\":\"testJoinUrl\",\"title\":\"testTitle\",\"type\":\"Unknown\"},\"conversation\":{\"id\":\"testConversationId\"},\"organizer\":{\"id\":\"testOrganizerId\",\"tenantId\":\"testTenantId\"}}" }, + { + "title": "getMeetingDetailsVerbose API Call - Success", + "version": ">2.22.0 && <= 2.28.0", + "type": "callResponse", + "boxSelector": "#box_getMeetingDetailsVerbose", + "expectedAlertValue": "getMeetingDetails called with shouldGetVerboseDetails: true", + "expectedTestAppValue": "{\"details\":{\"scheduledStartTime\":\"testStartTime\",\"joinUrl\":\"testJoinUrl\",\"type\":\"oneOnOneCall\",\"originalCaller\":\"testCallerId\",\"dialedEntity\":\"testDnis\",\"trackingId\":\"testTrackingId\"},\"conversation\":{\"id\":\"testConversationId\"},\"organizer\":{\"id\":\"testOrganizerId\",\"tenantId\":\"testTenantId\"}}" + }, { "title": "getMeetingDetailsVerbose API Call - Success", "version": ">2.28.0", From 4eaab1f06fb72ee584e56ac2c10e829879702b56 Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Fri, 27 Sep 2024 19:02:55 -0700 Subject: [PATCH 08/10] Add test for EmailAddress class --- packages/teams-js/test/public/meeting.spec.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/packages/teams-js/test/public/meeting.spec.ts b/packages/teams-js/test/public/meeting.spec.ts index e4e8fedc49..466a6cd2ba 100644 --- a/packages/teams-js/test/public/meeting.spec.ts +++ b/packages/teams-js/test/public/meeting.spec.ts @@ -2266,4 +2266,26 @@ describe('meeting', () => { }); }); }); + describe('utility', () => { + const invalidEmails = ['@@domain.com', 'firstname lastname@domain.com', 'name@domain']; + invalidEmails.forEach((invalidEmail) => { + it('should throw errors for invalid email addresses', () => { + expect(() => new meeting.EmailAddress(invalidEmail)).toThrowError( + 'Input email address does not have the correct format.', + ); + }); + }); + const validEmails = [ + 'email@domain.com', + 'firstname+lastname@domain.com', + '123@domain.com', + 'name@domain.subdomain.com', + ]; + validEmails.forEach((validEmail) => { + it('should not throw errors for valid email addresses', () => { + const email = new meeting.EmailAddress(validEmail); + expect(email.toString()).toBe(validEmail); + }); + }); + }); }); From 8e5bef5e38fc0918fcaa30e79e035f1ace6b4422 Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Mon, 30 Sep 2024 15:44:16 -0700 Subject: [PATCH 09/10] Add EmailAddress class --- packages/teams-js/src/public/emailAddress.ts | 18 ++++++++++++ packages/teams-js/src/public/index.ts | 1 + packages/teams-js/src/public/meeting.ts | 20 +------------ .../teams-js/test/public/emailAddress.spec.ts | 24 ++++++++++++++++ packages/teams-js/test/public/meeting.spec.ts | 28 ++----------------- 5 files changed, 47 insertions(+), 44 deletions(-) create mode 100644 packages/teams-js/src/public/emailAddress.ts create mode 100644 packages/teams-js/test/public/emailAddress.spec.ts diff --git a/packages/teams-js/src/public/emailAddress.ts b/packages/teams-js/src/public/emailAddress.ts new file mode 100644 index 0000000000..3fbcda2ada --- /dev/null +++ b/packages/teams-js/src/public/emailAddress.ts @@ -0,0 +1,18 @@ +/** + * Represents a validated email. + * + * @hidden + * Hide from docs. + */ +export class EmailAddress { + public constructor(private readonly val: string) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(this.val)) { + throw new Error('Input email address does not have the correct format.'); + } + } + + public toString(): string { + return this.val; + } +} diff --git a/packages/teams-js/src/public/index.ts b/packages/teams-js/src/public/index.ts index 49193f2cf3..b8ee1fcb30 100644 --- a/packages/teams-js/src/public/index.ts +++ b/packages/teams-js/src/public/index.ts @@ -42,6 +42,7 @@ export { } from './interfaces'; export { app } from './app'; export { AppId } from './appId'; +export { EmailAddress } from './emailAddress'; export { appInstallDialog } from './appInstallDialog'; export { barCode } from './barCode'; export { chat, OpenGroupChatRequest, OpenSingleChatRequest } from './chat'; diff --git a/packages/teams-js/src/public/meeting.ts b/packages/teams-js/src/public/meeting.ts index 5546cbd76a..9f36169267 100644 --- a/packages/teams-js/src/public/meeting.ts +++ b/packages/teams-js/src/public/meeting.ts @@ -3,6 +3,7 @@ import { doesHandlerExist, registerHandler, removeHandler } from '../internal/ha import { ensureInitialized } from '../internal/internalAPIs'; import { ApiName, ApiVersionNumber, getApiVersionTag } from '../internal/telemetry'; import { FrameContexts } from './constants'; +import { EmailAddress } from './emailAddress'; import { ErrorCode, SdkError } from './interfaces'; import { runtime } from './runtime'; @@ -577,25 +578,6 @@ export namespace meeting { ScreenShare = 'ScreenShare', } - /** - * Represents a validated email. - * - * @hidden - * Hide from docs. - */ - export class EmailAddress { - public constructor(private readonly val: string) { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(this.val)) { - throw new Error('Input email address does not have the correct format.'); - } - } - - public toString(): string { - return this.val; - } - } - /** * Allows an app to get the incoming audio speaker setting for the meeting user. * To learn more, visit https://aka.ms/teamsjs/getIncomingClientAudioState diff --git a/packages/teams-js/test/public/emailAddress.spec.ts b/packages/teams-js/test/public/emailAddress.spec.ts new file mode 100644 index 0000000000..3dae0726e1 --- /dev/null +++ b/packages/teams-js/test/public/emailAddress.spec.ts @@ -0,0 +1,24 @@ +import { EmailAddress } from '../../src/public'; + +describe('emailAddress', () => { + const invalidEmails = ['@@domain.com', 'firstname lastname@domain.com', 'name@domain']; + invalidEmails.forEach((invalidEmail) => { + it('should throw errors for invalid email addresses', () => { + expect(() => new EmailAddress(invalidEmail)).toThrowError( + 'Input email address does not have the correct format.', + ); + }); + }); + const validEmails = [ + 'email@domain.com', + 'firstname+lastname@domain.com', + '123@domain.com', + 'name@domain.subdomain.com', + ]; + validEmails.forEach((validEmail) => { + it('should not throw errors for valid email addresses', () => { + const email = new EmailAddress(validEmail); + expect(email.toString()).toBe(validEmail); + }); + }); +}); diff --git a/packages/teams-js/test/public/meeting.spec.ts b/packages/teams-js/test/public/meeting.spec.ts index 466a6cd2ba..f603a3f87f 100644 --- a/packages/teams-js/test/public/meeting.spec.ts +++ b/packages/teams-js/test/public/meeting.spec.ts @@ -2,7 +2,7 @@ import { errorLibraryNotInitialized } from '../../src/internal/constants'; import { GlobalVars } from '../../src/internal/globalVars'; import { DOMMessageEvent } from '../../src/internal/interfaces'; import { MessageRequest } from '../../src/internal/messageObjects'; -import { FrameContexts } from '../../src/public'; +import { EmailAddress, FrameContexts } from '../../src/public'; import { app } from '../../src/public/app'; import { ErrorCode, SdkError } from '../../src/public/interfaces'; import { meeting } from '../../src/public/meeting'; @@ -279,7 +279,7 @@ describe('meeting', () => { // Verbose details originalCallerInfo: { phoneNumber: '1234567890', - email: new meeting.EmailAddress('calleremail@somedomain.com'), + email: new EmailAddress('calleremail@somedomain.com'), }, }; const organizer: meeting.IOrganizer = { @@ -632,7 +632,7 @@ describe('meeting', () => { // Verbose details originalCallerInfo: { phoneNumber: '1234567890', - email: new meeting.EmailAddress('calleeemail@somedomain.com'), + email: new EmailAddress('calleeemail@somedomain.com'), }, }; const organizer: meeting.IOrganizer = { @@ -2266,26 +2266,4 @@ describe('meeting', () => { }); }); }); - describe('utility', () => { - const invalidEmails = ['@@domain.com', 'firstname lastname@domain.com', 'name@domain']; - invalidEmails.forEach((invalidEmail) => { - it('should throw errors for invalid email addresses', () => { - expect(() => new meeting.EmailAddress(invalidEmail)).toThrowError( - 'Input email address does not have the correct format.', - ); - }); - }); - const validEmails = [ - 'email@domain.com', - 'firstname+lastname@domain.com', - '123@domain.com', - 'name@domain.subdomain.com', - ]; - validEmails.forEach((validEmail) => { - it('should not throw errors for valid email addresses', () => { - const email = new meeting.EmailAddress(validEmail); - expect(email.toString()).toBe(validEmail); - }); - }); - }); }); From be248cd542e482e87879174e002add490a77d331 Mon Sep 17 00:00:00 2001 From: Johnny Lee Date: Mon, 30 Sep 2024 16:11:06 -0700 Subject: [PATCH 10/10] Spin email validation out to own utility function --- .../src/internal/emailAddressValidation.ts | 6 +++++ packages/teams-js/src/public/emailAddress.ts | 7 +++--- .../internal/emailAddressValidation.spec.ts | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 packages/teams-js/src/internal/emailAddressValidation.ts create mode 100644 packages/teams-js/test/internal/emailAddressValidation.spec.ts diff --git a/packages/teams-js/src/internal/emailAddressValidation.ts b/packages/teams-js/src/internal/emailAddressValidation.ts new file mode 100644 index 0000000000..ba25b61cf7 --- /dev/null +++ b/packages/teams-js/src/internal/emailAddressValidation.ts @@ -0,0 +1,6 @@ +export function validateEmailAddress(emailString: string): void { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(emailString)) { + throw new Error('Input email address does not have the correct format.'); + } +} diff --git a/packages/teams-js/src/public/emailAddress.ts b/packages/teams-js/src/public/emailAddress.ts index 3fbcda2ada..fbf8c67740 100644 --- a/packages/teams-js/src/public/emailAddress.ts +++ b/packages/teams-js/src/public/emailAddress.ts @@ -1,3 +1,5 @@ +import { validateEmailAddress } from '../internal/emailAddressValidation'; + /** * Represents a validated email. * @@ -6,10 +8,7 @@ */ export class EmailAddress { public constructor(private readonly val: string) { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - if (!emailRegex.test(this.val)) { - throw new Error('Input email address does not have the correct format.'); - } + validateEmailAddress(val); } public toString(): string { diff --git a/packages/teams-js/test/internal/emailAddressValidation.spec.ts b/packages/teams-js/test/internal/emailAddressValidation.spec.ts new file mode 100644 index 0000000000..49d39b3348 --- /dev/null +++ b/packages/teams-js/test/internal/emailAddressValidation.spec.ts @@ -0,0 +1,23 @@ +import { validateEmailAddress } from '../../src/internal/emailAddressValidation'; + +describe('emailAddressValidation', () => { + const invalidEmails = ['@@domain.com', 'firstname lastname@domain.com', 'name@domain']; + invalidEmails.forEach((invalidEmail) => { + it('should throw errors for invalid email addresses', () => { + expect(() => validateEmailAddress(invalidEmail)).toThrow('Input email address does not have the correct format.'); + }); + }); + const validEmails = [ + 'email@domain.com', + 'firstname+lastname@domain.com', + '123@domain.com', + 'name@domain.subdomain.com', + ]; + validEmails.forEach((validEmail) => { + it('should not throw errors for valid email addresses', () => { + expect(() => validateEmailAddress(validEmail)).not.toThrow( + 'Input email address does not have the correct format.', + ); + }); + }); +});