Lab 22 : Tests unitaires avec Vitest
📖 Ressources​
🚀 Code de départ​
album-wholesale-v17-signal-pre-jest
Dans ce lab, vous écrirez des tests unitaires pour les services et les composants en utilisant Vitest, le test runner moderne recommandé pour Angular. Vous utiliserez vi.fn() pour les mocks, les matchers Vitest et les hooks de cycle de vie.
📝 Instructions​
Étape 1 : Ajouter Vitest au projet​
Installez les versions compatibles manuellement (ng add @angular/vitest installe Vitest 4.x qui est incompatible avec Angular 17 / Vite 5) :
npm install --save-dev vitest@2 @vitest/coverage-v8@2 @analogjs/vite-plugin-angular jsdom
Créez vite.config.ts à la racine du projet :
import { defineConfig } from 'vitest/config';
import angular from '@analogjs/vite-plugin-angular';
export default defineConfig({
plugins: [angular()],
test: {
globals: true,
environment: 'jsdom',
include: ['**/*.spec.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'html'],
},
},
});
Ajoutez un script de test dans package.json :
{
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage"
}
}
Étape 2 : Exécuter les tests existants​
npm test
Vérifiez que tous les tests existants passent avant d'en ajouter de nouveaux.
Étape 3 : Tester un service​
Créez src/app/services/album.service.spec.ts :
import { TestBed } from '@angular/core/testing';
import { HttpClientTestingModule, HttpTestingController }
from '@angular/common/http/testing';
import { AlbumService } from './album.service';
import { Album } from '../model/album.model';
describe('AlbumService', () => {
let service: AlbumService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [AlbumService],
});
service = TestBed.inject(AlbumService);
httpMock = TestBed.inject(HttpTestingController);
});
afterEach(() => httpMock.verify());
it('should fetch albums', () => {
const mockAlbums: Album[] = [
{ id: 1, name: 'Test Album', artist: 'Artist', price: 9, description: '', tags: [] },
];
service.findAll().subscribe(albums => {
expect(albums).toHaveLength(1);
expect(albums[0].name).toBe('Test Album');
});
const req = httpMock.expectOne('http://localhost:3000/albums');
expect(req.request.method).toBe('GET');
req.flush(mockAlbums);
});
});
Étape 4 : Utiliser vi.fn() pour mocker une dépendance​
Créez src/app/components/album-list/album-list.component.spec.ts :
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { vi } from 'vitest';
import { of } from 'rxjs';
import { AlbumListComponent } from './album-list.component';
import { AlbumService } from '../../services/album.service';
describe('AlbumListComponent', () => {
let fixture: ComponentFixture<AlbumListComponent>;
let albumServiceMock: { findAll: ReturnType<typeof vi.fn> };
beforeEach(async () => {
albumServiceMock = {
findAll: vi.fn().mockReturnValue(of([
{ id: 1, name: 'Mock Album', artist: 'Mock Artist', price: 9, description: '', tags: [] },
])),
};
await TestBed.configureTestingModule({
imports: [AlbumListComponent],
providers: [
{ provide: AlbumService, useValue: albumServiceMock },
],
}).compileComponents();
fixture = TestBed.createComponent(AlbumListComponent);
fixture.detectChanges();
});
it('should display albums', () => {
const items = fixture.nativeElement.querySelectorAll('.album-card');
expect(items.length).toBeGreaterThan(0);
});
it('should call findAll on init', () => {
expect(albumServiceMock.findAll).toHaveBeenCalledOnce();
});
});
Étape 5 : Utiliser les hooks de cycle de vie​
Vitest fournit beforeAll, beforeEach, afterEach, afterAll :
describe('Calculs du panier', () => {
let items: CartItem[];
beforeEach(() => {
items = [
{ id: 1, quantity: 2, price: 10 },
{ id: 2, quantity: 1, price: 20 },
];
});
it('should calculate total', () => {
const total = items.reduce((sum, i) => sum + i.quantity * i.price, 0);
expect(total).toBe(40);
});
it('should count items', () => {
expect(items).toHaveLength(2);
});
});
Étape 6 : Exécuter avec la couverture​
npm run test:coverage
Consultez le rapport de couverture et assurez-vous que les méthodes critiques des services sont couvertes.
Étape 7 : Ouvrir l'interface graphique​
npx vitest --ui
Explorez le navigateur de tests interactif pour naviguer dans les tests et voir les résultats en temps réel.