From a478151fdeed0637ec80a6355031eadfc57cc491 Mon Sep 17 00:00:00 2001 From: Nanddeep Nachan Date: Sun, 6 Oct 2024 17:57:10 +0000 Subject: [PATCH 1/5] m365 spe container list --- .../docs/cmd/spe/container/container-list.mdx | 97 ++++++++++ docs/src/config/sidebars.ts | 9 + src/m365/spe/ContainerProperties.ts | 6 + src/m365/spe/ContainerTypeProperties.ts | 14 -- src/m365/spe/commands.ts | 1 + .../commands/container/container-list.spec.ts | 182 ++++++++++++++++++ .../spe/commands/container/container-list.ts | 113 +++++++++++ .../containertype/containertype-list.spec.ts | 145 ++++---------- .../containertype/containertype-list.ts | 30 +-- src/utils/spo.spec.ts | 90 +++++++++ src/utils/spo.ts | 38 ++++ 11 files changed, 577 insertions(+), 148 deletions(-) create mode 100644 docs/docs/cmd/spe/container/container-list.mdx create mode 100644 src/m365/spe/ContainerProperties.ts delete mode 100644 src/m365/spe/ContainerTypeProperties.ts create mode 100644 src/m365/spe/commands/container/container-list.spec.ts create mode 100644 src/m365/spe/commands/container/container-list.ts diff --git a/docs/docs/cmd/spe/container/container-list.mdx b/docs/docs/cmd/spe/container/container-list.mdx new file mode 100644 index 00000000000..247e2534228 --- /dev/null +++ b/docs/docs/cmd/spe/container/container-list.mdx @@ -0,0 +1,97 @@ +import Global from '/docs/cmd/_global.mdx'; +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# spe container list + +Lists containers of a specific Container Type + +## Usage + +```sh +m365 spe container list [options] +``` + +## Options + +```md definition-list +`--containerTypeId [containerTypeId]` +: The Container Type Id of the container instance. Use either `containerTypeId` or `containerTypeName` but not both. + +`--containerTypeName [containerTypeName]` +: The Container Type name of the container instance. Use either `containerTypeId` or `containerTypeName` but not both. +``` + + + +## Examples + +List containers of a specific type by id. + +```sh +m365 spe container list --containerTypeId "91710488-5756-407f-9046-fbe5f0b4de73" +``` + +List containers of a specific type by name. + +```sh +m365 spe container list --containerTypeName "trial container" +``` + +## Response + + + + + ```json + [ + { + "id": "b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z", + "displayName": "My File Storage Container", + "containerTypeId": "e2756c4d-fa33-4452-9c36-2325686e1082", + "createdDateTime": "2021-11-24T15:41:52.347Z" + } + ] + ``` + + + + + ```text + id displayName containerTypeId createdDateTime + ------------------------------------------------------------------ ------------------------- ------------------------------------ ------------------------ + b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z My File Storage Container e2756c4d-fa33-4452-9c36-2325686e1082 2021-11-24T15:41:52.347Z + ``` + + + + + ```csv + id,displayName,containerTypeId,createdDateTime + b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z,My File Storage Container,e2756c4d-fa33-4452-9c36-2325686e1082,2021-11-24T15:41:52.347Z + ``` + + + + + ```md + # spe container list + + Date: 10/06/2024 + + ## My File Storage Container + + Property | Value + ---------|------- + id | b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z + displayName | My File Storage Container + containerTypeId | e2756c4d-fa33-4452-9c36-2325686e1082 + createdDateTime | 2021-11-24T15:41:52.347Z + ``` + + + + +## More information + +In SharePoint Embedded, all files and documents are stored in Containers. The calling app should be the owning app of the container type. diff --git a/docs/src/config/sidebars.ts b/docs/src/config/sidebars.ts index 0e622422ac6..e4bd1351f0b 100644 --- a/docs/src/config/sidebars.ts +++ b/docs/src/config/sidebars.ts @@ -1964,6 +1964,15 @@ const sidebars: SidebarsConfig = { }, { 'SharePoint Embedded (spe)': [ + { + container: [ + { + type: 'doc', + label: 'container list', + id: 'cmd/spe/container/container-list' + } + ] + }, { containertype: [ { diff --git a/src/m365/spe/ContainerProperties.ts b/src/m365/spe/ContainerProperties.ts new file mode 100644 index 00000000000..b7738cad160 --- /dev/null +++ b/src/m365/spe/ContainerProperties.ts @@ -0,0 +1,6 @@ +export interface ContainerProperties { + id: string; + displayName: string; + containerTypeId: string; + createdDateTime: string; +} \ No newline at end of file diff --git a/src/m365/spe/ContainerTypeProperties.ts b/src/m365/spe/ContainerTypeProperties.ts deleted file mode 100644 index 5b077ef73b7..00000000000 --- a/src/m365/spe/ContainerTypeProperties.ts +++ /dev/null @@ -1,14 +0,0 @@ -export interface ContainerTypeProperties { - _ObjectType_?: string; - AzureSubscriptionId: string; - ContainerTypeId: string; - CreationDate: string; - DisplayName: string; - ExpiryDate: string; - IsBillingProfileRequired: boolean; - OwningAppId: string; - OwningTenantId: string; - Region?: string; - ResourceGroup?: string; - SPContainerTypeBillingClassification: string; -} \ No newline at end of file diff --git a/src/m365/spe/commands.ts b/src/m365/spe/commands.ts index ecd05a6e954..ed8e096ffd7 100644 --- a/src/m365/spe/commands.ts +++ b/src/m365/spe/commands.ts @@ -1,6 +1,7 @@ const prefix: string = 'spe'; export default { + CONTAINER_LIST: `${prefix} container list`, CONTAINERTYPE_ADD: `${prefix} containertype add`, CONTAINERTYPE_LIST: `${prefix} containertype list` }; \ No newline at end of file diff --git a/src/m365/spe/commands/container/container-list.spec.ts b/src/m365/spe/commands/container/container-list.spec.ts new file mode 100644 index 00000000000..a5900faf2fa --- /dev/null +++ b/src/m365/spe/commands/container/container-list.spec.ts @@ -0,0 +1,182 @@ +import assert from 'assert'; +import sinon from 'sinon'; +import auth from '../../../../Auth.js'; +import { Logger } from '../../../../cli/Logger.js'; +import request from '../../../../request.js'; +import { telemetry } from '../../../../telemetry.js'; +import { pid } from '../../../../utils/pid.js'; +import { session } from '../../../../utils/session.js'; +import { sinonUtil } from '../../../../utils/sinonUtil.js'; +import commands from '../../commands.js'; +import command from './container-list.js'; +import { spo } from '../../../../utils/spo.js'; +import { CommandError } from '../../../../Command.js'; +import { CommandInfo } from '../../../../cli/CommandInfo.js'; +import { cli } from '../../../../cli/cli.js'; + +describe(commands.CONTAINER_LIST, () => { + let log: string[]; + let logger: Logger; + let loggerLogSpy: sinon.SinonSpy; + let commandInfo: CommandInfo; + + const adminUrl = 'https://contoso-admin.sharepoint.com'; + const containersList = [{ + "id": "b!ISJs1WRro0y0EWgkUYcktDa0mE8zSlFEqFzqRn70Zwp1CEtDEBZgQICPkRbil_5Z", + "displayName": "My File Storage Container", + "containerTypeId": "e2756c4d-fa33-4452-9c36-2325686e1082", + "createdDateTime": "2021-11-24T15:41:52.347Z" + }, + { + "id": "b!NdyMBAJ1FEWHB2hEx0DND2dYRB9gz4JOl4rzl7-DuyPG3Fidzm5TTKkyZW2beare", + "displayName": "Trial Container", + "containerTypeId": "e2756c4d-fa33-4452-9c36-2325686e1082", + "createdDateTime": "2021-11-24T15:41:52.347Z" + }]; + + const containerTypedata = [{ + "AzureSubscriptionId": "/Guid(f08575e2-36c4-407f-a891-eabae23f66bc)", + "ContainerTypeId": "/Guid(e2756c4d-fa33-4452-9c36-2325686e1082)", + "CreationDate": "3/11/2024 2:38:56 PM", + "DisplayName": "standard container", + "ExpiryDate": "3/11/2028 2:38:56 PM", + "IsBillingProfileRequired": true, + "OwningAppId": "/Guid(1b3b8660-9a44-4a7c-9c02-657f3ff5d5ac)", + "OwningTenantId": "/Guid(e1dd4023-a656-480a-8a0e-c1b1eec51e1d)", + "Region": "West Europe", + "ResourceGroup": "Standard group", + "SPContainerTypeBillingClassification": "Standard" + }, + { + "AzureSubscriptionId": "/Guid(f08575e2-36c4-407f-a891-eabae23f66bc)", + "ContainerTypeId": "/Guid(e2756c4d-fa33-4452-9c36-2325686e1082)", + "CreationDate": "3/11/2024 2:38:56 PM", + "DisplayName": "trial container", + "ExpiryDate": "3/11/2028 2:38:56 PM", + "IsBillingProfileRequired": true, + "OwningAppId": "/Guid(1b3b8660-9a44-4a7c-9c02-657f3ff5d5ac)", + "OwningTenantId": "/Guid(e1dd4023-a656-480a-8a0e-c1b1eec51e1d)", + "Region": "West Europe", + "ResourceGroup": "Standard group", + "SPContainerTypeBillingClassification": "Standard" + }]; + + before(() => { + sinon.stub(auth, 'restoreAuth').resolves(); + sinon.stub(telemetry, 'trackEvent').returns(); + sinon.stub(pid, 'getProcessName').returns(''); + sinon.stub(session, 'getId').returns(''); + sinon.stub(spo, 'getSpoAdminUrl').resolves(adminUrl); + sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); + auth.connection.active = true; + auth.connection.spoUrl = 'https://contoso.sharepoint.com'; + commandInfo = cli.getCommandInfo(command); + }); + + beforeEach(() => { + log = []; + logger = { + log: async (msg: string) => { + log.push(msg); + }, + logRaw: async (msg: string) => { + log.push(msg); + }, + logToStderr: async (msg: string) => { + log.push(msg); + } + }; + loggerLogSpy = sinon.spy(logger, 'log'); + }); + + afterEach(() => { + sinonUtil.restore([ + request.get, + request.post, + spo.getSpoAdminUrl, + spo.getAllContainerTypes + ]); + }); + + after(() => { + sinon.restore(); + auth.connection.active = false; + auth.connection.spoUrl = undefined; + }); + + it('has correct name', () => { + assert.strictEqual(command.name, commands.CONTAINER_LIST); + }); + + it('has a description', () => { + assert.notStrictEqual(command.description, null); + }); + + it('defines correct properties for the default output', () => { + assert.deepStrictEqual(command.defaultProperties(), ['id', 'displayName', 'containerTypeId', 'createdDateTime']); + }); + + it('fails validation if the containerTypeId is not a valid guid', async () => { + const actual = await command.validate({ options: { containerTypeId: 'abc' } }, commandInfo); + assert.notStrictEqual(actual, true); + }); + + it('passes validation if valid containerTypeId is specified', async () => { + const actual = await command.validate({ options: { containerTypeId: "e2756c4d-fa33-4452-9c36-2325686e1082" } }, commandInfo); + assert.strictEqual(actual, true); + }); + + it('retrieves list of container type by id', async () => { + sinon.stub(request, 'get').callsFake(async (opts) => { + if (opts.url === 'https://graph.microsoft.com/v1.0/storage/fileStorage/containers?$filter=containerTypeId eq e2756c4d-fa33-4452-9c36-2325686e1082') { + return { "value": containersList }; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { options: { containerTypeId: "e2756c4d-fa33-4452-9c36-2325686e1082", debug: true } }); + assert(loggerLogSpy.calledWith(containersList)); + }); + + it('retrieves list of container type by name', async () => { + sinon.stub(spo, 'getAllContainerTypes').resolves(containerTypedata); + + sinon.stub(request, 'get').callsFake(async (opts) => { + if (opts.url === 'https://graph.microsoft.com/v1.0/storage/fileStorage/containers?$filter=containerTypeId eq e2756c4d-fa33-4452-9c36-2325686e1082') { + return { "value": containersList }; + } + + throw 'Invalid request'; + }); + + await command.action(logger, { options: { containerTypeName: "standard container", debug: true } }); + assert(loggerLogSpy.calledWith(containersList)); + }); + + it('throws an error when service principal is not found', async () => { + sinon.stub(request, 'get').callsFake(async (opts) => { + if (opts.url === 'https://graph.microsoft.com/v1.0/storage/fileStorage/containers?$filter=containerTypeId eq e2756c4d-fa33-4452-9c36-2325686e1086') { + return []; + } + + throw 'Invalid request'; + }); + + sinon.stub(spo, 'getAllContainerTypes').resolves(containerTypedata); + + await assert.rejects(command.action(logger, { options: { containerTypeName: "nonexisting container", debug: true } }), + new CommandError(`Container type with name nonexisting container not found`)); + }); + + it('correctly handles error when retrieving containers', async () => { + const error = 'An error has occurred'; + sinon.stub(spo, 'getAllContainerTypes').rejects(new Error(error)); + + await assert.rejects(command.action(logger, { + options: { + debug: true + } + }), new CommandError('An error has occurred')); + }); +}); \ No newline at end of file diff --git a/src/m365/spe/commands/container/container-list.ts b/src/m365/spe/commands/container/container-list.ts new file mode 100644 index 00000000000..1f0a5d45b1f --- /dev/null +++ b/src/m365/spe/commands/container/container-list.ts @@ -0,0 +1,113 @@ +import { Logger } from '../../../../cli/Logger.js'; +import GlobalOptions from '../../../../GlobalOptions.js'; +import { formatting } from '../../../../utils/formatting.js'; +import { odata } from '../../../../utils/odata.js'; +import { validation } from '../../../../utils/validation.js'; +import GraphCommand from '../../../base/GraphCommand.js'; +import commands from '../../commands.js'; +import { ContainerProperties } from '../../ContainerProperties.js'; +import { ContainerTypeProperties, spo } from '../../../../utils/spo.js'; + +interface CommandArgs { + options: Options; +} + +export interface Options extends GlobalOptions { + containerTypeId?: string; + containerTypeName?: string; +} + +class SpeContainerListCommand extends GraphCommand { + public get name(): string { + return commands.CONTAINER_LIST; + } + + public get description(): string { + return 'Lists all Container Types'; + } + + public defaultProperties(): string[] | undefined { + return ['id', 'displayName', 'containerTypeId', 'createdDateTime']; + } + + constructor() { + super(); + + this.#initTelemetry(); + this.#initOptions(); + this.#initValidators(); + this.#initOptionSets(); + } + + #initTelemetry(): void { + this.telemetry.push((args: CommandArgs) => { + Object.assign(this.telemetryProperties, { + containerTypeId: typeof args.options.containerTypeId !== 'undefined', + containerTypeName: typeof args.options.containerTypeName !== 'undefined' + }); + }); + } + + #initOptions(): void { + this.options.unshift( + { + option: '--containerTypeId [containerTypeId]' + }, + { + option: '--containerTypeName [containerTypeName]' + } + ); + } + + #initValidators(): void { + this.validators.push( + async (args: CommandArgs) => { + if (args.options.containerTypeId && !validation.isValidGuid(args.options.containerTypeId as string)) { + return `${args.options.containerTypeId} is not a valid GUID`; + } + + return true; + } + ); + } + + #initOptionSets(): void { + this.optionSets.push({ options: ['containerTypeId', 'containerTypeName'] }); + } + + public async commandAction(logger: Logger, args: CommandArgs): Promise { + try { + if (this.verbose) { + await logger.logToStderr(`Retrieving list of Containers...`); + } + + const containerTypeId = await this.getContainerTypeId(logger, args); + const allContainers = await odata.getAllItems(`${this.resource}/v1.0/storage/fileStorage/containers?$filter=containerTypeId eq ${formatting.encodeQueryParameter(containerTypeId)}`); + await logger.log(allContainers); + } + catch (err: any) { + this.handleRejectedPromise(err); + } + } + + private async getContainerTypeId(logger: Logger, args: CommandArgs): Promise { + if (args.options.containerTypeId) { + return args.options.containerTypeId; + } + + const spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug); + const containerTypes: ContainerTypeProperties[] = await spo.getAllContainerTypes(spoAdminUrl, logger, this.debug); + + // Get id of the container type by name + const containerType: ContainerTypeProperties | undefined = containerTypes.find(c => c.DisplayName === args.options.containerTypeName); + if (!containerType) { + throw new Error(`Container type with name ${args.options.containerTypeName} not found`); + } + + // The value is returned as "/Guid(073269af-f1d2-042d-2ef5-5bdd6ac83115)/". We need to extract the GUID from it. + const containerTypeValue = containerType.ContainerTypeId.toString(); + return containerTypeValue.substring(containerTypeValue.indexOf('(') + 1, containerTypeValue.lastIndexOf(')')); + } +} + +export default new SpeContainerListCommand(); \ No newline at end of file diff --git a/src/m365/spe/commands/containertype/containertype-list.spec.ts b/src/m365/spe/commands/containertype/containertype-list.spec.ts index 1d161c62fe7..7e8f2bbccc0 100644 --- a/src/m365/spe/commands/containertype/containertype-list.spec.ts +++ b/src/m365/spe/commands/containertype/containertype-list.spec.ts @@ -11,42 +11,37 @@ import commands from '../../commands.js'; import command from './containertype-list.js'; import { spo } from '../../../../utils/spo.js'; import { CommandError } from '../../../../Command.js'; -import config from '../../../../config.js'; + +const containerTypedata = [{ + "AzureSubscriptionId": "/Guid(f08575e2-36c4-407f-a891-eabae23f66bc)", + "ContainerTypeId": "/Guid(c33cfee5-c9b6-0a2a-02ee-060693a57f37)", + "CreationDate": "3/11/2024 2:38:56 PM", + "DisplayName": "standard container", + "ExpiryDate": "3/11/2028 2:38:56 PM", + "IsBillingProfileRequired": true, + "OwningAppId": "/Guid(1b3b8660-9a44-4a7c-9c02-657f3ff5d5ac)", + "OwningTenantId": "/Guid(e1dd4023-a656-480a-8a0e-c1b1eec51e1d)", + "Region": "West Europe", + "ResourceGroup": "Standard group", + "SPContainerTypeBillingClassification": "Standard" +}, +{ + "AzureSubscriptionId": "/Guid(f08575e2-36c4-407f-a891-eabae23f66bc)", + "ContainerTypeId": "/Guid(c33cfee5-c9b6-0a2a-02ee-060693a57f37)", + "CreationDate": "3/11/2024 2:38:56 PM", + "DisplayName": "trial container", + "ExpiryDate": "3/11/2028 2:38:56 PM", + "IsBillingProfileRequired": true, + "OwningAppId": "/Guid(1b3b8660-9a44-4a7c-9c02-657f3ff5d5ac)", + "OwningTenantId": "/Guid(e1dd4023-a656-480a-8a0e-c1b1eec51e1d)", + "Region": "West Europe", + "ResourceGroup": "Standard group", + "SPContainerTypeBillingClassification": "Standard" +}]; describe(commands.CONTAINERTYPE_LIST, () => { let log: string[]; let logger: Logger; - let loggerLogSpy: sinon.SinonSpy; - const containerTypedata = [{ - "_ObjectType_": "Microsoft.Online.SharePoint.TenantAdministration.SPContainerTypeProperties", - "ApplicationRedirectUrl": null, - "AzureSubscriptionId": "/Guid(00000000-0000-0000-0000-000000000000)/", - "ContainerTypeId": "/Guid(073269af-f1d2-042d-2ef5-5bdd6ac83115)/", - "CreationDate": null, - "DisplayName": "test1", - "ExpiryDate": null, - "IsBillingProfileRequired": true, - "OwningAppId": "/Guid(df4085cc-9a38-4255-badc-5c5225610475)/", - "OwningTenantId": "/Guid(00000000-0000-0000-0000-000000000000)/", - "Region": null, - "ResourceGroup": null, - "SPContainerTypeBillingClassification": 0 - }, - { - "_ObjectType_": "Microsoft.Online.SharePoint.TenantAdministration.SPContainerTypeProperties", - "ApplicationRedirectUrl": null, - "AzureSubscriptionId": "/Guid(00000000-0000-0000-0000-000000000000)/", - "ContainerTypeId": "/Guid(880ab3bd-5b68-01d4-3744-01a7656cf2ba)/", - "CreationDate": null, - "DisplayName": "test1", - "ExpiryDate": null, - "IsBillingProfileRequired": true, - "OwningAppId": "/Guid(50785fde-3082-47ac-a36d-06282ac5c7da)/", - "OwningTenantId": "/Guid(00000000-0000-0000-0000-000000000000)/", - "Region": null, - "ResourceGroup": null, - "SPContainerTypeBillingClassification": 0 - }]; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -71,12 +66,12 @@ describe(commands.CONTAINERTYPE_LIST, () => { log.push(msg); } }; - loggerLogSpy = sinon.spy(logger, 'log'); }); afterEach(() => { sinonUtil.restore([ - request.post + request.post, + spo.getAllContainerTypes ]); }); @@ -98,81 +93,19 @@ describe(commands.CONTAINERTYPE_LIST, () => { assert.deepStrictEqual(command.defaultProperties(), ['ContainerTypeId', 'DisplayName', 'OwningAppId']); }); - it('correctly handles random API error', async () => { - sinon.stub(request, 'post').rejects(new Error('An error has occurred')); - - await assert.rejects(command.action(logger, { options: { debug: true } } as any), new CommandError("An error has occurred")); - }); - - it('retrieves list of Container Type', async () => { - sinon.stub(request, 'post').callsFake(async (opts) => { - if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { - if (opts.headers && - opts.headers['X-RequestDigest'] && - opts.headers['X-RequestDigest'] === 'abc' && - opts.data === `1`) { - return JSON.stringify([ - { - "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.24817.12005", "ErrorInfo": null, "TraceCorrelationId": "2d63d39f-3016-0000-a532-30514e76ae73" - }, 46, { - "IsNull": false - }, 47, containerTypedata - ]); - } - } - - throw 'Invalid request'; - }); - - await command.action(logger, { options: {} }); - assert(loggerLogSpy.calledWith(containerTypedata)); - }); - - it('retrieves list of Container Type (debug)', async () => { - sinon.stub(request, 'post').callsFake(async (opts) => { - if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { - if (opts.headers && - opts.headers['X-RequestDigest'] && - opts.headers['X-RequestDigest'] === 'abc' && - opts.data === `1`) { - return JSON.stringify([ - { - "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.24817.12005", "ErrorInfo": null, "TraceCorrelationId": "2d63d39f-3016-0000-a532-30514e76ae73" - }, 46, { - "IsNull": false - }, 47, containerTypedata - ]); - } - } - - throw 'Invalid request'; - }); - + it('retrieves list of container type', async () => { + sinon.stub(spo, 'getAllContainerTypes').resolves(containerTypedata); await command.action(logger, { options: { debug: true } }); - assert(loggerLogSpy.calledWith(containerTypedata)); }); - it('correctly handles error when retrieving Container Types', async () => { - sinon.stub(request, 'post').callsFake(async (opts) => { - if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { - if (opts.headers && - opts.headers['X-RequestDigest'] && - opts.headers['X-RequestDigest'] === 'abc') { + it('correctly handles error when retrieving container types', async () => { + const error = 'An error has occurred'; + sinon.stub(spo, 'getAllContainerTypes').rejects(new Error(error)); - return JSON.stringify([ - { - "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.7324.1200", "ErrorInfo": { - "ErrorMessage": "An error has occurred.", "ErrorValue": null, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d", "ErrorCode": -1, "ErrorTypeName": "SPException" - }, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d" - } - ]); - } + await assert.rejects(command.action(logger, { + options: { + debug: true } - - throw 'Invalid request'; - }); - - await assert.rejects(command.action(logger, { options: { debug: true } } as any), - new CommandError("An error has occurred.")); + }), new CommandError('An error has occurred')); }); -}); +}); \ No newline at end of file diff --git a/src/m365/spe/commands/containertype/containertype-list.ts b/src/m365/spe/commands/containertype/containertype-list.ts index b55527b9a9e..97e0f573a20 100644 --- a/src/m365/spe/commands/containertype/containertype-list.ts +++ b/src/m365/spe/commands/containertype/containertype-list.ts @@ -1,10 +1,7 @@ import { Logger } from '../../../../cli/Logger.js'; -import config from '../../../../config.js'; -import request, { CliRequestOptions } from '../../../../request.js'; -import { ClientSvcResponse, ClientSvcResponseContents, FormDigestInfo, spo } from '../../../../utils/spo.js'; import SpoCommand from '../../../base/SpoCommand.js'; import commands from '../../commands.js'; -import { ContainerTypeProperties } from '../../ContainerTypeProperties.js'; +import { ContainerTypeProperties, spo } from '../../../../utils/spo.js'; class SpeContainertypeListCommand extends SpoCommand { @@ -28,36 +25,13 @@ class SpeContainertypeListCommand extends SpoCommand { await logger.logToStderr(`Retrieving list of Container types...`); } - const allContainerTypes = await this.getAllContainerTypes(spoAdminUrl, logger); + const allContainerTypes: ContainerTypeProperties[] = await spo.getAllContainerTypes(spoAdminUrl, logger, this.debug); await logger.log(allContainerTypes); } catch (err: any) { this.handleRejectedPromise(err); } } - - private async getAllContainerTypes(spoAdminUrl: string, logger: Logger): Promise { - const formDigestInfo: FormDigestInfo = await spo.ensureFormDigest(spoAdminUrl, logger, undefined, this.debug); - - const requestOptions: CliRequestOptions = { - url: `${spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`, - headers: { - 'X-RequestDigest': formDigestInfo.FormDigestValue - }, - data: `1` - }; - - const res: string = await request.post(requestOptions); - const json: ClientSvcResponse = JSON.parse(res); - const response: ClientSvcResponseContents = json[0]; - - if (response.ErrorInfo) { - throw response.ErrorInfo.ErrorMessage; - } - - const containerTypes: ContainerTypeProperties[] = json[json.length - 1]; - return containerTypes; - } } export default new SpeContainertypeListCommand(); \ No newline at end of file diff --git a/src/utils/spo.spec.ts b/src/utils/spo.spec.ts index 1b58e02ba2d..6fe82a612ed 100644 --- a/src/utils/spo.spec.ts +++ b/src/utils/spo.spec.ts @@ -78,6 +78,37 @@ const entraGroupResponse = { UserPrincipalName: null }; +const containerTypedata = [{ + "_ObjectType_": "Microsoft.Online.SharePoint.TenantAdministration.SPContainerTypeProperties", + "ApplicationRedirectUrl": null, + "AzureSubscriptionId": "/Guid(00000000-0000-0000-0000-000000000000)/", + "ContainerTypeId": "/Guid(073269af-f1d2-042d-2ef5-5bdd6ac83115)/", + "CreationDate": null, + "DisplayName": "test1", + "ExpiryDate": null, + "IsBillingProfileRequired": true, + "OwningAppId": "/Guid(df4085cc-9a38-4255-badc-5c5225610475)/", + "OwningTenantId": "/Guid(00000000-0000-0000-0000-000000000000)/", + "Region": null, + "ResourceGroup": null, + "SPContainerTypeBillingClassification": 0 +}, +{ + "_ObjectType_": "Microsoft.Online.SharePoint.TenantAdministration.SPContainerTypeProperties", + "ApplicationRedirectUrl": null, + "AzureSubscriptionId": "/Guid(00000000-0000-0000-0000-000000000000)/", + "ContainerTypeId": "/Guid(880ab3bd-5b68-01d4-3744-01a7656cf2ba)/", + "CreationDate": null, + "DisplayName": "test1", + "ExpiryDate": null, + "IsBillingProfileRequired": true, + "OwningAppId": "/Guid(50785fde-3082-47ac-a36d-06282ac5c7da)/", + "OwningTenantId": "/Guid(00000000-0000-0000-0000-000000000000)/", + "Region": null, + "ResourceGroup": null, + "SPContainerTypeBillingClassification": 0 +}]; + describe('utils/spo', () => { let logger: Logger; let log: string[]; @@ -2669,4 +2700,63 @@ describe('utils/spo', () => { const group = await spo.getFileById(webUrl, id, logger, true); assert.deepEqual(group, fileResponse); }); + + it('retrieves list of Container Type', async () => { + sinon.stub(spo, 'getSpoAdminUrl').resolves('https://contoso-admin.sharepoint.com'); + sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { + if (opts.headers && + opts.headers['X-RequestDigest'] && + opts.headers['X-RequestDigest'] === 'abc' && + opts.data === `1`) { + return JSON.stringify([ + { + "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.24817.12005", "ErrorInfo": null, "TraceCorrelationId": "2d63d39f-3016-0000-a532-30514e76ae73" + }, 46, { + "IsNull": false + }, 47, containerTypedata + ]); + } + } + + throw 'Invalid request'; + }); + + const containerTypeList = await spo.getAllContainerTypes('https://contoso-admin.sharepoint.com', logger, true); + assert.deepEqual(containerTypeList, containerTypedata); + }); + + it('throws error retrieving container types', async () => { + try { + sinon.stub(spo, 'getSpoAdminUrl').resolves('https://contoso-admin.sharepoint.com'); + sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { + if (opts.headers && + opts.headers['X-RequestDigest'] && + opts.headers['X-RequestDigest'] === 'abc') { + + return JSON.stringify([ + { + "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.7324.1200", "ErrorInfo": { + "ErrorMessage": "An error has occurred", "ErrorValue": null, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d", "ErrorCode": -1, "ErrorTypeName": "SPException" + }, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d" + } + ]); + } + } + + throw 'Invalid request'; + }); + + await spo.getAllContainerTypes('https://contoso-admin.sharepoint.com', logger, true); + assert.fail('An error has occurred'); + } + catch (e) { + assert.deepEqual(e, 'An error has occurred'); + } + }); }); \ No newline at end of file diff --git a/src/utils/spo.ts b/src/utils/spo.ts index acd1bf6fe54..f85574bf1b2 100644 --- a/src/utils/spo.ts +++ b/src/utils/spo.ts @@ -88,6 +88,21 @@ export interface User { UserPrincipalName: string | null; } +export interface ContainerTypeProperties { + _ObjectType_?: string; + AzureSubscriptionId: string; + ContainerTypeId: string; + CreationDate: string; + DisplayName: string; + ExpiryDate: string; + IsBillingProfileRequired: boolean; + OwningAppId: string; + OwningTenantId: string; + Region?: string; + ResourceGroup?: string; + SPContainerTypeBillingClassification: string; +} + export const spo = { async getRequestDigest(siteUrl: string): Promise { const requestOptions: CliRequestOptions = { @@ -122,6 +137,29 @@ export const spo = { return context; }, + async getAllContainerTypes(spoAdminUrl: string, logger: Logger, verbose: boolean): Promise { + const formDigestInfo: FormDigestInfo = await spo.ensureFormDigest(spoAdminUrl, logger, undefined, verbose); + + const requestOptions: CliRequestOptions = { + url: `${spoAdminUrl}/_vti_bin/client.svc/ProcessQuery`, + headers: { + 'X-RequestDigest': formDigestInfo.FormDigestValue + }, + data: `1` + }; + + const res: string = await request.post(requestOptions); + const json: ClientSvcResponse = JSON.parse(res); + const response: ClientSvcResponseContents = json[0]; + + if (response.ErrorInfo) { + throw response.ErrorInfo.ErrorMessage; + } + + const containerTypes: ContainerTypeProperties[] = json[json.length - 1]; + return containerTypes; + }, + async waitUntilFinished({ operationId, siteUrl, logger, currentContext, debug, verbose }: { operationId: string, siteUrl: string, logger: Logger, currentContext: FormDigestInfo, debug: boolean, verbose: boolean }): Promise { const resFormDigest = await spo.ensureFormDigest(siteUrl, logger, currentContext, debug); currentContext = resFormDigest; From 8212e5a652f5379034dfaa39be076b96f5024892 Mon Sep 17 00:00:00 2001 From: Nanddeep Nachan Date: Sun, 6 Oct 2024 18:09:35 +0000 Subject: [PATCH 2/5] build fix --- src/utils/spo.spec.ts | 134 +++++++++++++++++++++--------------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/src/utils/spo.spec.ts b/src/utils/spo.spec.ts index 13c24bcc48d..51157ec1ca7 100644 --- a/src/utils/spo.spec.ts +++ b/src/utils/spo.spec.ts @@ -78,6 +78,14 @@ const entraGroupResponse = { UserPrincipalName: null }; +const copyJobInfo = { + EncryptionKey: "2by8+2oizihYOFqk02Tlokj8lWUShePAEE+WMuA9lzA=", + JobId: "d812e5a0-d95a-4e4f-bcb7-d4415e88c8ee", + JobQueueUri: "https://spoam1db1m020p4.queue.core.windows.net/2-1499-20240831-29533e6c72c6464780b756c71ea3fe92?sv=2018-03-28&sig=aX%2BNOkUimZ3f%2B%2BvdXI95%2FKJI1e5UE6TU703Dw3Eb5c8%3D&st=2024-08-09T00%3A00%3A00Z&se=2024-08-31T00%3A00%3A00Z&sp=rap", + SourceListItemUniqueIds: [ + 'c194762b-3f54-4f5f-9f5c-eba26084e29d' + ] +}; const containerTypedata = [{ "_ObjectType_": "Microsoft.Online.SharePoint.TenantAdministration.SPContainerTypeProperties", @@ -110,15 +118,6 @@ const containerTypedata = [{ "SPContainerTypeBillingClassification": 0 }]; -const copyJobInfo = { - EncryptionKey: "2by8+2oizihYOFqk02Tlokj8lWUShePAEE+WMuA9lzA=", - JobId: "d812e5a0-d95a-4e4f-bcb7-d4415e88c8ee", - JobQueueUri: "https://spoam1db1m020p4.queue.core.windows.net/2-1499-20240831-29533e6c72c6464780b756c71ea3fe92?sv=2018-03-28&sig=aX%2BNOkUimZ3f%2B%2BvdXI95%2FKJI1e5UE6TU703Dw3Eb5c8%3D&st=2024-08-09T00%3A00%3A00Z&se=2024-08-31T00%3A00%3A00Z&sp=rap", - SourceListItemUniqueIds: [ - 'c194762b-3f54-4f5f-9f5c-eba26084e29d' - ] -}; - describe('utils/spo', () => { let logger: Logger; let log: string[]; @@ -2712,64 +2711,6 @@ describe('utils/spo', () => { assert.deepEqual(group, fileResponse); }); - it('retrieves list of Container Type', async () => { - sinon.stub(spo, 'getSpoAdminUrl').resolves('https://contoso-admin.sharepoint.com'); - sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); - - sinon.stub(request, 'post').callsFake(async (opts) => { - if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { - if (opts.headers && - opts.headers['X-RequestDigest'] && - opts.headers['X-RequestDigest'] === 'abc' && - opts.data === `1`) { - return JSON.stringify([ - { - "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.24817.12005", "ErrorInfo": null, "TraceCorrelationId": "2d63d39f-3016-0000-a532-30514e76ae73" - }, 46, { - "IsNull": false - }, 47, containerTypedata - ]); - } - } - - throw 'Invalid request'; - }); - - const containerTypeList = await spo.getAllContainerTypes('https://contoso-admin.sharepoint.com', logger, true); - assert.deepEqual(containerTypeList, containerTypedata); - }); - - it('throws error retrieving container types', async () => { - try { - sinon.stub(spo, 'getSpoAdminUrl').resolves('https://contoso-admin.sharepoint.com'); - sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); - - sinon.stub(request, 'post').callsFake(async (opts) => { - if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { - if (opts.headers && - opts.headers['X-RequestDigest'] && - opts.headers['X-RequestDigest'] === 'abc') { - - return JSON.stringify([ - { - "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.7324.1200", "ErrorInfo": { - "ErrorMessage": "An error has occurred", "ErrorValue": null, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d", "ErrorCode": -1, "ErrorTypeName": "SPException" - }, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d" - } - ]); - } - } - - throw 'Invalid request'; - }); - - await spo.getAllContainerTypes('https://contoso-admin.sharepoint.com', logger, true); - assert.fail('An error has occurred'); - } - catch (e) { - assert.deepEqual(e, 'An error has occurred'); - } - it('correctly outputs result when calling createCopyJob', async () => { sinon.stub(request, 'post').callsFake(async (opts) => { if (opts.url === 'https://contoso.sharepoint.com/sites/sales/_api/Site/CreateCopyJobs') { @@ -3088,4 +3029,63 @@ describe('utils/spo', () => { await assert.rejects(spo.getCopyJobResult('https://contoso.sharepoint.com/sites/sales', copyJobInfo), new Error('A file or folder with the name Company.png already exists at the destination.')); }); + + it('retrieves list of Container Type', async () => { + sinon.stub(spo, 'getSpoAdminUrl').resolves('https://contoso-admin.sharepoint.com'); + sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { + if (opts.headers && + opts.headers['X-RequestDigest'] && + opts.headers['X-RequestDigest'] === 'abc' && + opts.data === `1`) { + return JSON.stringify([ + { + "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.24817.12005", "ErrorInfo": null, "TraceCorrelationId": "2d63d39f-3016-0000-a532-30514e76ae73" + }, 46, { + "IsNull": false + }, 47, containerTypedata + ]); + } + } + + throw 'Invalid request'; + }); + + const containerTypeList = await spo.getAllContainerTypes('https://contoso-admin.sharepoint.com', logger, true); + assert.deepEqual(containerTypeList, containerTypedata); + }); + + it('throws error retrieving container types', async () => { + try { + sinon.stub(spo, 'getSpoAdminUrl').resolves('https://contoso-admin.sharepoint.com'); + sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { + if (opts.headers && + opts.headers['X-RequestDigest'] && + opts.headers['X-RequestDigest'] === 'abc') { + + return JSON.stringify([ + { + "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.7324.1200", "ErrorInfo": { + "ErrorMessage": "An error has occurred", "ErrorValue": null, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d", "ErrorCode": -1, "ErrorTypeName": "SPException" + }, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d" + } + ]); + } + } + + throw 'Invalid request'; + }); + + await spo.getAllContainerTypes('https://contoso-admin.sharepoint.com', logger, true); + assert.fail('An error has occurred'); + } + catch (e) { + assert.deepEqual(e, 'An error has occurred'); + } + }); }); \ No newline at end of file From 0d15a32aa62e4f031ff3f0f7031f7da2932e4c22 Mon Sep 17 00:00:00 2001 From: Nanddeep Nachan Date: Thu, 24 Oct 2024 16:34:44 +0000 Subject: [PATCH 3/5] review comments --- .../spe/commands/container/container-list.ts | 17 +++++++++++------ .../containertype/containertype-list.spec.ts | 3 +++ src/utils/spo.ts | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/m365/spe/commands/container/container-list.ts b/src/m365/spe/commands/container/container-list.ts index 1f0a5d45b1f..3149436ab36 100644 --- a/src/m365/spe/commands/container/container-list.ts +++ b/src/m365/spe/commands/container/container-list.ts @@ -37,6 +37,7 @@ class SpeContainerListCommand extends GraphCommand { this.#initOptions(); this.#initValidators(); this.#initOptionSets(); + this.#initTypes(); } #initTelemetry(): void { @@ -75,13 +76,17 @@ class SpeContainerListCommand extends GraphCommand { this.optionSets.push({ options: ['containerTypeId', 'containerTypeName'] }); } + #initTypes(): void { + this.types.string.push('containerTypeId', 'containerTypeName'); + } + public async commandAction(logger: Logger, args: CommandArgs): Promise { try { if (this.verbose) { await logger.logToStderr(`Retrieving list of Containers...`); } - const containerTypeId = await this.getContainerTypeId(logger, args); + const containerTypeId = await this.getContainerTypeId(logger, args.options); const allContainers = await odata.getAllItems(`${this.resource}/v1.0/storage/fileStorage/containers?$filter=containerTypeId eq ${formatting.encodeQueryParameter(containerTypeId)}`); await logger.log(allContainers); } @@ -90,18 +95,18 @@ class SpeContainerListCommand extends GraphCommand { } } - private async getContainerTypeId(logger: Logger, args: CommandArgs): Promise { - if (args.options.containerTypeId) { - return args.options.containerTypeId; + private async getContainerTypeId(logger: Logger, options: Options): Promise { + if (options.containerTypeId) { + return options.containerTypeId; } const spoAdminUrl = await spo.getSpoAdminUrl(logger, this.debug); const containerTypes: ContainerTypeProperties[] = await spo.getAllContainerTypes(spoAdminUrl, logger, this.debug); // Get id of the container type by name - const containerType: ContainerTypeProperties | undefined = containerTypes.find(c => c.DisplayName === args.options.containerTypeName); + const containerType: ContainerTypeProperties | undefined = containerTypes.find(c => c.DisplayName === options.containerTypeName); if (!containerType) { - throw new Error(`Container type with name ${args.options.containerTypeName} not found`); + throw new Error(`Container type with name ${options.containerTypeName} not found`); } // The value is returned as "/Guid(073269af-f1d2-042d-2ef5-5bdd6ac83115)/". We need to extract the GUID from it. diff --git a/src/m365/spe/commands/containertype/containertype-list.spec.ts b/src/m365/spe/commands/containertype/containertype-list.spec.ts index 7e8f2bbccc0..cb21ddc29ed 100644 --- a/src/m365/spe/commands/containertype/containertype-list.spec.ts +++ b/src/m365/spe/commands/containertype/containertype-list.spec.ts @@ -42,6 +42,7 @@ const containerTypedata = [{ describe(commands.CONTAINERTYPE_LIST, () => { let log: string[]; let logger: Logger; + let loggerLogSpy: sinon.SinonSpy; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -66,6 +67,7 @@ describe(commands.CONTAINERTYPE_LIST, () => { log.push(msg); } }; + loggerLogSpy = sinon.spy(logger, 'log'); }); afterEach(() => { @@ -96,6 +98,7 @@ describe(commands.CONTAINERTYPE_LIST, () => { it('retrieves list of container type', async () => { sinon.stub(spo, 'getAllContainerTypes').resolves(containerTypedata); await command.action(logger, { options: { debug: true } }); + assert(loggerLogSpy.calledWith(containerTypedata)); }); it('correctly handles error when retrieving container types', async () => { diff --git a/src/utils/spo.ts b/src/utils/spo.ts index 72989f4f541..e08e03eff19 100644 --- a/src/utils/spo.ts +++ b/src/utils/spo.ts @@ -955,7 +955,7 @@ export const spo = { const response: ClientSvcResponseContents = json[0]; if (response.ErrorInfo) { - throw response.ErrorInfo.ErrorMessage; + throw new Error(response.ErrorInfo.ErrorMessage); } else { const operation: SpoOperation = json[json.length - 1]; From ada492e558f9b309e0fe2f180b99924838e35512 Mon Sep 17 00:00:00 2001 From: Nanddeep Nachan Date: Thu, 24 Oct 2024 16:46:59 +0000 Subject: [PATCH 4/5] test fix --- src/utils/spo.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils/spo.ts b/src/utils/spo.ts index fd006c09fef..e0d7637d2cd 100644 --- a/src/utils/spo.ts +++ b/src/utils/spo.ts @@ -324,7 +324,7 @@ export const spo = { const response: ClientSvcResponseContents = json[0]; if (response.ErrorInfo) { - throw response.ErrorInfo.ErrorMessage; + throw new Error(response.ErrorInfo.ErrorMessage); } const containerTypes: ContainerTypeProperties[] = json[json.length - 1]; @@ -1082,7 +1082,7 @@ export const spo = { const response: ClientSvcResponseContents = json[0]; if (response.ErrorInfo) { - throw new Error(response.ErrorInfo.ErrorMessage); + throw response.ErrorInfo.ErrorMessage; } else { const operation: SpoOperation = json[json.length - 1]; From 923f8be8391210ec840d2f041a96c16cd438ba39 Mon Sep 17 00:00:00 2001 From: Nanddeep Nachan Date: Thu, 24 Oct 2024 17:55:23 +0000 Subject: [PATCH 5/5] test fix --- src/utils/spo.spec.ts | 50 +++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/utils/spo.spec.ts b/src/utils/spo.spec.ts index 4c86ca930e1..adbf41a71d0 100644 --- a/src/utils/spo.spec.ts +++ b/src/utils/spo.spec.ts @@ -3186,7 +3186,7 @@ describe('utils/spo', () => { await spo.getSiteAdminPropertiesByUrl('https://contoso.sharepoint.com/sites/sales', true, logger, true); assert.deepStrictEqual(postStub.firstCall.args[0].data, { url: 'https://contoso.sharepoint.com/sites/sales', includeDetail: true }); }); - + it('retrieves list of Container Type', async () => { sinon.stub(spo, 'getSpoAdminUrl').resolves('https://contoso-admin.sharepoint.com'); sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); @@ -3214,35 +3214,29 @@ describe('utils/spo', () => { assert.deepEqual(containerTypeList, containerTypedata); }); - it('throws error retrieving container types', async () => { - try { - sinon.stub(spo, 'getSpoAdminUrl').resolves('https://contoso-admin.sharepoint.com'); - sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); - - sinon.stub(request, 'post').callsFake(async (opts) => { - if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { - if (opts.headers && - opts.headers['X-RequestDigest'] && - opts.headers['X-RequestDigest'] === 'abc') { - - return JSON.stringify([ - { - "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.7324.1200", "ErrorInfo": { - "ErrorMessage": "An error has occurred", "ErrorValue": null, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d", "ErrorCode": -1, "ErrorTypeName": "SPException" - }, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d" - } - ]); - } + it('correctly throws error when retrieving container types', async () => { + sinon.stub(spo, 'getSpoAdminUrl').resolves('https://contoso-admin.sharepoint.com'); + sinon.stub(spo, 'ensureFormDigest').resolves({ FormDigestValue: 'abc', FormDigestTimeoutSeconds: 1800, FormDigestExpiresAt: new Date(), WebFullUrl: 'https://contoso.sharepoint.com' }); + + sinon.stub(request, 'post').callsFake(async (opts) => { + if ((opts.url as string).indexOf(`/_vti_bin/client.svc/ProcessQuery`) > -1) { + if (opts.headers && + opts.headers['X-RequestDigest'] && + opts.headers['X-RequestDigest'] === 'abc') { + + return JSON.stringify([ + { + "SchemaVersion": "15.0.0.0", "LibraryVersion": "16.0.7324.1200", "ErrorInfo": { + "ErrorMessage": "An error has occurred", "ErrorValue": null, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d", "ErrorCode": -1, "ErrorTypeName": "SPException" + }, "TraceCorrelationId": "e13c489e-2026-5000-8242-7ec96d02ba1d" + } + ]); } + } - throw 'Invalid request'; - }); + throw 'Invalid request'; + }); - await spo.getAllContainerTypes('https://contoso-admin.sharepoint.com', logger, true); - assert.fail('An error has occurred'); - } - catch (e) { - assert.deepEqual(e, 'An error has occurred'); - } + await assert.rejects(spo.getAllContainerTypes('https://contoso-admin.sharepoint.com', logger, true), 'An error occured'); }); }); \ No newline at end of file