From e56cc4d8e54f656b67e51f4bd7c50cc86a7d8bd6 Mon Sep 17 00:00:00 2001 From: Lakhveer Kaur Date: Fri, 15 Nov 2024 12:10:40 -0800 Subject: [PATCH 1/6] Adding optional feature sets to eligibility data --- .../src/private/copilot/eligibility.ts | 4 +++- packages/teams-js/src/public/interfaces.ts | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/teams-js/src/private/copilot/eligibility.ts b/packages/teams-js/src/private/copilot/eligibility.ts index e42d56b719..50791d0a52 100644 --- a/packages/teams-js/src/private/copilot/eligibility.ts +++ b/packages/teams-js/src/private/copilot/eligibility.ts @@ -80,7 +80,9 @@ function isEligibilityInfoValid(eligibilityInfo: AppEligibilityInformation): boo eligibilityInfo.userClassification === undefined || eligibilityInfo.isCopilotEligible === undefined || eligibilityInfo.isCopilotEnabledRegion === undefined || - eligibilityInfo.isOptedOutByAdmin === undefined + eligibilityInfo.isOptedOutByAdmin === undefined || + (eligibilityInfo.featureSet && + (eligibilityInfo.featureSet.serverFeatures === undefined || eligibilityInfo.featureSet.uxFeatures === undefined)) ) { return false; } diff --git a/packages/teams-js/src/public/interfaces.ts b/packages/teams-js/src/public/interfaces.ts index ab607a1864..aa95911c50 100644 --- a/packages/teams-js/src/public/interfaces.ts +++ b/packages/teams-js/src/public/interfaces.ts @@ -1148,6 +1148,26 @@ export interface AppEligibilityInformation { * Education Eligibility Information for the app user */ userClassification: UserClassification | null; + /** + * Feature Sets + */ + featureSet?: FeatureSet | null; +} + +/** + * @hidden + * @beta + * Represents the feature set available to the user. + */ +export interface FeatureSet { + /** + * UX Feature set + */ + uxFeatures: string[]; + /** + * Server Feature set + */ + serverFeatures: string[]; } /** From 9afa14fbf0aff63a6cda652ec078b808165bca7f Mon Sep 17 00:00:00 2001 From: Lakhveer Kaur Date: Fri, 15 Nov 2024 12:12:18 -0800 Subject: [PATCH 2/6] changefile --- ...soft-teams-js-fc4a8f34-92ca-48dc-9c74-c84d8eed6a89.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@microsoft-teams-js-fc4a8f34-92ca-48dc-9c74-c84d8eed6a89.json diff --git a/change/@microsoft-teams-js-fc4a8f34-92ca-48dc-9c74-c84d8eed6a89.json b/change/@microsoft-teams-js-fc4a8f34-92ca-48dc-9c74-c84d8eed6a89.json new file mode 100644 index 0000000000..5b8b7b14c6 --- /dev/null +++ b/change/@microsoft-teams-js-fc4a8f34-92ca-48dc-9c74-c84d8eed6a89.json @@ -0,0 +1,7 @@ +{ + "type": "minor", + "comment": "Added optional `FeatureSet` field to `AppEligibilityInformation` interface", + "packageName": "@microsoft/teams-js", + "email": "email not defined", + "dependentChangeType": "patch" +} From 8f756b18d3e41b2386a8f468d834386689333cfc Mon Sep 17 00:00:00 2001 From: Lakhveer Kaur Date: Mon, 18 Nov 2024 16:11:51 -0800 Subject: [PATCH 3/6] updating interface --- packages/teams-js/src/public/interfaces.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/teams-js/src/public/interfaces.ts b/packages/teams-js/src/public/interfaces.ts index aa95911c50..e3829e757d 100644 --- a/packages/teams-js/src/public/interfaces.ts +++ b/packages/teams-js/src/public/interfaces.ts @@ -1151,7 +1151,7 @@ export interface AppEligibilityInformation { /** * Feature Sets */ - featureSet?: FeatureSet | null; + featureSet?: FeatureSet; } /** From 80b24343613bfe00959e57563fcf9bf25dd1bcd2 Mon Sep 17 00:00:00 2001 From: Lakhveer Kaur Date: Mon, 18 Nov 2024 16:33:46 -0800 Subject: [PATCH 4/6] adding UTs --- .../teams-js/test/private/copilot.spec.ts | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/packages/teams-js/test/private/copilot.spec.ts b/packages/teams-js/test/private/copilot.spec.ts index 4de25d9e4b..b270558743 100644 --- a/packages/teams-js/test/private/copilot.spec.ts +++ b/packages/teams-js/test/private/copilot.spec.ts @@ -16,6 +16,7 @@ const mockedAppEligibilityInformation = { persona: Persona.Student, eduType: EduType.HigherEducation, }, + featureSet: { serverFeatures: ['feature1', 'feature2'], uxFeatures: ['feature3'] }, }; const mockedAppEligibilityInformationUserClassificationNull = { @@ -188,6 +189,24 @@ describe('copilot', () => { return expect(promise).resolves.toEqual(mockedAppEligibilityInformation); }); + it(`should not throw if featureSet in response is undefined - with context ${frameContext}`, async () => { + await utils.initializeWithContext(frameContext); + utils.setRuntimeConfig(copilotRuntimeConfig); + + const promise = copilot.eligibility.getEligibilityInfo(); + const message = utils.findMessageByFunc('copilot.eligibility.getEligibilityInfo'); + const mockedAppEligibilityInformationWithUndefinedFeatureSet = { + ...mockedAppEligibilityInformation, + featureSet: undefined, + }; + expect(message).not.toBeNull(); + if (message) { + utils.respondToMessage(message, mockedAppEligibilityInformationWithUndefinedFeatureSet); + } + + return expect(promise).resolves.toEqual(mockedAppEligibilityInformationWithUndefinedFeatureSet); + }); + it(`should throw error if host returns error - with context ${frameContext}`, async () => { await utils.initializeWithContext(frameContext); utils.setRuntimeConfig(copilotRuntimeConfig); @@ -319,6 +338,28 @@ describe('copilot', () => { await expect(promise).rejects.toThrowError('Error deserializing eligibility information'); }); + + it('getEligibilityInfo should throw if AppEligibilityInformation.featureSet.serverFeatures or uxFeatures is undefined', async () => { + await utils.initializeWithContext(FrameContexts.content); + utils.setRuntimeConfig(copilotRuntimeConfig); + + const mockedInvalidAppEligibilityInformationWithInvalidUxFeatures = { + ...mockedAppEligibilityInformation, + featureSet: { + serverFeatures: [], + uxFeatures: undefined, + }, + }; + + const promise = copilot.eligibility.getEligibilityInfo(); + const message = utils.findMessageByFunc('copilot.eligibility.getEligibilityInfo'); + expect(message).not.toBeNull(); + if (message) { + utils.respondToMessage(message, mockedInvalidAppEligibilityInformationWithInvalidUxFeatures); + } + + await expect(promise).rejects.toThrowError('Error deserializing eligibility information'); + }); }); }); }); From a43f2e2d64945f43215e926a6bb6d17bf6c97e61 Mon Sep 17 00:00:00 2001 From: Lakhveer Kaur Date: Tue, 19 Nov 2024 10:35:40 -0800 Subject: [PATCH 5/6] Adding UT --- packages/teams-js/src/public/interfaces.ts | 16 ++++++------- .../teams-js/test/private/copilot.spec.ts | 24 ++++++++++++++++++- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/packages/teams-js/src/public/interfaces.ts b/packages/teams-js/src/public/interfaces.ts index e3829e757d..76596c75c9 100644 --- a/packages/teams-js/src/public/interfaces.ts +++ b/packages/teams-js/src/public/interfaces.ts @@ -1132,6 +1132,10 @@ export interface AppEligibilityInformation { * A user will be in at most one cohort. */ cohort: Cohort | null; + /** + * Feature Sets + */ + featureSet?: FeatureSet; /** * Indicates that the user is eligible for Microsoft Entra ID Authenticated Copilot experience. */ @@ -1148,10 +1152,6 @@ export interface AppEligibilityInformation { * Education Eligibility Information for the app user */ userClassification: UserClassification | null; - /** - * Feature Sets - */ - featureSet?: FeatureSet; } /** @@ -1160,14 +1160,14 @@ export interface AppEligibilityInformation { * Represents the feature set available to the user. */ export interface FeatureSet { - /** - * UX Feature set - */ - uxFeatures: string[]; /** * Server Feature set */ serverFeatures: string[]; + /** + * UX Feature set + */ + uxFeatures: string[]; } /** diff --git a/packages/teams-js/test/private/copilot.spec.ts b/packages/teams-js/test/private/copilot.spec.ts index b270558743..6d89749d24 100644 --- a/packages/teams-js/test/private/copilot.spec.ts +++ b/packages/teams-js/test/private/copilot.spec.ts @@ -339,7 +339,29 @@ describe('copilot', () => { await expect(promise).rejects.toThrowError('Error deserializing eligibility information'); }); - it('getEligibilityInfo should throw if AppEligibilityInformation.featureSet.serverFeatures or uxFeatures is undefined', async () => { + it('getEligibilityInfo should throw if AppEligibilityInformation.featureSet.serverFeatures is undefined', async () => { + await utils.initializeWithContext(FrameContexts.content); + utils.setRuntimeConfig(copilotRuntimeConfig); + + const mockedInvalidAppEligibilityInformationWithInvalidUxFeatures = { + ...mockedAppEligibilityInformation, + featureSet: { + serverFeatures: undefined, + uxFeatures: [], + }, + }; + + const promise = copilot.eligibility.getEligibilityInfo(); + const message = utils.findMessageByFunc('copilot.eligibility.getEligibilityInfo'); + expect(message).not.toBeNull(); + if (message) { + utils.respondToMessage(message, mockedInvalidAppEligibilityInformationWithInvalidUxFeatures); + } + + await expect(promise).rejects.toThrowError('Error deserializing eligibility information'); + }); + + it('getEligibilityInfo should throw if AppEligibilityInformation.featureSet.uxFeatures is undefined', async () => { await utils.initializeWithContext(FrameContexts.content); utils.setRuntimeConfig(copilotRuntimeConfig); From af49dad7b3c982dba65a97575122a8382fd9f0c3 Mon Sep 17 00:00:00 2001 From: Lakhveer Kaur Date: Mon, 2 Dec 2024 10:16:55 -0800 Subject: [PATCH 6/6] make the feature set property readyOnly --- packages/teams-js/src/public/interfaces.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/teams-js/src/public/interfaces.ts b/packages/teams-js/src/public/interfaces.ts index 76596c75c9..8f10629bb5 100644 --- a/packages/teams-js/src/public/interfaces.ts +++ b/packages/teams-js/src/public/interfaces.ts @@ -1134,6 +1134,7 @@ export interface AppEligibilityInformation { cohort: Cohort | null; /** * Feature Sets + * If this property is undefined, it indicates that the host is an older version that doesn't support this property. */ featureSet?: FeatureSet; /** @@ -1163,11 +1164,11 @@ export interface FeatureSet { /** * Server Feature set */ - serverFeatures: string[]; + serverFeatures: ReadonlyArray; /** * UX Feature set */ - uxFeatures: string[]; + uxFeatures: ReadonlyArray; } /**