From e361f03e7e1aeb37bbaf7a3653a58e29d05a45c0 Mon Sep 17 00:00:00 2001 From: Raffaele Preziosi Date: Sun, 28 Jan 2024 19:47:51 +0100 Subject: [PATCH] fix: test class --- src/PermissionSetUpdater.ts | 8 +- src/commands/perms/field/new.ts | 64 +++++++---- test/commands/perms/field/new.nut.ts | 21 ---- test/commands/perms/field/new.test.ts | 102 +++++++++++++----- .../fields/AddressString__c.field-meta.xml | 0 .../Account/fields/Address__c.field-meta.xml | 0 .../Account/fields/Name.field-meta.xml | 0 .../FirstPermissionSet.permissionset-meta.xml | 6 ++ 8 files changed, 134 insertions(+), 67 deletions(-) delete mode 100644 test/commands/perms/field/new.nut.ts create mode 100644 test/force-app/main/default/objects/Account/fields/AddressString__c.field-meta.xml create mode 100644 test/force-app/main/default/objects/Account/fields/Address__c.field-meta.xml create mode 100644 test/force-app/main/default/objects/Account/fields/Name.field-meta.xml create mode 100644 test/force-app/main/default/permissionsets/FirstPermissionSet.permissionset-meta.xml diff --git a/src/PermissionSetUpdater.ts b/src/PermissionSetUpdater.ts index 699e1b9..a573ca6 100644 --- a/src/PermissionSetUpdater.ts +++ b/src/PermissionSetUpdater.ts @@ -1,4 +1,5 @@ /* eslint-disable class-methods-use-this */ +import path from 'node:path'; import { promises as fsPromises } from 'node:fs'; import { XMLParser, XMLBuilder } from 'fast-xml-parser'; @@ -27,13 +28,14 @@ export class PermissionSetUpdater { } public async updatePermissionSet( + directoryPath: string, permissionSet: string, fieldsPermissionSelected: { [key: string]: string }, objectSelected: string ): Promise { - const completeFilePath = `./force-app/main/default/permissionsets/${permissionSet}`; - const permissionSetXml = await this.fs.readFile(completeFilePath, 'utf8'); - const permissionSetParsedJSON = this.parser.parse(permissionSetXml) as PermissionSet; + const completeFilePath: string = path.resolve(directoryPath, 'permissionsets', permissionSet); + const permissionSetXml: string = await this.fs.readFile(completeFilePath, 'utf8'); + const permissionSetParsedJSON: PermissionSet = this.parser.parse(permissionSetXml) as PermissionSet; for (const field in fieldsPermissionSelected) { if (Object.prototype.hasOwnProperty.call(fieldsPermissionSelected, field)) { diff --git a/src/commands/perms/field/new.ts b/src/commands/perms/field/new.ts index 77cc440..7f49be0 100644 --- a/src/commands/perms/field/new.ts +++ b/src/commands/perms/field/new.ts @@ -1,5 +1,5 @@ /* eslint-disable class-methods-use-this */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +import path from 'node:path'; import { promises as fsPromises } from 'node:fs'; import { SfCommand } from '@salesforce/sf-plugins-core'; import { Messages } from '@salesforce/core'; @@ -10,7 +10,7 @@ Messages.importMessagesDirectoryFromMetaUrl(import.meta.url); const messages = Messages.loadMessages('sf-perms', 'perms.field.new'); export type PermsFieldNewResult = { - isSucces: boolean; + isSuccess: boolean; errorMessage?: string; }; @@ -18,36 +18,59 @@ export default class PermsFieldNew extends SfCommand { public static readonly summary = messages.getMessage('summary'); public static readonly description = messages.getMessage('description'); public static readonly examples = messages.getMessages('examples'); - public static readonly flags = {}; - // eslint-disable-next-line class-methods-use-this + public static fs = fsPromises; + public static prompts = prompts; + public async run(): Promise { const result: PermsFieldNewResult = { - isSucces: true, + isSuccess: true, }; + const directoryPath: string = path.resolve(process.cwd(), 'test', 'force-app', 'main', 'default'); + try { - const { permissionSetsSelected, objectSelected } = await this.selectPermissionSetsAndObject(); - const selectedFields = await this.selectFields(objectSelected); + await this.checkDirectory(directoryPath); + const { permissionSetsSelected, objectSelected } = await this.selectPermissionSetsAndObject(directoryPath); + const selectedFields = await this.selectFields(objectSelected, directoryPath); const fieldsPermissionSelected = await this.selectFieldsPermissions(selectedFields); - const permissionSetUpdater = new PermissionSetUpdater(fsPromises); + const permissionSetUpdater = new PermissionSetUpdater(PermsFieldNew.fs); await Promise.all( permissionSetsSelected.map((permissionSet) => - permissionSetUpdater.updatePermissionSet(permissionSet, fieldsPermissionSelected, objectSelected) + permissionSetUpdater.updatePermissionSet( + directoryPath, + permissionSet, + fieldsPermissionSelected, + objectSelected + ) ) ); this.log(`Permission Sets ${permissionSetsSelected.join(', ')} updated successfully!`); } catch (err) { - result.isSucces = false; + result.isSuccess = false; result.errorMessage = (err as Error).message; } return result; } - private async selectFields(objectSelected: string): Promise { - const fields: string[] = await fsPromises.readdir(`./force-app/main/default/objects/${objectSelected}/fields`); + private async checkDirectory(directoryPath: string): Promise { + try { + await PermsFieldNew.fs.access(directoryPath); + } catch (err) { + throw new Error(`Directory ${directoryPath} not found`); + } + const files = await PermsFieldNew.fs.readdir(directoryPath); + if (files.length === 0) { + throw new Error(`Directory ${directoryPath} is empty`); + } + } + + private async selectFields(objectSelected: string, directoryPath: string): Promise { + const pathToFields: string = path.resolve(directoryPath, 'objects', objectSelected, 'fields'); + await this.checkDirectory(pathToFields); + const fields: string[] = await PermsFieldNew.fs.readdir(pathToFields); const fieldChoises: prompts.Choice[] = fields.map((file) => ({ title: file.split('.')[0], @@ -55,7 +78,7 @@ export default class PermsFieldNew extends SfCommand { })); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unused-vars - const selectedFields = await prompts({ + const selectedFields = await PermsFieldNew.prompts({ type: 'multiselect', name: 'Fields', message: 'Select Fields', @@ -67,13 +90,18 @@ export default class PermsFieldNew extends SfCommand { return selectedFields.Fields; } - private async selectPermissionSetsAndObject(): Promise<{ + private async selectPermissionSetsAndObject(directoryPath: string): Promise<{ permissionSetsSelected: string[]; objectSelected: string; }> { + const pathToPermissionSets: string = path.resolve(directoryPath, 'permissionsets'); + await this.checkDirectory(pathToPermissionSets); + const pathToObjects: string = path.resolve(directoryPath, 'objects'); + await this.checkDirectory(pathToObjects); + const [permissionsets, objects]: [string[], string[]] = await Promise.all([ - fsPromises.readdir('./force-app/main/default/permissionsets'), - fsPromises.readdir('./force-app/main/default/objects'), + PermsFieldNew.fs.readdir(pathToPermissionSets), + PermsFieldNew.fs.readdir(pathToObjects), ]); const permissionSetChoises: prompts.Choice[] = permissionsets.map((file) => ({ @@ -87,7 +115,7 @@ export default class PermsFieldNew extends SfCommand { })); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unused-vars - const { permissionSetsSelected, objectSelected } = await prompts([ + const { permissionSetsSelected, objectSelected } = await PermsFieldNew.prompts([ { type: 'multiselect', name: 'permissionSetsSelected', @@ -131,7 +159,7 @@ export default class PermsFieldNew extends SfCommand { })); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call - const fieldsPermissionSelected = await prompts(fieldsPermissionPrompts); + const fieldsPermissionSelected = await PermsFieldNew.prompts(fieldsPermissionPrompts); // eslint-disable-next-line @typescript-eslint/no-unsafe-return return fieldsPermissionSelected; diff --git a/test/commands/perms/field/new.nut.ts b/test/commands/perms/field/new.nut.ts deleted file mode 100644 index 67e9de6..0000000 --- a/test/commands/perms/field/new.nut.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { execCmd, TestSession } from '@salesforce/cli-plugins-testkit'; -import { expect } from 'chai'; - -describe('perms field new NUTs', () => { - let session: TestSession; - - before(async () => { - session = await TestSession.create({ devhubAuthStrategy: 'NONE' }); - }); - - after(async () => { - await session?.clean(); - }); - - it('should display provided name', () => { - const name = 'World'; - const command = `perms field new --name ${name}`; - const output = execCmd(command, { ensureExitCode: 0 }).shellOutput.stdout; - expect(output).to.contain(name); - }); -}); diff --git a/test/commands/perms/field/new.test.ts b/test/commands/perms/field/new.test.ts index 62fbddf..273812c 100644 --- a/test/commands/perms/field/new.test.ts +++ b/test/commands/perms/field/new.test.ts @@ -1,40 +1,92 @@ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +import fs from 'node:fs'; +import path from 'node:path'; +import { XMLParser } from 'fast-xml-parser'; import { TestContext } from '@salesforce/core/lib/testSetup.js'; import { expect } from 'chai'; -import { stubSfCommandUx } from '@salesforce/sf-plugins-core'; -import PermsFieldNew from '../../../../src/commands/perms/field/new.js'; +import PermsFieldNew, { PermsFieldNewResult } from '../../../../src/commands/perms/field/new.js'; + +const pathToPermissionSet = path.resolve('', 'test', 'force-app', 'main', 'default', 'permissionsets'); describe('perms field new', () => { const $$ = new TestContext(); - let sfCommandStubs: ReturnType; beforeEach(() => { - sfCommandStubs = stubSfCommandUx($$.SANDBOX); + fs.copyFileSync( + path.resolve(pathToPermissionSet, 'FirstPermissionSet.permissionset-meta.xml'), + path.resolve(pathToPermissionSet, 'FirstPermissionSetBackup.permissionset-meta.xml') + ); }); afterEach(() => { $$.restore(); + fs.copyFileSync( + path.resolve(pathToPermissionSet, 'FirstPermissionSetBackup.permissionset-meta.xml'), + path.resolve(pathToPermissionSet, 'FirstPermissionSet.permissionset-meta.xml') + ); + fs.unlinkSync(path.resolve(pathToPermissionSet, 'FirstPermissionSetBackup.permissionset-meta.xml')); }); - it('runs hello', async () => { - await PermsFieldNew.run([]); - const output = sfCommandStubs.log - .getCalls() - .flatMap((c) => c.args) - .join('\n'); - expect(output).to.include('hello world'); - }); - - it('runs hello with --json and no provided name', async () => { - const result = await PermsFieldNew.run([]); - expect(result.path).to.equal('/Users/raffaele.preziosi/VsCode/sf-perms/src/commands/perms/field/new.ts'); - }); - - it('runs hello world --name Astro', async () => { - await PermsFieldNew.run(['--name', 'Astro']); - const output = sfCommandStubs.log - .getCalls() - .flatMap((c) => c.args) - .join('\n'); - expect(output).to.include('hello Astro'); + it('add new field permission', async () => { + let callCount = 0; + $$.SANDBOX.stub(PermsFieldNew, 'prompts').callsFake(() => { + callCount++; + switch (callCount) { + case 1: + return Promise.resolve({ + permissionSetsSelected: ['FirstPermissionSet.permissionset-meta.xml'], + objectSelected: 'Account', + }); + case 2: + return Promise.resolve({ + Fields: ['Address__c', 'AddressString__c'], + }); + case 3: + return Promise.resolve({ + // eslint-disable-next-line camelcase + Address__c: 'read', + // eslint-disable-next-line camelcase + AddressString__c: 'read_edit', + }); + default: + return Promise.resolve({}); + } + }); + const result: PermsFieldNewResult = await PermsFieldNew.run([]); + expect(result).to.have.property('isSuccess', true); + // check field permissions are added in the file + const permissionSetXml = fs.readFileSync( + path.resolve(pathToPermissionSet, 'FirstPermissionSet.permissionset-meta.xml'), + 'utf8' + ); + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const permissionSetParsedJSON = new XMLParser({ ignoreAttributes: false }).parse(permissionSetXml); + expect(permissionSetParsedJSON).to.have.property('PermissionSet'); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(permissionSetParsedJSON.PermissionSet).to.have.property('fieldPermissions'); + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access + expect(permissionSetParsedJSON.PermissionSet.fieldPermissions).to.be.an('array'); + expect(permissionSetParsedJSON.PermissionSet.fieldPermissions).to.have.lengthOf(2); + expect( + permissionSetParsedJSON.PermissionSet.fieldPermissions.find( + (fp: { field: string }) => fp.field === 'Account.Address__c' + ) + ).to.have.property('editable', false); + expect( + permissionSetParsedJSON.PermissionSet.fieldPermissions.find( + (fp: { field: string }) => fp.field === 'Account.Address__c' + ) + ).to.have.property('readable', true); + expect( + permissionSetParsedJSON.PermissionSet.fieldPermissions.find( + (fp: { field: string }) => fp.field === 'Account.AddressString__c' + ) + ).to.have.property('editable', true); + expect( + permissionSetParsedJSON.PermissionSet.fieldPermissions.find( + (fp: { field: string }) => fp.field === 'Account.AddressString__c' + ) + ).to.have.property('readable', true); }); }); diff --git a/test/force-app/main/default/objects/Account/fields/AddressString__c.field-meta.xml b/test/force-app/main/default/objects/Account/fields/AddressString__c.field-meta.xml new file mode 100644 index 0000000..e69de29 diff --git a/test/force-app/main/default/objects/Account/fields/Address__c.field-meta.xml b/test/force-app/main/default/objects/Account/fields/Address__c.field-meta.xml new file mode 100644 index 0000000..e69de29 diff --git a/test/force-app/main/default/objects/Account/fields/Name.field-meta.xml b/test/force-app/main/default/objects/Account/fields/Name.field-meta.xml new file mode 100644 index 0000000..e69de29 diff --git a/test/force-app/main/default/permissionsets/FirstPermissionSet.permissionset-meta.xml b/test/force-app/main/default/permissionsets/FirstPermissionSet.permissionset-meta.xml new file mode 100644 index 0000000..7c9d639 --- /dev/null +++ b/test/force-app/main/default/permissionsets/FirstPermissionSet.permissionset-meta.xml @@ -0,0 +1,6 @@ + + + + false + + \ No newline at end of file