diff --git a/src/m365/entra/commands/multitenant/multitenant-add.spec.ts b/src/m365/entra/commands/multitenant/multitenant-add.spec.ts index 44d609c2bc6..336cd714504 100644 --- a/src/m365/entra/commands/multitenant/multitenant-add.spec.ts +++ b/src/m365/entra/commands/multitenant/multitenant-add.spec.ts @@ -1,5 +1,6 @@ import assert from 'assert'; import sinon from 'sinon'; +import { z } from 'zod'; import auth from '../../../../Auth.js'; import { cli } from '../../../../cli/cli.js'; import { CommandInfo } from '../../../../cli/CommandInfo.js'; @@ -33,6 +34,7 @@ describe(commands.MULTITENANT_ADD, () => { let logger: Logger; let loggerLogSpy: sinon.SinonSpy; let commandInfo: CommandInfo; + let commandOptionsSchema: z.ZodTypeAny; before(() => { sinon.stub(auth, 'restoreAuth').resolves(); @@ -41,6 +43,7 @@ describe(commands.MULTITENANT_ADD, () => { sinon.stub(session, 'getId').returns(''); auth.connection.active = true; commandInfo = cli.getCommandInfo(command); + commandOptionsSchema = commandInfo.command.getSchemaToParse()!; }); beforeEach(() => { @@ -80,13 +83,13 @@ describe(commands.MULTITENANT_ADD, () => { }); it('passes validation when only displayName is specified', async () => { - const actual = await command.validate({ options: { displayName: 'Contoso organization' } }, commandInfo); - assert.strictEqual(actual, true); + const parseResult = commandOptionsSchema.safeParse({ displayName: 'Contoso organization' }); + assert.strictEqual(parseResult.success, true); }); it('passes validation when the displayName and description are specified', async () => { - const actual = await command.validate({ options: { displayName: 'Contoso organization', description: 'Contoso and partners' } }, commandInfo); - assert.strictEqual(actual, true); + const parseResult = commandOptionsSchema.safeParse({ displayName: 'Contoso organization', description: 'Contoso and partners' }); + assert.strictEqual(parseResult.success, true); }); it('creates a multitenant organization with a displayName only', async () => { @@ -98,7 +101,7 @@ describe(commands.MULTITENANT_ADD, () => { throw 'Invalid request'; }); - await command.action(logger, { options: { displayName: 'Contoso organization', verbose: true } }); + await command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Contoso organization', verbose: true }) }); assert(loggerLogSpy.calledOnceWithExactly(multitenantOrganizationShortReponse)); }); @@ -111,7 +114,7 @@ describe(commands.MULTITENANT_ADD, () => { throw 'Invalid request'; }); - await command.action(logger, { options: { displayName: 'Contoso organization', description: 'Contoso and partners' } }); + await command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Contoso organization', description: 'Contoso and partners' }) }); assert(loggerLogSpy.calledOnceWithExactly(multitenantOrganizationReponse)); }); @@ -127,7 +130,7 @@ describe(commands.MULTITENANT_ADD, () => { } }); - await assert.rejects(command.action(logger, { options: {} } as any), new CommandError('Invalid request')); + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Contoso organization' }) }), new CommandError('Invalid request')); }); it('correctly handles API OData error when the multitenant organization already exist', async () => { @@ -143,6 +146,6 @@ describe(commands.MULTITENANT_ADD, () => { } }); - await assert.rejects(command.action(logger, { options: {} } as any), new CommandError('Method not supported for update operation.')); + await assert.rejects(command.action(logger, { options: commandOptionsSchema.parse({ displayName: 'Contoso organization' }) }), new CommandError('Method not supported for update operation.')); }); }); \ No newline at end of file diff --git a/src/m365/entra/commands/multitenant/multitenant-add.ts b/src/m365/entra/commands/multitenant/multitenant-add.ts index a5155eb7e4a..1823f88478c 100644 --- a/src/m365/entra/commands/multitenant/multitenant-add.ts +++ b/src/m365/entra/commands/multitenant/multitenant-add.ts @@ -1,19 +1,23 @@ -import GlobalOptions from '../../../../GlobalOptions.js'; +import { z } from 'zod'; +import { globalOptionsZod } from '../../../../Command.js'; import { Logger } from '../../../../cli/Logger.js'; import request, { CliRequestOptions } from '../../../../request.js'; import GraphCommand from '../../../base/GraphCommand.js'; import commands from '../../commands.js'; import { MultitenantOrganization } from './MultitenantOrganization.js'; +import { zod } from '../../../../utils/zod.js'; + +const options = globalOptionsZod + .extend({ + displayName: zod.alias('n', z.string()), + description: zod.alias('d', z.string().optional()) + }).strict(); +declare type Options = z.infer; interface CommandArgs { options: Options; } -interface Options extends GlobalOptions { - displayName: string; - description?: string; -} - class EntraMultitenantAddCommand extends GraphCommand { public get name(): string { return commands.MULTITENANT_ADD; @@ -23,36 +27,8 @@ class EntraMultitenantAddCommand extends GraphCommand { return 'Creates a new multitenant organization'; } - constructor() { - super(); - - this.#initTelemetry(); - this.#initOptions(); - this.#initTypes(); - } - - #initTelemetry(): void { - this.telemetry.push((args: CommandArgs) => { - Object.assign(this.telemetryProperties, { - displayName: typeof args.options.displayName !== 'undefined', - description: typeof args.options.description !== 'undefined' - }); - }); - } - - #initOptions(): void { - this.options.unshift( - { - option: '-n, --displayName ' - }, - { - option: '-d, --description [description]' - } - ); - } - - #initTypes(): void { - this.types.string.push('displayName', 'description'); + public get schema(): z.ZodTypeAny | undefined { + return options; } public async commandAction(logger: Logger, args: CommandArgs): Promise {