front(test): Vitest + premier spec (ErrorService)

- Vitest (cohérent avec le back) pour les tests de logique/services purs ;
  vitest-setup charge @angular/compiler (fallback JIT requis pour importer
  les symboles @angular/* partiellement compilés)
- error.service.spec.ts : 6 cas couvrant toMessage()
- script test -> vitest run (+ test:watch). Tests de composants TestBed =
  plugin Angular dédié, hors périmètre pour l'instant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
z3n
2026-06-26 13:17:00 +00:00
parent c9fa0cd97b
commit f9df2dd1bb
5 changed files with 188 additions and 8 deletions

View File

@@ -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"
}
}

View File

@@ -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');
});
});

View File

@@ -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';

View File

@@ -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'],
},
});

137
pnpm-lock.yaml generated
View File

@@ -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