diff --git a/front-public/package.json b/front-public/package.json index 359bde4..37d2bf7 100644 --- a/front-public/package.json +++ b/front-public/package.json @@ -6,7 +6,8 @@ "start": "ng serve", "build": "ng build", "build:prod": "ng build --configuration production", - "test": "ng test --watch=false --browsers=ChromeHeadless", + "test": "vitest run", + "test:watch": "vitest", "lint": "eslint .", "lint:fix": "eslint . --fix" }, @@ -33,8 +34,10 @@ "@types/node": "^22.0.0", "angular-eslint": "^19.8.1", "eslint": "^9.39.4", + "jsdom": "^29.1.1", "sass": "^1.83.0", "typescript": "~5.8.3", - "typescript-eslint": "^8.62.0" + "typescript-eslint": "^8.62.0", + "vitest": "^3.2.4" } } diff --git a/front-public/src/app/core/error.service.spec.ts b/front-public/src/app/core/error.service.spec.ts new file mode 100644 index 0000000..4f35571 --- /dev/null +++ b/front-public/src/app/core/error.service.spec.ts @@ -0,0 +1,36 @@ +import { describe, it, expect } from 'vitest'; +import { HttpErrorResponse } from '@angular/common/http'; +import { ErrorService } from './error.service'; + +describe('ErrorService.toMessage', () => { + const svc = new ErrorService(); + + it('retourne un body string', () => { + const err = new HttpErrorResponse({ error: 'Boom', status: 500 }); + expect(svc.toMessage(err)).toBe('Boom'); + }); + + it('extrait body.message', () => { + const err = new HttpErrorResponse({ error: { message: 'Champ invalide' }, status: 400 }); + expect(svc.toMessage(err)).toBe('Champ invalide'); + }); + + it('joint un body.message tableau', () => { + const err = new HttpErrorResponse({ error: { message: ['a', 'b'] }, status: 400 }); + expect(svc.toMessage(err)).toBe('a, b'); + }); + + it('status 0 -> serveur injoignable', () => { + const err = new HttpErrorResponse({ status: 0 }); + expect(svc.toMessage(err)).toContain('injoignable'); + }); + + it('Error standard -> son message', () => { + expect(svc.toMessage(new Error('oops'))).toBe('oops'); + }); + + it('valeur inconnue -> fallback', () => { + expect(svc.toMessage(null)).toBe('Une erreur est survenue.'); + expect(svc.toMessage(undefined, 'custom')).toBe('custom'); + }); +}); diff --git a/front-public/vitest-setup.ts b/front-public/vitest-setup.ts new file mode 100644 index 0000000..6c64aec --- /dev/null +++ b/front-public/vitest-setup.ts @@ -0,0 +1,3 @@ +// Charge le compilateur Angular pour permettre le fallback JIT en test +// (sinon l'import de symboles @angular/* partiellement compilés échoue). +import '@angular/compiler'; diff --git a/front-public/vitest.config.ts b/front-public/vitest.config.ts new file mode 100644 index 0000000..ce1398d --- /dev/null +++ b/front-public/vitest.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from 'vitest/config'; + +// Vitest pour les tests de logique/services purs (cohérent avec le back). +// Les tests de composants avec TestBed nécessiteraient un plugin Angular dédié +// (ex. @analogjs/vitest-angular) — hors périmètre pour l'instant. +export default defineConfig({ + test: { + globals: true, + environment: 'node', + setupFiles: ['./vitest-setup.ts'], + include: ['src/**/*.spec.ts'], + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1fc0d64..939c9bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -103,13 +103,13 @@ importers: version: 10.0.0 '@vitest/coverage-v8': specifier: ^3.2.6 - version: 3.2.6(vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0)) + version: 3.2.6(vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@29.1.1(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0)) typescript: specifier: ^5.7.0 version: 5.9.3 vitest: specifier: ^3.0.0 - version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@29.1.1(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) front-public: dependencies: @@ -174,6 +174,9 @@ importers: eslint: specifier: ^9.39.4 version: 9.39.4(jiti@1.21.7) + jsdom: + specifier: ^29.1.1 + version: 29.1.1(@noble/hashes@1.8.0) sass: specifier: ^1.83.0 version: 1.99.0 @@ -183,6 +186,9 @@ importers: typescript-eslint: specifier: ^8.62.0 version: 8.62.0(eslint@9.39.4(jiti@1.21.7))(typescript@5.8.3) + vitest: + specifier: ^3.2.4 + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@29.1.1(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0) shared: {} @@ -474,6 +480,10 @@ packages: '@asamuzakjp/dom-selector@6.8.1': resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==} + '@asamuzakjp/dom-selector@7.1.1': + resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + '@asamuzakjp/generational-cache@1.0.1': resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} @@ -6925,6 +6935,15 @@ packages: canvas: optional: true + jsdom@29.1.1: + resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + jsep@1.4.0: resolution: {integrity: sha512-B7qPcEVE3NVkmSJbaYxvv4cHkVW7DQsZz13pUMrfS8z8Q/BuShN+gcTXrUlPiGqM2/t/EEaI030bpxMqY8gMlw==} engines: {node: '>= 10.16.0'} @@ -10968,6 +10987,14 @@ snapshots: is-potential-custom-element-name: 1.0.1 lru-cache: 11.5.0 + '@asamuzakjp/dom-selector@7.1.1': + dependencies: + '@asamuzakjp/generational-cache': 1.0.1 + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + '@asamuzakjp/generational-cache@1.0.1': {} '@asamuzakjp/nwsapi@2.3.9': {} @@ -16223,7 +16250,7 @@ snapshots: dependencies: vite: 7.3.3(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0) - '@vitest/coverage-v8@3.2.6(vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0))': + '@vitest/coverage-v8@3.2.6(vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@29.1.1(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0))': dependencies: '@ampproject/remapping': 2.3.0 '@bcoe/v8-coverage': 1.0.2 @@ -16238,7 +16265,7 @@ snapshots: std-env: 3.10.0 test-exclude: 7.0.2 tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) + vitest: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@29.1.1(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0) transitivePeerDependencies: - supports-color @@ -16250,6 +16277,14 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 + '@vitest/mocker@3.2.4(vite@7.3.3(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.3(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0) + '@vitest/mocker@3.2.4(vite@7.3.3(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0))': dependencies: '@vitest/spy': 3.2.4 @@ -19363,6 +19398,32 @@ snapshots: - '@noble/hashes' - supports-color + jsdom@29.1.1(@noble/hashes@1.8.0): + dependencies: + '@asamuzakjp/css-color': 5.1.11 + '@asamuzakjp/dom-selector': 7.1.1 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.5(css-tree@3.2.1) + '@exodus/bytes': 1.15.1(@noble/hashes@1.8.0) + css-tree: 3.2.1 + data-urls: 7.0.0(@noble/hashes@1.8.0) + decimal.js: 10.6.0 + html-encoding-sniffer: 6.0.0(@noble/hashes@1.8.0) + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.0 + parse5: 8.0.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.1 + undici: 7.27.1 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1(@noble/hashes@1.8.0) + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + jsep@1.4.0: {} jsesc@3.1.0: {} @@ -22933,6 +22994,27 @@ snapshots: vary@1.1.2: {} + vite-node@3.2.4(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0): + dependencies: + cac: 6.7.14 + debug: 4.4.3(supports-color@8.1.1) + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.3(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + vite-node@3.2.4(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0): dependencies: cac: 6.7.14 @@ -23005,7 +23087,50 @@ snapshots: terser: 5.47.1 yaml: 2.9.0 - vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@28.1.0(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0): + vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@29.1.1(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@7.3.3(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + debug: 4.4.3(supports-color@8.1.1) + expect-type: 1.3.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.4 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.16 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.3(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0) + vite-node: 3.2.4(@types/node@22.19.19)(jiti@1.21.7)(less@4.2.2)(sass@1.99.0)(terser@5.39.0)(yaml@2.9.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.13 + '@types/node': 22.19.19 + jsdom: 29.1.1(@noble/hashes@1.8.0) + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.19)(jiti@1.21.7)(jsdom@29.1.1(@noble/hashes@1.8.0))(less@4.2.2)(sass@1.99.0)(terser@5.47.1)(yaml@2.9.0): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 @@ -23033,7 +23158,7 @@ snapshots: optionalDependencies: '@types/debug': 4.1.13 '@types/node': 22.19.19 - jsdom: 28.1.0(@noble/hashes@1.8.0) + jsdom: 29.1.1(@noble/hashes@1.8.0) transitivePeerDependencies: - jiti - less