test: ajoute des tests automatisés frontend (Vitest) et mobile (Jest)

- Frontend Next.js : Vitest + Testing Library
  - Button (rendu, clic, état loading)
  - auth-store (setAuth, déconnexion, persistance token)
  - script `npm test`, config jsdom + alias @/
- Mobile Expo : Jest (preset jest-expo)
  - getApiError (erreur Axios, validation, erreur générique, sans réponse)
  - script `npm test`, transformIgnorePatterns adapté
- Cahier de tests : section « Outils de test automatisés » (PHPUnit + Vitest + Jest)
  et entrée 6.4 (PV de recette) au sommaire

Suites vertes : backend 15, frontend 6, mobile 4. tsc/lint/build OK, expo-doctor 18/18.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Azmog
2026-06-18 22:17:20 +02:00
parent 8904e6127a
commit 0e07f5a57e
11 changed files with 4713 additions and 32 deletions
+1878 -28
View File
File diff suppressed because it is too large Load Diff
+9 -2
View File
@@ -6,7 +6,8 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint"
"lint": "eslint",
"test": "vitest run"
},
"dependencies": {
"@tanstack/react-query": "^5.90.21",
@@ -22,12 +23,18 @@
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
"@testing-library/dom": "^10.4.1",
"@testing-library/jest-dom": "^6.9.1",
"@testing-library/react": "^16.3.2",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@vitejs/plugin-react": "^6.0.2",
"eslint": "^9",
"eslint-config-next": "16.1.6",
"jsdom": "^29.1.1",
"tailwindcss": "^4",
"typescript": "^5"
"typescript": "^5",
"vitest": "^4.1.9"
}
}
+30
View File
@@ -0,0 +1,30 @@
import { describe, it, expect, vi } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import Button from '@/components/ui/Button';
describe('Button', () => {
it('affiche son libellé', () => {
render(<Button>Enregistrer</Button>);
expect(screen.getByRole('button', { name: 'Enregistrer' })).toBeInTheDocument();
});
it('déclenche onClick au clic', () => {
const onClick = vi.fn();
render(<Button onClick={onClick}>Valider</Button>);
fireEvent.click(screen.getByRole('button', { name: 'Valider' }));
expect(onClick).toHaveBeenCalledTimes(1);
});
it('est désactivé pendant le chargement et ne déclenche pas onClick', () => {
const onClick = vi.fn();
render(
<Button loading onClick={onClick}>
Envoi
</Button>
);
const btn = screen.getByRole('button');
expect(btn).toBeDisabled();
fireEvent.click(btn);
expect(onClick).not.toHaveBeenCalled();
});
});
+42
View File
@@ -0,0 +1,42 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { useAuthStore } from '@/lib/auth-store';
import type { Utilisateur } from '@/types';
const fakeUser = {
id: 1,
nom: 'Martin',
prenom: 'Claire',
email: 'claire@email.fr',
role: { id: 2, nom: 'membre' },
} as unknown as Utilisateur;
describe('auth-store', () => {
beforeEach(() => {
localStorage.clear();
useAuthStore.setState({ user: null, token: null, isAuthenticated: false });
});
it('démarre déconnecté', () => {
const state = useAuthStore.getState();
expect(state.isAuthenticated).toBe(false);
expect(state.token).toBeNull();
});
it('setAuth stocke le token et authentifie l\'utilisateur', () => {
useAuthStore.getState().setAuth(fakeUser, 'jwt-123');
const state = useAuthStore.getState();
expect(state.isAuthenticated).toBe(true);
expect(state.token).toBe('jwt-123');
expect(state.user?.email).toBe('claire@email.fr');
expect(localStorage.getItem('cesizen_token')).toBe('jwt-123');
});
it('setAuth(null) déconnecte et purge le token', () => {
useAuthStore.getState().setAuth(fakeUser, 'jwt-123');
useAuthStore.getState().setAuth(null, null);
const state = useAuthStore.getState();
expect(state.isAuthenticated).toBe(false);
expect(state.token).toBeNull();
expect(localStorage.getItem('cesizen_token')).toBeNull();
});
});
+18
View File
@@ -0,0 +1,18 @@
import { defineConfig } from 'vitest/config';
import react from '@vitejs/plugin-react';
import path from 'node:path';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
},
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./vitest.setup.ts'],
include: ['src/**/*.{test,spec}.{ts,tsx}'],
},
});
+1
View File
@@ -0,0 +1 @@
import '@testing-library/jest-dom/vitest';