Просмотр исходного кода

complete abilityUtils.test.ts and add apiRequestService.test.ts

Olivier Massot 3 лет назад
Родитель
Сommit
359f96a2eb

+ 2 - 0
services/data/apiRequestService.ts

@@ -8,6 +8,8 @@ import {HTTP_METHOD} from "~/types/enum/data";
 import {$Fetch, FetchOptions} from "ohmyfetch";
 
 class ApiRequestService {
+    // TODO: fusionner les paramètres `query` et `params` des méthodes, puisque l'un est un alias de l'autre
+    //       dans ohmyfetch : https://github.com/unjs/ofetch#%EF%B8%8F-adding-query-search-params
     private readonly fetch: $Fetch
 
     public constructor(

+ 1 - 1
services/data/fileManager.ts

@@ -8,7 +8,7 @@ class FileManager {
     }
 
     public fetch() {
-
+        // TODO: récupérer le contenu de fileNormalizer ici
     }
 }
 

+ 2 - 2
services/rights/abilityBuilder.ts

@@ -2,7 +2,7 @@ import RoleUtils from '~/services/rights/roleUtils'
 import {AbilitiesType} from '~/types/interfaces'
 import {MongoAbility} from "@casl/ability/dist/types/Ability";
 import {ABILITIES} from "~/types/enum/enums";
-import {read} from "yaml-import";
+import yaml from "yaml-import";
 import _ from "lodash"
 
 interface Condition {
@@ -68,7 +68,7 @@ class AbilityBuilder {
     buildAbilitiesFromConfig() {
         const abilitiesByConfig: Array<AbilitiesType> = []
 
-        const doc = read(this.configFile)
+        const doc = yaml.read(this.configFile)
         const fromConfig = doc.abilities
 
         _.each(fromConfig, (ability: { action: ABILITIES, conditions: Array<Condition> }, subject: string) => {

+ 175 - 0
tests/units/services/data/apiRequestService.test.ts

@@ -0,0 +1,175 @@
+import {describe, expect, test} from 'vitest'
+import ApiRequestService from "~/services/data/apiRequestService";
+import {$Fetch, FetchOptions} from "ohmyfetch";
+import {HTTP_METHOD} from "~/types/enum/data";
+import {AssociativeArray} from "~/types/data";
+
+class TestableApiRequestService extends ApiRequestService {
+    public async request(
+        method: HTTP_METHOD,
+        url: string,
+        body: string | null = null,
+        params: AssociativeArray | null = null,
+        query: AssociativeArray | null = null
+    ): Promise<Response> {
+        return super.request(method, url, body, params, query)
+    }
+}
+
+let fetcher: $Fetch
+let apiRequestService: TestableApiRequestService
+
+beforeEach(() => {
+    // @ts-ignore
+    fetcher = vi.fn((url: string, config: FetchOptions) => 'fetch_response') as $Fetch
+    apiRequestService = new TestableApiRequestService(fetcher)
+})
+
+const mockedRequestMethod = (
+    method: HTTP_METHOD,
+    url: string,
+    body: string | null = null,
+    params: AssociativeArray | null = null,
+    query: AssociativeArray | null = null
+) => 'a_response'
+
+describe('get', () => {
+    test('simple call', async () => {
+        // @ts-ignore
+        apiRequestService.request = vi.fn(mockedRequestMethod)
+
+        const result = await apiRequestService.get('https://myapi.com/api/item', { a: 1 })
+
+        expect(result).toEqual('a_response')
+        expect(apiRequestService.request).toHaveBeenCalledWith(
+            HTTP_METHOD.GET, 'https://myapi.com/api/item', null, null, { a: 1 }
+        )
+    })
+})
+
+describe('post', () => {
+    test('simple call', async () => {
+        // @ts-ignore
+        apiRequestService.request = vi.fn(mockedRequestMethod)
+
+        const result = await apiRequestService.post(
+            'https://myapi.com/api/item',
+            'request_body',
+            { a: 1 },
+            { b: 2 },
+        )
+
+        expect(result).toEqual('a_response')
+        expect(apiRequestService.request).toHaveBeenCalledWith(
+            HTTP_METHOD.POST,
+            'https://myapi.com/api/item',
+            'request_body',
+            { a: 1 },
+            { b: 2 }
+        )
+    })
+})
+
+describe('put', () => {
+    test('simple call', async () => {
+        // @ts-ignore
+        apiRequestService.request = vi.fn(mockedRequestMethod)
+
+        const result = await apiRequestService.put(
+            'https://myapi.com/api/item',
+            'request_body',
+            { a: 1 },
+            { b: 2 },
+        )
+
+        expect(result).toEqual('a_response')
+        expect(apiRequestService.request).toHaveBeenCalledWith(
+            HTTP_METHOD.PUT,
+            'https://myapi.com/api/item',
+            'request_body',
+            { a: 1 },
+            { b: 2 }
+        )
+    })
+})
+
+describe('delete', () => {
+    test('simple call', async () => {
+        // @ts-ignore
+        apiRequestService.request = vi.fn(mockedRequestMethod)
+
+        const result = await apiRequestService.delete(
+            'https://myapi.com/api/item',
+            { a: 1 },
+        )
+
+        expect(result).toEqual('a_response')
+        expect(apiRequestService.request).toHaveBeenCalledWith(
+            HTTP_METHOD.DELETE,
+            'https://myapi.com/api/item',
+            null,
+            null,
+            { a: 1 },
+        )
+    })
+})
+
+describe('request', () => {
+    test('simple call', async () => {
+
+        const result = await apiRequestService.request(HTTP_METHOD.GET, 'https://myapi.com/api/item')
+
+        expect(result).toEqual('fetch_response')
+        // @ts-ignore
+        expect(fetcher).toHaveBeenCalledWith('https://myapi.com/api/item', {method: 'GET'})
+    })
+
+    test('post with body', async () => {
+
+        const result = await apiRequestService.request(HTTP_METHOD.POST, 'https://myapi.com/api/item', 'a_body')
+
+        expect(result).toEqual('fetch_response')
+        // @ts-ignore
+        expect(fetcher).toHaveBeenCalledWith('https://myapi.com/api/item', {method: 'POST', body: 'a_body'})
+    })
+
+    test('put with body', async () => {
+
+        const result = await apiRequestService.request(HTTP_METHOD.PUT, 'https://myapi.com/api/item', 'a_body')
+
+        expect(result).toEqual('fetch_response')
+        // @ts-ignore
+        expect(fetcher).toHaveBeenCalledWith('https://myapi.com/api/item', {method: 'PUT', body: 'a_body'})
+    })
+
+    test('get : body must be ignored even if provided', async () => {
+
+        const result = await apiRequestService.request(HTTP_METHOD.GET, 'https://myapi.com/api/item', 'a_body')
+
+        expect(result).toEqual('fetch_response')
+        // @ts-ignore
+        expect(fetcher).toHaveBeenCalledWith('https://myapi.com/api/item', {method: 'GET'})
+    })
+
+    test('with query and params', async () => {
+        const result = await apiRequestService.request(
+            HTTP_METHOD.PUT,
+            'https://myapi.com/api/item',
+            'a_body',
+            { a: 1 },
+            { b: 2 }
+        )
+
+        expect(result).toEqual('fetch_response')
+        // @ts-ignore
+        expect(fetcher).toHaveBeenCalledWith(
+            'https://myapi.com/api/item',
+            {
+                method: 'PUT',
+                body: 'a_body',
+                params: { a: 1 },
+                query: { b: 2 },
+            }
+        )
+    })
+})

+ 85 - 8
tests/units/services/rights/abilityBuilder.test.ts

@@ -1,8 +1,9 @@
 import { describe, test, it, expect } from 'vitest'
 import {MongoAbility} from "@casl/ability/dist/types/Ability";
-import {AccessProfile, organizationState} from "~/types/interfaces";
+import {AbilitiesType, AccessProfile, organizationState} from "~/types/interfaces";
 import AbilityBuilder from "~/services/rights/abilityBuilder";
 import {ABILITIES} from "~/types/enum/enums";
+import yaml from "yaml-import";
 
 let ability: MongoAbility
 let accessProfile: AccessProfile
@@ -13,6 +14,35 @@ class TestableAbilityBuilder extends AbilityBuilder {
     public execAndValidateCondition(condition: any, subject: string = '') { return super.execAndValidateCondition(condition, subject) }
 }
 
+// Mock the content of the config yaml files
+// > This must be done in the global scope: https://vitest.dev/api/vi.html#vi-mock
+const doc = {
+    abilities: {
+        'subject1': {
+            action: ABILITIES.READ,
+            conditions: [
+                {
+                    'function': 'fct1',
+                    'parameters': ['param1'],
+                    'expectedResult': true
+                }
+            ]
+        },
+        'subject2': {
+            action: ABILITIES.READ,
+            conditions: {
+                'function': 'fct2',
+                'parameters': ['param2'],
+                'expectedResult': false
+            }
+        }
+    }
+}
+vi.mock('yaml-import', async () => {
+    return {
+        default: { read: vi.fn((data: string) => doc) }
+    }
+})
 
 beforeEach(() => {
     ability = vi.fn() as any as MongoAbility
@@ -23,13 +53,60 @@ beforeEach(() => {
 })
 
 describe('buildAbilities', () => {
-    // test('base call', () => {
-    //     abilityBuilder.buildAbilities()
-    //
-    //     expect(ability.update).toHaveBeenCalledTimes(1)
-    //     // @ts-ignore
-    //     expect(organizationProfile.$onAction).toHaveBeenCalledTimes(1)
-    // })
+    test('base call', () => {
+
+        const roleAbilities: Array<AbilitiesType> = [
+            {action: ABILITIES.READ, subject: 'subject1'},
+            {action: ABILITIES.READ, subject: 'subject2'}
+        ]
+        const configAbilities: Array<AbilitiesType> = [
+            {action: ABILITIES.READ, subject: 'subject3'},
+            {action: ABILITIES.READ, subject: 'subject4'}
+        ]
+        const allAbilities: Array<AbilitiesType> = roleAbilities.concat(configAbilities)
+
+
+        abilityBuilder.buildAbilitiesFromRoles = vi.fn(() => roleAbilities)
+        abilityBuilder.buildAbilitiesFromConfig = vi.fn(() => configAbilities)
+
+        ability.update = vi.fn()
+
+        const result = abilityBuilder.buildAbilities()
+
+        expect(ability.update).toHaveBeenCalledTimes(2)
+        expect(ability.update).toHaveBeenCalledWith(roleAbilities)
+        expect(ability.update).toHaveBeenCalledWith(allAbilities)
+
+        expect(abilityBuilder.buildAbilitiesFromRoles).toHaveBeenCalledOnce()
+        expect(abilityBuilder.buildAbilitiesFromConfig).toHaveBeenCalledOnce()
+
+        expect(result).toEqual(allAbilities)
+    })
+})
+
+describe('buildAbilitiesFromRoles', () => {
+  test('calls roleUtils', () => {
+      accessProfile.roles = ['ROLE_EVENTS_VIEW', 'ROLE_COURSES', 'ROLE_TEACHER_CORE', 'ROLE_OTHER']
+
+      const expected = [
+          { subject: 'events', action: 'read' },
+          { subject: 'courses', action: 'manage' },
+          { subject: 'other', action: 'manage' },
+      ]
+
+      expect(abilityBuilder.buildAbilitiesFromRoles()).toEqual(expected)
+  })
+})
+
+describe('buildAbilitiesFromConfig', () => {
+  test('calls roleUtils', () => {
+      abilityBuilder.hasConfigAbility = vi.fn(() => true)
+
+      expect(abilityBuilder.buildAbilitiesFromConfig()).toEqual([
+          { action: 'read', subject: 'subject1' },
+          { action: 'read', subject: 'subject2' },
+      ])
+  })
 })
 
 describe('hasConfigAbility', () => {