Browse Source

tests ok for abilityUtils (3 methods left, too complicated for now)

Olivier Massot 2 years ago
parent
commit
c4eac71d18
2 changed files with 576 additions and 12 deletions
  1. 2 2
      services/rights/abilityBuilder.ts
  2. 574 10
      tests/units/services/rights/abilityBuilder.test.ts

+ 2 - 2
services/rights/abilityBuilder.ts

@@ -109,7 +109,7 @@ class AbilityBuilder {
         accessHasAllRoleAbilities: (parameters: any) => this.hasAllRoleAbilities(parameters),
         accessHasAnyRoleAbility: (parameters: any) => this.hasAnyRoleAbility(parameters),
         accessHasAnyProfile: (parameters: any) => parameters === null || this.hasAnyProfile(parameters),
-        accessHasAllModules: (parameters: any) => this.hasAllModules(parameters),
+        organizationHasAllModules: (parameters: any) => this.hasAllModules(parameters),
         organizationHasAnyModule: (parameters: any) => this.hasAnyModule(parameters),
         accessIsAdminAccount: (parameters: any) => this.accessProfile.isAdminAccount,
         organizationIsSchool: (parameters: any) => this.organizationProfile.isSchool,
@@ -129,7 +129,7 @@ class AbilityBuilder {
      * @param subject  For debugging purpose only
      * @private
      */
-    private execAndValidateCondition(
+    protected execAndValidateCondition(
         condition: Condition,
         subject: string = ''
     ) {

+ 574 - 10
tests/units/services/rights/abilityBuilder.test.ts

@@ -1,33 +1,597 @@
 import { describe, test, it, expect } from 'vitest'
 import {MongoAbility} from "@casl/ability/dist/types/Ability";
-import {AbilitiesType, AccessProfile, organizationState} from "~/types/interfaces";
+import {AccessProfile, organizationState} from "~/types/interfaces";
 import AbilityBuilder from "~/services/rights/abilityBuilder";
+import {ABILITIES} from "~/types/enum/enums";
 
 let ability: MongoAbility
 let accessProfile: AccessProfile
 let organizationProfile: organizationState
-let abilityBuilder: AbilityBuilder
+let abilityBuilder: TestableAbilityBuilder
+
+class TestableAbilityBuilder extends AbilityBuilder {
+    public execAndValidateCondition(condition: any, subject: string = '') { return super.execAndValidateCondition(condition, subject) }
+}
+
 
 beforeEach(() => {
     ability = vi.fn() as any as MongoAbility
     accessProfile = vi.fn() as any as AccessProfile
     organizationProfile = vi.fn() as any as organizationState
 
-    abilityBuilder = new AbilityBuilder(ability, accessProfile, organizationProfile)
+    abilityBuilder = new TestableAbilityBuilder(ability, accessProfile, organizationProfile)
+})
+
+describe('buildAbilities', () => {
+    // test('base call', () => {
+    //     abilityBuilder.buildAbilities()
+    //
+    //     expect(ability.update).toHaveBeenCalledTimes(1)
+    //     // @ts-ignore
+    //     expect(organizationProfile.$onAction).toHaveBeenCalledTimes(1)
+    // })
+})
+
+describe('hasConfigAbility', () => {
+    beforeEach(() => {
+        accessProfile.isGuardian = true
+        // @ts-ignore
+        organizationProfile.isSchool = true
+        // @ts-ignore
+        organizationProfile.isCmf = false
+    })
+    test('fulfill all conditions', () => {
+        const conditions = [
+            {'function': 'accessHasAnyProfile', parameters: ['guardian', 'payer']},
+            {'function': 'organizationIsSchool'},
+        ]
+
+        expect(abilityBuilder.hasConfigAbility(conditions)).toBeTruthy()
+    })
+    test('fulfill at least one condition', () => {
+        const conditions = [
+            {'function': 'accessHasAnyProfile', parameters: ['guardian', 'payer']},
+            {'function': 'organizationIsCmf'},
+        ]
+
+        expect(abilityBuilder.hasConfigAbility(conditions)).toBeFalsy()
+    })
+    test('fulfill none of the conditions', () => {
+        const conditions = [
+            {'function': 'organizationIsCmf'},
+        ]
+
+        expect(abilityBuilder.hasConfigAbility(conditions)).toBeFalsy()
+    })
+})
+
+describe('execAndValidateCondition', () => {
+    test('accessHasAllRoleAbilities', () => {
+        ability.can = vi.fn((action: string, subject: string) => {
+            return action === 'read' && (subject === 'subject1' || subject === 'subject2')
+        })
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {
+                    'function': 'accessHasAllRoleAbilities',
+                    parameters: [
+                        {action: ABILITIES.READ, subject: 'subject1'},
+                        {action: ABILITIES.READ, subject: 'subject2'},
+                    ]
+                })
+        ).toBeTruthy()
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {
+                    'function': 'accessHasAllRoleAbilities',
+                    parameters: [
+                    {action: ABILITIES.READ, subject: 'subject1'},
+                    {action: ABILITIES.READ, subject: 'subject3'}
+                ]
+            })
+        ).toBeFalsy()
+    })
+
+    test('accessHasAnyRoleAbility', () => {
+        ability.can = vi.fn((action: string, subject: string) => {
+            return action === 'read' && subject === 'subject1'
+        })
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {
+                    'function': 'accessHasAnyRoleAbility',
+                    parameters: [
+                        {action: ABILITIES.READ, subject: 'subject1'},
+                        {action: ABILITIES.READ, subject: 'subject2'},
+                    ]
+                })
+        ).toBeTruthy()
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'accessHasAnyRoleAbility', parameters: [{action: ABILITIES.READ, subject: 'subject2'}]})
+        ).toBeFalsy()
+    })
+
+    test('accessHasAnyProfile', () => {
+        accessProfile.isMember = true
+        accessProfile.isGuardian = true
+        accessProfile.isPayer = true
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'accessHasAnyProfile', parameters: ['guardian', 'payer']}
+            )
+        ).toBeTruthy()
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'accessHasAnyProfile', parameters: ['guardian', 'caMember']}
+            )
+        ).toBeTruthy()
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'accessHasAnyProfile', parameters: ['caMember']}
+            )
+        ).toBeFalsy()
+    })
+
+    test('organizationHasAllModules', () => {
+        // @ts-ignore
+        organizationProfile.hasModule = vi.fn(
+            (module: string) => module === 'module1' || module === 'module2'
+        )
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'organizationHasAllModules', parameters: ['module1', 'module2']}
+            )
+        ).toBeTruthy()
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'organizationHasAllModules', parameters: ['module1', 'module3']}
+            )
+        ).toBeFalsy()
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'organizationHasAllModules', parameters: ['module3']}
+            )
+        ).toBeFalsy()
+    })
+
+    test('organizationHasAnyModule', () => {
+        // @ts-ignore
+        organizationProfile.hasModule = vi.fn(
+            (module: string) => module === 'module1' || module === 'module2'
+        )
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'organizationHasAnyModule', parameters: ['module1', 'module2']}
+            )
+        ).toBeTruthy()
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'organizationHasAnyModule', parameters: ['module1', 'module3']}
+            )
+        ).toBeTruthy()
+
+        expect(
+            abilityBuilder.execAndValidateCondition(
+                {'function': 'organizationHasAnyModule', parameters: ['module3']}
+            )
+        ).toBeFalsy()
+    })
+
+    test('organizationHasAnyModule', () => {
+        // @ts-ignore
+        accessProfile.isAdminAccount = true
+        expect(abilityBuilder.execAndValidateCondition({'function': 'accessIsAdminAccount'})).toBeTruthy()
+
+        // @ts-ignore
+        accessProfile.isAdminAccount = false
+        expect(abilityBuilder.execAndValidateCondition({'function': 'accessIsAdminAccount'})).toBeFalsy()
+    })
+
+    test('organizationIsSchool', () => {
+        // @ts-ignore
+        organizationProfile.isSchool = true
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsSchool'})).toBeTruthy()
+
+        // @ts-ignore
+        organizationProfile.isSchool = false
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsSchool'})).toBeFalsy()
+    })
+
+    test('organizationIsArtist', () => {
+        // @ts-ignore
+        organizationProfile.isArtist = true
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsArtist'})).toBeTruthy()
+
+        // @ts-ignore
+        organizationProfile.isArtist = false
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsArtist'})).toBeFalsy()
+    })
+
+    test('organizationIsManagerProduct', () => {
+        // @ts-ignore
+        organizationProfile.isManagerProduct = true
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsManagerProduct'})).toBeTruthy()
+
+        // @ts-ignore
+        organizationProfile.isManagerProduct = false
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsManagerProduct'})).toBeFalsy()
+    })
+
+    test('organizationHasChildren', () => {
+        // @ts-ignore
+        organizationProfile.hasChildren = true
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationHasChildren'})).toBeTruthy()
+
+        // @ts-ignore
+        organizationProfile.hasChildren = false
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationHasChildren'})).toBeFalsy()
+    })
+
+    test('organizationIsAssociation', () => {
+        // @ts-ignore
+        organizationProfile.isAssociation = true
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsAssociation'})).toBeTruthy()
+
+        // @ts-ignore
+        organizationProfile.isAssociation = false
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsAssociation'})).toBeFalsy()
+    })
+
+    test('organizationIsShowAdherentList', () => {
+        // @ts-ignore
+        organizationProfile.isShowAdherentList = true
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsShowAdherentList'})).toBeTruthy()
+
+        // @ts-ignore
+        organizationProfile.isShowAdherentList = false
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsShowAdherentList'})).toBeFalsy()
+    })
+
+    test('organizationIsCmf', () => {
+        // @ts-ignore
+        organizationProfile.isCmf = true
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsCmf'})).toBeTruthy()
+
+        // @ts-ignore
+        organizationProfile.isCmf = false
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationIsCmf'})).toBeFalsy()
+    })
+
+    test('organizationHasWebsite', () => {
+        // @ts-ignore
+        organizationProfile.getWebsite = true
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationHasWebsite'})).toBeTruthy()
+
+        // @ts-ignore
+        organizationProfile.getWebsite = false
+        expect(abilityBuilder.execAndValidateCondition({'function': 'organizationHasWebsite'})).toBeFalsy()
+    })
+
+    test('with expected result', () => {
+        // @ts-ignore
+        organizationProfile.getWebsite = true
+
+        expect(
+            abilityBuilder.execAndValidateCondition({'function': 'organizationHasWebsite', expectedResult: true})
+        ).toBeTruthy()
+
+        expect(
+            abilityBuilder.execAndValidateCondition({'function': 'organizationHasWebsite', expectedResult: 'abc'})
+        ).toBeFalsy()
+    })
+
+    test('invalid function', () => {
+        expect(
+            () => abilityBuilder.execAndValidateCondition({'function': 'invalid'})
+        ).toThrowError('unknown condition function : invalid')
+    })
+})
+
+describe('hasRoleAbility', () => {
+    beforeEach(() => {
+        ability.can = vi.fn((action: string, subject: string) => {
+            return action === 'read' && subject === 'a_subject'
+        })
+    })
+
+    test('owned ability', () => {
+        expect(abilityBuilder.hasRoleAbility({action: ABILITIES.READ, subject: 'a_subject'})).toBeTruthy()
+    })
+
+    test('not owned ability', () => {
+        expect(abilityBuilder.hasRoleAbility({action: ABILITIES.READ, subject: 'other_subject'})).toBeFalsy()
+    })
 })
 
-describe('setupAbilities', () => {
-    test('base call', () => {
+describe('hasAllRoleAbilities', () => {
+    beforeEach(() => {
+        ability.can = vi.fn((action: string, subject: string) => {
+            return action === 'read' && (subject === 'subject1' || subject === 'subject2')
+        })
+    })
+
+    test('own all abilities', () => {
+        const result = abilityBuilder.hasAllRoleAbilities(
+            [
+                {action: ABILITIES.READ, subject: 'subject1'},
+                {action: ABILITIES.READ, subject: 'subject2'},
+            ]
+        )
+
+        expect(result).toBeTruthy()
+    })
+
+    test('own at least one ability', () => {
+        const result = abilityBuilder.hasAllRoleAbilities(
+            [
+                {action: ABILITIES.READ, subject: 'subject1'},
+                {action: ABILITIES.READ, subject: 'subject3'},
+            ]
+        )
+
+        expect(result).toBeFalsy()
+    })
+
+    test('own none of the abilities', () => {
+        const result = abilityBuilder.hasAllRoleAbilities(
+            [
+                {action: ABILITIES.READ, subject: 'subject3'},
+                {action: ABILITIES.READ, subject: 'subject4'},
+            ]
+        )
+
+        expect(result).toBeFalsy()
+    })
+})
+
+describe('hasAnyRoleAbility', () => {
+    beforeEach(() => {
+        ability.can = vi.fn((action: string, subject: string) => {
+            return action === 'read' && (subject === 'subject1' || subject === 'subject2')
+        })
+    })
+
+    test('has all abilities', () => {
+        const result = abilityBuilder.hasAnyRoleAbility(
+            [
+                {action: ABILITIES.READ, subject: 'subject1'},
+                {action: ABILITIES.READ, subject: 'subject2'},
+            ]
+        )
+
+        expect(result).toBeTruthy()
+    })
+
+    test('has at least one ability', () => {
+        const result = abilityBuilder.hasAnyRoleAbility(
+            [
+                {action: ABILITIES.READ, subject: 'subject1'},
+                {action: ABILITIES.READ, subject: 'subject3'},
+            ]
+        )
+
+        expect(result).toBeTruthy()
+    })
+
+    test('any none of the abilites', () => {
+        const result = abilityBuilder.hasAnyRoleAbility(
+            [
+                {action: ABILITIES.READ, subject: 'subject3'},
+                {action: ABILITIES.READ, subject: 'subject4'},
+            ]
+        )
+
+        expect(result).toBeFalsy()
+    })
+})
+
+describe('hasProfile', () => {
+    test('owned profiles', () => {
+        accessProfile.isAdmin = true
+        accessProfile.isAdministratifManager = true
+        accessProfile.isPedagogicManager = true
+        accessProfile.isFinancialManager = true
+        accessProfile.isCaMember = true
+        accessProfile.isStudent = true
+        accessProfile.isTeacher = true
+        accessProfile.isMember = true
+        accessProfile.isOther = true
+        accessProfile.isGuardian = true
+        accessProfile.isPayer = true
+
+        expect(abilityBuilder.hasProfile('admin')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('administratifManager')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('pedagogicManager')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('financialManager')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('caMember')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('student')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('teacher')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('member')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('other')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('guardian')).toBeTruthy()
+        expect(abilityBuilder.hasProfile('payor')).toBeTruthy()
+    })
+
+    test('not owned profiles', () => {
+        accessProfile.isAdmin = false
+        accessProfile.isAdministratifManager = false
+        accessProfile.isPedagogicManager = false
+        accessProfile.isFinancialManager = false
+        accessProfile.isCaMember = false
+        accessProfile.isStudent = false
+        accessProfile.isTeacher = false
+        accessProfile.isMember = false
+        accessProfile.isOther = false
+        accessProfile.isGuardian = false
+        accessProfile.isPayer = false
+
+        expect(abilityBuilder.hasProfile('admin')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('administratifManager')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('pedagogicManager')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('financialManager')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('caMember')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('student')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('teacher')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('member')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('other')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('guardian')).toBeFalsy()
+        expect(abilityBuilder.hasProfile('payor')).toBeFalsy()
+    })
+})
+
+describe('hasAnyProfile', () => {
+    beforeEach(() => {
+        accessProfile.isMember = true
+        accessProfile.isGuardian = true
+        accessProfile.isPayer = true
+    })
+
+    test('own all profiles', () => {
+        expect(abilityBuilder.hasAnyProfile(['member', 'guardian', 'payor'])).toBeTruthy()
+    })
+
+    test('own at least one profile', () => {
+        expect(abilityBuilder.hasAnyProfile(['member', 'caMember'])).toBeTruthy()
+    })
+
+    test('own none of the profiles', () => {
+        expect(abilityBuilder.hasAnyProfile(['caMember', 'isFinancialManager'])).toBeFalsy()
+    })
+})
+
+describe('hasAllProfiles', () => {
+    beforeEach(() => {
+        accessProfile.isMember = true
+        accessProfile.isGuardian = true
+        accessProfile.isPayer = true
+    })
+
+    test('own all profiles', () => {
+        expect(abilityBuilder.hasAllProfiles(['member', 'guardian', 'payor'])).toBeTruthy()
+    })
+
+    test('own only one of the profiles', () => {
+        expect(abilityBuilder.hasAllProfiles(['member', 'caMember'])).toBeFalsy()
+    })
+
+    test('own none of the profiles', () => {
+        expect(abilityBuilder.hasAllProfiles(['caMember', 'isFinancialManager'])).toBeFalsy()
+    })
+})
+
+describe('hasRole', () => {
+    beforeEach(() => {
+        // @ts-ignore
+        accessProfile.hasRole = vi.fn((role: string) => role === 'foo')
+    })
+
+    test('has role', () => {
+        expect(abilityBuilder.hasRole('foo')).toBeTruthy()
+    })
+    test('has not role', () => {
+        expect(abilityBuilder.hasRole('bar')).toBeFalsy()
+    })
+})
+
+describe('hasAnyRole', () => {
+    beforeEach(() => {
+        // @ts-ignore
+        accessProfile.hasRole = vi.fn((role: string) => role === 'role1' || role === 'role2')
+    })
+
+    test('own all roles', () => {
+        expect(abilityBuilder.hasAnyRole(['role1', 'role2'])).toBeTruthy()
+    })
+
+    test('own at least one role', () => {
+        expect(abilityBuilder.hasAnyRole(['role1', 'role3'])).toBeTruthy()
+    })
+
+    test('own none of the roles', () => {
+        expect(abilityBuilder.hasAnyRole(['role3'])).toBeFalsy()
+    })
+})
+
+describe('hasAllRoles', () => {
+    beforeEach(() => {
         // @ts-ignore
-        ability.update = vi.fn((abilities: Array<AbilitiesType>) => {})
+        accessProfile.hasRole = vi.fn((role: string) => role === 'role1' || role === 'role2')
+    })
+
+    test('own all roles', () => {
+        expect(abilityBuilder.hasAllRoles(['role1', 'role2'])).toBeTruthy()
+    })
+
+    test('own at least one role', () => {
+        expect(abilityBuilder.hasAllRoles(['role1', 'role3'])).toBeFalsy()
+    })
+
+    test('own none of the roles', () => {
+        expect(abilityBuilder.hasAllRoles(['role3'])).toBeFalsy()
+    })
+})
+
+describe('hasModule', () => {
+    beforeEach(() => {
         // @ts-ignore
-        organizationProfile.$onAction = vi.fn((params: any) => {})
+        organizationProfile.hasModule = vi.fn((module: string) => module === 'foo')
+    })
 
-        abilityBuilder.setupAbilities()
+    test('has module', () => {
+        expect(abilityBuilder.hasModule('foo')).toBeTruthy()
+    })
+    test('has not module', () => {
+        expect(abilityBuilder.hasModule('bar')).toBeFalsy()
+    })
+})
 
-        expect(ability.update).toHaveBeenCalledTimes(1)
+describe('hasAnyModule', () => {
+    beforeEach(() => {
         // @ts-ignore
-        expect(organizationProfile.$onAction).toHaveBeenCalledTimes(1)
+        organizationProfile.hasModule = vi.fn((Module: string) => Module === 'Module1' || Module === 'Module2')
+    })
+
+    test('own all modules', () => {
+        expect(abilityBuilder.hasAnyModule(['Module1', 'Module2'])).toBeTruthy()
+    })
+
+    test('own at least one module', () => {
+        expect(abilityBuilder.hasAnyModule(['Module1', 'Module3'])).toBeTruthy()
+    })
+
+    test('own none of the modules', () => {
+        expect(abilityBuilder.hasAnyModule(['Module3'])).toBeFalsy()
     })
 })
 
+describe('hasAllModules', () => {
+    beforeEach(() => {
+        // @ts-ignore
+        organizationProfile.hasModule = vi.fn((Module: string) => Module === 'Module1' || Module === 'Module2')
+    })
+
+    test('own all modules', () => {
+        expect(abilityBuilder.hasAllModules(['Module1', 'Module2'])).toBeTruthy()
+    })
+
+    test('own at least one module', () => {
+        expect(abilityBuilder.hasAllModules(['Module1', 'Module3'])).toBeFalsy()
+    })
+
+    test('own none of the modules', () => {
+        expect(abilityBuilder.hasAllModules(['Module3'])).toBeFalsy()
+    })
+})