From f0f6dbf6f4019d76690791d006fd3d46eb50f676 Mon Sep 17 00:00:00 2001 From: Beau Cameron Date: Mon, 2 Oct 2023 16:19:12 -0600 Subject: [PATCH 1/3] WIP - Teams App Catalog --- packages/graph/appCatalogs/index.ts | 22 +++++++ packages/graph/appCatalogs/types.ts | 99 +++++++++++++++++++++++++++++ packages/graph/teams/types.ts | 2 +- 3 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 packages/graph/appCatalogs/index.ts create mode 100644 packages/graph/appCatalogs/types.ts diff --git a/packages/graph/appCatalogs/index.ts b/packages/graph/appCatalogs/index.ts new file mode 100644 index 000000000..5574c454c --- /dev/null +++ b/packages/graph/appCatalogs/index.ts @@ -0,0 +1,22 @@ +import { GraphFI } from "../fi.js"; +import { AppCatalogs, IAppCatalogs} from "./types.js"; + + +export { + AppCatalogs, + IAppCatalogs, +} from "./types.js"; + +declare module "../fi" { + interface GraphFI { + readonly appCatalogs: IAppCatalogs; + } +} + +Reflect.defineProperty(GraphFI.prototype, "appCatalogs", { + configurable: true, + enumerable: true, + get: function (this: GraphFI) { + return this.create(AppCatalogs); + }, +}); diff --git a/packages/graph/appCatalogs/types.ts b/packages/graph/appCatalogs/types.ts new file mode 100644 index 000000000..a33369fdb --- /dev/null +++ b/packages/graph/appCatalogs/types.ts @@ -0,0 +1,99 @@ + +import { AppCatalogs as IAppCatalogsType, TeamsApp as ITeamsAppType, TeamsAppDefinition as ITeamsAppDefinitionType } from "@microsoft/microsoft-graph-types"; +import { _GraphCollection, graphInvokableFactory, _GraphInstance, graphPost, graphDelete } from "../graphqueryable.js"; +import { IGetById, defaultPath, getById } from "../decorators.js"; +import { InjectHeaders } from "@pnp/queryable/index.js"; + +/** + * AppCatalogs + */ + +@defaultPath("appCatalogs") +export class _AppCatalogs extends _GraphInstance { + /** + * Get teams apps in appCatalog + * + */ + public get teamsApps(): ITeamsApps { + return TeamsApps(this); + } + +} +export interface IAppCatalogs extends _AppCatalogs { } +export const AppCatalogs = graphInvokableFactory(_AppCatalogs); + + +/** + * AppDefinitions + */ +export class _AppDefinition extends _GraphInstance { } +export interface IAppDefinition extends _AppDefinition { } +export const AppDefinitions = graphInvokableFactory(_AppDefinition); + + +/** + * TeamsApp + */ +export class _TeamsApp extends _GraphInstance { + + /** + * Deletes a Teams App + * + */ + public async delete(appDefinitionId?: string): Promise { + + // Un-approved apps must be deleted differently. https://learn.microsoft.com/en-us/graph/api/teamsapp-delete?view=graph-rest-1.0&tabs=http#permissions + if(appDefinitionId){ + return graphDelete(TeamsApp(this,`/appDefinitions/${appDefinitionId}`)); + } + return graphDelete(this); + } + + /** + * Updates a Teams App + * + * @param zip zip file of app + * @param requiresReview This optional query parameter triggers the app review process. Users with admin privileges can submit apps without triggering a review. + */ + public async update(zip: Blob, requiresReview:boolean = false): Promise { + + const q = TeamsApp(this,`appDefinitions?$requiresReview=${requiresReview}`); + q.using(InjectHeaders({ + "Content-Type": "application/zip", + })); + + return graphPost(q, { body: zip }); + } + +} + +export interface ITeamsApp extends _TeamsApp { } +export const TeamsApp = graphInvokableFactory(_TeamsApp); + + +/** + * TeamsApps + */ + +@defaultPath("teamsApps") +@getById(TeamsApp) +export class _TeamsApps extends _GraphCollection { + + /** + * Adds a Teams App + * + * @param zip zip file of app + * @param requiresReview This optional query parameter triggers the app review process. Users with admin privileges can submit apps without triggering a review. + */ + public async add(zip: Blob, requiresReview:boolean = false): Promise { + + const q = TeamsApp(this); + q.using(InjectHeaders({ + "Content-Type": "application/zip", + })); + + return graphPost(q, { body: zip }); + } + } +export interface ITeamsApps extends _TeamsApps, IGetById {} { } +export const TeamsApps = graphInvokableFactory(_TeamsApps); diff --git a/packages/graph/teams/types.ts b/packages/graph/teams/types.ts index 7ac7c401c..fce469c61 100644 --- a/packages/graph/teams/types.ts +++ b/packages/graph/teams/types.ts @@ -180,7 +180,7 @@ export interface IMessage extends _Message { } export const Message = graphInvokableFactory(_Message); /** - * Channels + * Messages */ @defaultPath("messages") @getById(Message) From 5df22dd1fa39cf3187e104fec323ee9403a97bc8 Mon Sep 17 00:00:00 2001 From: Beau Cameron Date: Fri, 13 Oct 2023 10:22:04 -0600 Subject: [PATCH 2/3] AppCatalog Docs --- docs/graph/appCatalogs.md | 83 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 docs/graph/appCatalogs.md diff --git a/docs/graph/appCatalogs.md b/docs/graph/appCatalogs.md new file mode 100644 index 000000000..e15c42c25 --- /dev/null +++ b/docs/graph/appCatalogs.md @@ -0,0 +1,83 @@ +# @pnp/graph/appcatalogs + +The ability to use Teams App Catalogs + +## AppCatalogs, IAppCatalogs + +[![Invokable Banner](https://img.shields.io/badge/Invokable-informational.svg)](../concepts/invokable.md) [![Selective Imports Banner](https://img.shields.io/badge/Selective%20Imports-informational.svg)](../concepts/selective-imports.md) + +## Get Teams Apps in App Catalog + +Using teamsApps() you get the Teams AppCatalog + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalogs"; + +const graph = graphfi(...); + +const apps = await graph.appCatalogs.teamsApps(); + +``` +## Get Teams Apps by Id + +Using getById() you get the Teams App by Id + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalogs"; + +const graph = graphfi(...); + +const apps = await graph.appCatalogs.teamsApps.getById('{teams app id}')(); + +``` +## Add a Teams App + + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalogs"; + +const graph = graphfi(...); +const appPackage = {...} as Blob; + +//second parameter is "Requires Approval" +const app = await graph.appCatalogs.teamsApps.getById('{teams app id}').add(appPackage, false); + +``` +## Update a Teams App + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalogs"; + +const graph = graphfi(...); +const appPackage = {...} as Blob; + +//second parameter is "Requires Approval" +const app = await graph.appCatalogs.teamsApps.getById('{teams app id}').update(appPackage, false); + +``` +## Delete a Teams App + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalogs"; + +const graph = graphfi(...); + +//delete a Teams App +await graph.appCatalogs.teamsApps.getById(app).delete(); + +// delete an un-approved Teams App requires the app definition id. +// sample is just selecting the first app definition. +const appDefinition = (await graph.appCatalogs.teamsApps.getById("{teams app id}")()).appDefinitions[0]; +await graph.appCatalogs.teamsApps.getById(app).delete(appDefinition); + +``` \ No newline at end of file From db78afa80b2389d1ca9a668259065f5ee7327fbd Mon Sep 17 00:00:00 2001 From: Beau Cameron Date: Sun, 22 Oct 2023 12:39:09 -0600 Subject: [PATCH 3/3] Adding Tests, Refactoring, adding missing endpoints --- docs/graph/appCatalog.md | 121 ++++++++++++++++++ docs/graph/appCatalogs.md | 83 ------------ packages/graph/appCatalog/index.ts | 22 ++++ .../{appCatalogs => appCatalog}/types.ts | 87 ++++++++----- packages/graph/appCatalogs/index.ts | 22 ---- packages/graph/presets/all.ts | 2 + test/graph/appCatalogs.ts | 47 +++++++ 7 files changed, 247 insertions(+), 137 deletions(-) create mode 100644 docs/graph/appCatalog.md delete mode 100644 docs/graph/appCatalogs.md create mode 100644 packages/graph/appCatalog/index.ts rename packages/graph/{appCatalogs => appCatalog}/types.ts (51%) delete mode 100644 packages/graph/appCatalogs/index.ts create mode 100644 test/graph/appCatalogs.ts diff --git a/docs/graph/appCatalog.md b/docs/graph/appCatalog.md new file mode 100644 index 000000000..9d664fcad --- /dev/null +++ b/docs/graph/appCatalog.md @@ -0,0 +1,121 @@ +# @pnp/graph/appcatalog + +The ability to use Teams App Catalog + +## AppCatalog, IAppCatalog + +[![Invokable Banner](https://img.shields.io/badge/Invokable-informational.svg)](../concepts/invokable.md) [![Selective Imports Banner](https://img.shields.io/badge/Selective%20Imports-informational.svg)](../concepts/selective-imports.md) + +## Get Teams Apps in App Catalog + +Using teamsApps() you get the Teams AppCatalog + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalog"; + +const graph = graphfi(...); + +const apps = await graph.appCatalog.teamsApps(); + +``` +## Get Teams Apps by Id + +Using getById() you get the Teams App by Id + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalog"; + +const graph = graphfi(...); + +const apps = await graph.appCatalog.teamsApps.getById('{teams app id}')(); + +``` +## Add a Teams App + + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalog"; + +const graph = graphfi(...); +const appPackage = {...} as Blob; + +//second parameter is "Requires Approval" +const app = await graph.appCatalog.teamsApps.getById('{teams app id}').add(appPackage, false); + +``` +## Update a Teams App + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalog"; + +const graph = graphfi(...); +const appPackage = {...} as Blob; + +//second parameter is "Requires Approval" +const app = await graph.appCatalog.teamsApps.getById('{teams app id}').update(appPackage, false); + +``` +## Delete a Teams App + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalog"; + +const graph = graphfi(...); + +//delete a Teams App +await graph.appCatalog.teamsApps.getById(app).delete(); + +// delete an un-approved Teams App requires the app definition id. +// sample is just selecting the first app definition. +const appDefinition = (await graph.appCatalog.teamsApps.getById("{teams app id}")()).appDefinitions[0]; +await graph.appCatalog.teamsApps.getById(app).delete(appDefinition); + +``` +## Get Teams App Definitions + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalog"; + +const graph = graphfi(...); + +//get teams app definitions +await graph.appCatalog.teamsApps.getById(`{teams app id}`).appDefinitions(); + +``` +## Get Teams App Definitions by Id + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalog"; + +const graph = graphfi(...); + +//get teams app definitions +await graph.appCatalog.teamsApps.getById(`{teams app id}`).appDefinitions.getById(`{Teams App Definition Id}`) + +``` +## Get Bot associated with Teams App Definition + +```TypeScript +import { graphfi } from "@pnp/graph"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalog"; + +const graph = graphfi(...); + +await graph.appCatalog.teamsApps.getById(`{teams app id}`).appDefinitions.getById(`{Teams App Definition Id}`).bot(); + +``` \ No newline at end of file diff --git a/docs/graph/appCatalogs.md b/docs/graph/appCatalogs.md deleted file mode 100644 index e15c42c25..000000000 --- a/docs/graph/appCatalogs.md +++ /dev/null @@ -1,83 +0,0 @@ -# @pnp/graph/appcatalogs - -The ability to use Teams App Catalogs - -## AppCatalogs, IAppCatalogs - -[![Invokable Banner](https://img.shields.io/badge/Invokable-informational.svg)](../concepts/invokable.md) [![Selective Imports Banner](https://img.shields.io/badge/Selective%20Imports-informational.svg)](../concepts/selective-imports.md) - -## Get Teams Apps in App Catalog - -Using teamsApps() you get the Teams AppCatalog - -```TypeScript -import { graphfi } from "@pnp/graph"; -import "@pnp/graph/teams"; -import "@pnp/graph/appCatalogs"; - -const graph = graphfi(...); - -const apps = await graph.appCatalogs.teamsApps(); - -``` -## Get Teams Apps by Id - -Using getById() you get the Teams App by Id - -```TypeScript -import { graphfi } from "@pnp/graph"; -import "@pnp/graph/teams"; -import "@pnp/graph/appCatalogs"; - -const graph = graphfi(...); - -const apps = await graph.appCatalogs.teamsApps.getById('{teams app id}')(); - -``` -## Add a Teams App - - -```TypeScript -import { graphfi } from "@pnp/graph"; -import "@pnp/graph/teams"; -import "@pnp/graph/appCatalogs"; - -const graph = graphfi(...); -const appPackage = {...} as Blob; - -//second parameter is "Requires Approval" -const app = await graph.appCatalogs.teamsApps.getById('{teams app id}').add(appPackage, false); - -``` -## Update a Teams App - -```TypeScript -import { graphfi } from "@pnp/graph"; -import "@pnp/graph/teams"; -import "@pnp/graph/appCatalogs"; - -const graph = graphfi(...); -const appPackage = {...} as Blob; - -//second parameter is "Requires Approval" -const app = await graph.appCatalogs.teamsApps.getById('{teams app id}').update(appPackage, false); - -``` -## Delete a Teams App - -```TypeScript -import { graphfi } from "@pnp/graph"; -import "@pnp/graph/teams"; -import "@pnp/graph/appCatalogs"; - -const graph = graphfi(...); - -//delete a Teams App -await graph.appCatalogs.teamsApps.getById(app).delete(); - -// delete an un-approved Teams App requires the app definition id. -// sample is just selecting the first app definition. -const appDefinition = (await graph.appCatalogs.teamsApps.getById("{teams app id}")()).appDefinitions[0]; -await graph.appCatalogs.teamsApps.getById(app).delete(appDefinition); - -``` \ No newline at end of file diff --git a/packages/graph/appCatalog/index.ts b/packages/graph/appCatalog/index.ts new file mode 100644 index 000000000..8fba9b1aa --- /dev/null +++ b/packages/graph/appCatalog/index.ts @@ -0,0 +1,22 @@ +import { GraphFI } from "../fi.js"; +import { AppCatalog, IAppCatalog} from "./types.js"; + + +export { + AppCatalog, + IAppCatalog, +} from "./types.js"; + +declare module "../fi" { + interface GraphFI { + readonly appCatalog: IAppCatalog; + } +} + +Reflect.defineProperty(GraphFI.prototype, "appCatalog", { + configurable: true, + enumerable: true, + get: function (this: GraphFI) { + return this.create(AppCatalog); + }, +}); diff --git a/packages/graph/appCatalogs/types.ts b/packages/graph/appCatalog/types.ts similarity index 51% rename from packages/graph/appCatalogs/types.ts rename to packages/graph/appCatalog/types.ts index a33369fdb..cad91a185 100644 --- a/packages/graph/appCatalogs/types.ts +++ b/packages/graph/appCatalog/types.ts @@ -1,7 +1,10 @@ - -import { AppCatalogs as IAppCatalogsType, TeamsApp as ITeamsAppType, TeamsAppDefinition as ITeamsAppDefinitionType } from "@microsoft/microsoft-graph-types"; -import { _GraphCollection, graphInvokableFactory, _GraphInstance, graphPost, graphDelete } from "../graphqueryable.js"; -import { IGetById, defaultPath, getById } from "../decorators.js"; +import { + AppCatalogs as IAppCatalogsType, + TeamsApp as ITeamsAppType, + TeamsAppDefinition as ITeamsAppDefinitionType, + TeamworkBot as ITeamworkBot } from "@microsoft/microsoft-graph-types"; +import { _GraphCollection, graphInvokableFactory, _GraphInstance, graphPost, graphDelete, graphGet } from "../graphqueryable.js"; +import { IGetById, defaultPath, getById } from "../decorators.js"; import { InjectHeaders } from "@pnp/queryable/index.js"; /** @@ -9,65 +12,86 @@ import { InjectHeaders } from "@pnp/queryable/index.js"; */ @defaultPath("appCatalogs") -export class _AppCatalogs extends _GraphInstance { +export class _AppCatalog extends _GraphInstance { /** * Get teams apps in appCatalog - * + * */ public get teamsApps(): ITeamsApps { return TeamsApps(this); } } -export interface IAppCatalogs extends _AppCatalogs { } -export const AppCatalogs = graphInvokableFactory(_AppCatalogs); +export interface IAppCatalog extends _AppCatalog {} +export const AppCatalog = graphInvokableFactory(_AppCatalog); +/** + * AppDefinition + */ +export class _AppDefinition extends _GraphInstance { + /** + * Gets bot associated with app + * + */ + public async bot(): Promise{ + return graphGet(AppDefinitions(this, "/bot")); + } +} +export interface IAppDefinition extends _AppDefinition { } +export const AppDefinition = graphInvokableFactory(_AppDefinition); /** * AppDefinitions */ -export class _AppDefinition extends _GraphInstance { } -export interface IAppDefinition extends _AppDefinition { } -export const AppDefinitions = graphInvokableFactory(_AppDefinition); + +@defaultPath("appDefinitions") +@getById(AppDefinition) +export class _AppDefinitions extends _GraphCollection {} +export interface IAppDefinitions extends _AppDefinitions, IGetById {} +export const AppDefinitions = graphInvokableFactory(_AppDefinitions); /** * TeamsApp */ -export class _TeamsApp extends _GraphInstance { +export class _TeamsApp extends _GraphInstance { + /** + * Get app definitions + * + */ + public get appDefinitions(): IAppDefinitions { + return AppDefinitions(this); + } /** * Deletes a Teams App - * + * */ public async delete(appDefinitionId?: string): Promise { - // Un-approved apps must be deleted differently. https://learn.microsoft.com/en-us/graph/api/teamsapp-delete?view=graph-rest-1.0&tabs=http#permissions if(appDefinitionId){ - return graphDelete(TeamsApp(this,`/appDefinitions/${appDefinitionId}`)); + return graphDelete(AppDefinitions(this,`/${appDefinitionId}`)); } return graphDelete(this); } - /** + /** * Updates a Teams App * * @param zip zip file of app - * @param requiresReview This optional query parameter triggers the app review process. Users with admin privileges can submit apps without triggering a review. + * @param requiresReview This optional query parameter triggers the app review process. Users with admin privileges can submit apps without triggering a review. */ - public async update(zip: Blob, requiresReview:boolean = false): Promise { - - const q = TeamsApp(this,`appDefinitions?$requiresReview=${requiresReview}`); + public async update(zip: Blob, requiresReview = false): Promise { + const q = AppDefinitions(this,`?$requiresReview=${requiresReview}`); q.using(InjectHeaders({ "Content-Type": "application/zip", })); - + return graphPost(q, { body: zip }); } - } -export interface ITeamsApp extends _TeamsApp { } +export interface ITeamsApp extends _TeamsApp{} export const TeamsApp = graphInvokableFactory(_TeamsApp); @@ -78,22 +102,21 @@ export const TeamsApp = graphInvokableFactory(_TeamsApp); @defaultPath("teamsApps") @getById(TeamsApp) export class _TeamsApps extends _GraphCollection { - - /** + /** * Adds a Teams App * * @param zip zip file of app - * @param requiresReview This optional query parameter triggers the app review process. Users with admin privileges can submit apps without triggering a review. + * @param requiresReview This optional query parameter triggers the app review process. Users with admin privileges can submit apps without triggering a review. + * */ - public async add(zip: Blob, requiresReview:boolean = false): Promise { - - const q = TeamsApp(this); + public async add(zip: Blob, requiresReview = false): Promise { + const q = TeamsApp(this, `?requiresReview=${requiresReview}`); q.using(InjectHeaders({ "Content-Type": "application/zip", })); - + return graphPost(q, { body: zip }); } - } -export interface ITeamsApps extends _TeamsApps, IGetById {} { } +} +export interface ITeamsApps extends _TeamsApps, IGetById{} export const TeamsApps = graphInvokableFactory(_TeamsApps); diff --git a/packages/graph/appCatalogs/index.ts b/packages/graph/appCatalogs/index.ts deleted file mode 100644 index 5574c454c..000000000 --- a/packages/graph/appCatalogs/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { GraphFI } from "../fi.js"; -import { AppCatalogs, IAppCatalogs} from "./types.js"; - - -export { - AppCatalogs, - IAppCatalogs, -} from "./types.js"; - -declare module "../fi" { - interface GraphFI { - readonly appCatalogs: IAppCatalogs; - } -} - -Reflect.defineProperty(GraphFI.prototype, "appCatalogs", { - configurable: true, - enumerable: true, - get: function (this: GraphFI) { - return this.create(AppCatalogs); - }, -}); diff --git a/packages/graph/presets/all.ts b/packages/graph/presets/all.ts index 641972213..2edcc11ad 100644 --- a/packages/graph/presets/all.ts +++ b/packages/graph/presets/all.ts @@ -1,3 +1,4 @@ +import "../appCatalog/index.js"; import "../attachments/index.js"; import "../calendars/index.js"; import "../cloud-communications/index.js"; @@ -20,6 +21,7 @@ import "../subscriptions/index.js"; import "../teams/index.js"; import "../users/index.js"; +export * from "../appCatalog/index.js"; export * from "../attachments/index.js"; export * from "../calendars/index.js"; export * from "../cloud-communications/index.js"; diff --git a/test/graph/appCatalogs.ts b/test/graph/appCatalogs.ts new file mode 100644 index 000000000..39aa54dc7 --- /dev/null +++ b/test/graph/appCatalogs.ts @@ -0,0 +1,47 @@ +import { expect } from "chai"; +import "@pnp/graph/teams"; +import "@pnp/graph/appCatalog"; +import { pnpTest } from "../pnp-test.js"; + +describe.only("AppCatalog", function () { + + before(async function () { + + if (!this.pnp.settings.enableWebTests) { + this.skip(); + } + }); + + it("teamsApps", pnpTest("32d84a70-52cb-47c8-8957-cda902c07d85", async function () { + const apps = await this.pnp.graph.appCatalog.teamsApps(); + return expect(apps).to.be.an("array") && expect(apps[0]).to.haveOwnProperty("id"); + })); + + it("teamsApps - getById()", pnpTest("17bfb2cd-8fd3-41d3-a387-2fcf410b7100", async function () { + let passed = false; + const apps = await this.pnp.graph.appCatalog.teamsApps(); + if (apps.length > 0) { + const app = await this.pnp.graph.appCatalog.teamsApps.getById(apps[0].id)(); + passed = (app.id === apps[0].id); + } + return expect(passed).is.true; + })); + + it("appDefinitions", pnpTest("63c8ef41-067f-4f58-bd78-9b5d8d60b5b4", async function () { + const apps = await this.pnp.graph.appCatalog.teamsApps(); + const appDefinitions = await this.pnp.graph.appCatalog.teamsApps.getById(apps[0].id).appDefinitions(); + return expect(appDefinitions).to.be.an("array") && expect(appDefinitions[0]).to.haveOwnProperty("id"); + })); + + it("appDefinitions - getById()", pnpTest("11dce742-2aeb-4b8e-8967-6f73b7fd55d6", async function () { + let passed = false; + const apps = await this.pnp.graph.appCatalog.teamsApps(); + const appDefinitions = await this.pnp.graph.appCatalog.teamsApps.getById(apps[0].id).appDefinitions(); + + if (apps.length > 0) { + const def = await this.pnp.graph.appCatalog.teamsApps.getById(apps[0].id).appDefinitions.getById(appDefinitions[0].id)(); + passed = (def.id === appDefinitions[0].id); + } + return expect(passed).is.true; + })); +});