@the-bearded-bear/claude-craft 8.8.1 → 8.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dev/i18n/de/Angular/commands/check-compliance.md +218 -168
- package/Dev/i18n/de/Common/agents/refactoring-specialist.md +146 -69
- package/Dev/i18n/de/Common/commands/add-technology.md +166 -68
- package/Dev/i18n/de/Common/commands/setup-ci.md +216 -33
- package/Dev/i18n/de/Laravel/commands/check-compliance.md +223 -115
- package/Dev/i18n/de/Python/checklists/new-feature.md +319 -44
- package/Dev/i18n/de/React/rules/02-architecture.md +483 -322
- package/Dev/i18n/de/React/rules/03-coding-standards.md +584 -368
- package/Dev/i18n/de/Symfony/commands/check-compliance.md +186 -114
- package/Dev/i18n/de/Symfony/rules/07-testing-symfony.md +679 -10
- package/Dev/i18n/de/UIUX/commands/a11y-component.md +284 -26
- package/Dev/i18n/de/UIUX/commands/design-tokens.md +199 -35
- package/Dev/i18n/de/UIUX/commands/user-flow.md +179 -16
- package/Dev/i18n/de/VueJS/commands/check-compliance.md +227 -102
- package/Dev/i18n/es/Angular/commands/check-compliance.md +217 -167
- package/Dev/i18n/es/Common/commands/add-technology.md +158 -60
- package/Dev/i18n/es/Laravel/commands/check-compliance.md +223 -115
- package/Dev/i18n/es/React/commands/check-testing.md +263 -169
- package/Dev/i18n/es/ReactNative/commands/check-testing.md +256 -198
- package/Dev/i18n/es/Symfony/commands/check-compliance.md +189 -117
- package/Dev/i18n/es/Symfony/commands/check-testing.md +301 -102
- package/Dev/i18n/es/Symfony/commands/migration-plan.md +267 -34
- package/Dev/i18n/es/UIUX/commands/a11y-component.md +274 -16
- package/Dev/i18n/es/UIUX/commands/design-tokens.md +186 -22
- package/Dev/i18n/es/UIUX/commands/user-flow.md +173 -10
- package/Dev/i18n/es/VueJS/commands/check-compliance.md +227 -102
- package/Dev/i18n/fr/Angular/commands/check-compliance.md +217 -167
- package/Dev/i18n/fr/Common/commands/ralph-run.md +138 -60
- package/Dev/i18n/fr/Laravel/commands/check-compliance.md +223 -115
- package/Dev/i18n/fr/React/commands/check-architecture.md +370 -53
- package/Dev/i18n/fr/React/commands/check-code-quality.md +454 -64
- package/Dev/i18n/fr/React/commands/check-testing.md +476 -102
- package/Dev/i18n/fr/Symfony/commands/check-compliance.md +188 -116
- package/Dev/i18n/fr/VueJS/commands/check-compliance.md +227 -102
- package/Dev/i18n/pt/Angular/commands/check-compliance.md +225 -175
- package/Dev/i18n/pt/Common/agents/ralph-conductor.md +211 -30
- package/Dev/i18n/pt/Common/commands/add-technology.md +149 -51
- package/Dev/i18n/pt/Common/commands/ralph-run.md +239 -35
- package/Dev/i18n/pt/Flutter/commands/analyze-performance.md +331 -46
- package/Dev/i18n/pt/Flutter/commands/check-compliance.md +234 -29
- package/Dev/i18n/pt/Flutter/commands/generate-feature.md +526 -51
- package/Dev/i18n/pt/Flutter/commands/generate-widget.md +515 -27
- package/Dev/i18n/pt/Flutter/commands/golden-update.md +322 -46
- package/Dev/i18n/pt/Flutter/commands/localization-check.md +278 -37
- package/Dev/i18n/pt/Laravel/commands/check-compliance.md +212 -104
- package/Dev/i18n/pt/React/commands/accessibility-check.md +151 -42
- package/Dev/i18n/pt/React/commands/bundle-analyze.md +300 -25
- package/Dev/i18n/pt/React/commands/check-architecture.md +369 -34
- package/Dev/i18n/pt/React/commands/check-code-quality.md +440 -34
- package/Dev/i18n/pt/React/commands/check-compliance.md +232 -62
- package/Dev/i18n/pt/React/commands/check-security.md +370 -31
- package/Dev/i18n/pt/React/commands/check-testing.md +473 -43
- package/Dev/i18n/pt/React/commands/generate-component.md +454 -19
- package/Dev/i18n/pt/React/commands/generate-hook.md +425 -24
- package/Dev/i18n/pt/React/commands/storybook-story.md +520 -35
- package/Dev/i18n/pt/ReactNative/commands/app-size.md +358 -387
- package/Dev/i18n/pt/ReactNative/commands/check-code-quality.md +246 -75
- package/Dev/i18n/pt/ReactNative/commands/check-compliance.md +191 -85
- package/Dev/i18n/pt/ReactNative/commands/check-security.md +363 -115
- package/Dev/i18n/pt/ReactNative/commands/check-testing.md +269 -79
- package/Dev/i18n/pt/ReactNative/commands/generate-screen.md +491 -324
- package/Dev/i18n/pt/ReactNative/commands/native-module.md +539 -82
- package/Dev/i18n/pt/ReactNative/commands/store-prepare.md +429 -185
- package/Dev/i18n/pt/ReactNative/rules/02-architecture.md +1084 -31
- package/Dev/i18n/pt/Symfony/commands/check-compliance.md +195 -123
- package/Dev/i18n/pt/UIUX/commands/a11y-audit.md +208 -24
- package/Dev/i18n/pt/UIUX/commands/a11y-component.md +281 -23
- package/Dev/i18n/pt/UIUX/commands/design-tokens.md +197 -33
- package/Dev/i18n/pt/UIUX/commands/user-flow.md +183 -20
- package/Dev/i18n/pt/VueJS/commands/check-compliance.md +228 -103
- package/Dev/i18n/pt/Workflow/commands/analyze.md +147 -146
- package/Dev/i18n/pt/Workflow/commands/design.md +205 -204
- package/Dev/i18n/pt/Workflow/commands/implement.md +184 -184
- package/Project/i18n/de/Sprint/commands/dev.md +339 -86
- package/Project/i18n/es/Sprint/commands/dev.md +342 -91
- package/Project/i18n/pt/Sprint/commands/dev.md +343 -92
- package/bundles/cursor/.cursorrules +1 -1
- package/bundles/windsurf/.windsurfrules +1 -1
- package/package.json +1 -1
|
@@ -1,115 +1,439 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Vérification
|
|
3
|
-
argument-hint: [arguments]
|
|
2
|
+
description: Vérification de la Stratégie de Tests
|
|
4
3
|
---
|
|
5
4
|
|
|
6
|
-
# Vérification
|
|
5
|
+
# Vérification de la Stratégie de Tests
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
Vérifie que l'application React dispose d'une couverture de tests complète et suit les meilleures pratiques de test.
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
## Ce que fait cette commande
|
|
10
|
+
|
|
11
|
+
1. **Analyse des Tests**
|
|
12
|
+
- Vérifier la couverture de tests
|
|
13
|
+
- Valider la qualité des tests
|
|
14
|
+
- Contrôler les patterns de test
|
|
15
|
+
- Vérifier l'organisation des tests
|
|
16
|
+
- Analyser les performances des tests
|
|
17
|
+
|
|
18
|
+
2. **Métriques Mesurées**
|
|
19
|
+
- Couverture du code (lignes, fonctions, branches)
|
|
20
|
+
- Nombre de tests par type (unitaire, intégration, e2e)
|
|
21
|
+
- Temps d'exécution des tests
|
|
22
|
+
- Détection des tests instables (flaky)
|
|
23
|
+
- Chemins critiques non testés
|
|
24
|
+
|
|
25
|
+
3. **Rapport Généré**
|
|
26
|
+
- Rapport de couverture
|
|
27
|
+
- Tests manquants
|
|
28
|
+
- Score de qualité des tests
|
|
29
|
+
- Recommandations
|
|
30
|
+
|
|
31
|
+
## Comment Utiliser
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
# Lancer tous les tests avec couverture
|
|
35
|
+
npm run test:coverage
|
|
36
|
+
|
|
37
|
+
# Mode watch
|
|
38
|
+
npm run test:watch
|
|
39
|
+
|
|
40
|
+
# Mode UI
|
|
41
|
+
npm run test:ui
|
|
42
|
+
|
|
43
|
+
# Tests E2E
|
|
44
|
+
npm run test:e2e
|
|
45
|
+
```
|
|
11
46
|
|
|
12
47
|
## Mode Plan
|
|
13
48
|
|
|
14
49
|
> Le mode plan est activé automatiquement lorsque le périmètre couvre plusieurs modules ou nécessite une investigation transversale.
|
|
15
50
|
|
|
16
|
-
##
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
- [ ] Coverage statements ≥ 80%
|
|
47
|
-
- [ ] Coverage branches ≥ 75%
|
|
48
|
-
- [ ] Coverage functions ≥ 80%
|
|
49
|
-
- [ ] Coverage lines ≥ 80%
|
|
50
|
-
- [ ] Fichiers critiques couverts à >90%
|
|
51
|
-
- [ ] Pas de fichiers importants non testés
|
|
52
|
-
- [ ] Tendance d'amélioration du coverage
|
|
53
|
-
|
|
54
|
-
**Qualité des tests unitaires (5 points)**
|
|
55
|
-
- [ ] Tests co-localisés avec le code (__tests__ ou .test.tsx)
|
|
56
|
-
- [ ] Un fichier de test par composant/hook/utilitaire
|
|
57
|
-
- [ ] Conventions de nommage : *.test.tsx, *.spec.tsx
|
|
58
|
-
- [ ] Tests isolés et indépendants
|
|
59
|
-
- [ ] Pas de tests flaky ou skip sans raison
|
|
60
|
-
|
|
61
|
-
### Étape 4 : Vérification des bonnes pratiques de test
|
|
62
|
-
|
|
63
|
-
**React Testing Library (4 points)**
|
|
64
|
-
- [ ] Tests basés sur le comportement utilisateur (not implementation)
|
|
65
|
-
- [ ] Queries prioritaires : getByRole, getByLabelText, getByText
|
|
66
|
-
- [ ] Pas d'usage excessif de getByTestId
|
|
67
|
-
- [ ] userEvent utilisé pour les interactions
|
|
68
|
-
- [ ] Assertions sur les éléments accessibles
|
|
69
|
-
- [ ] waitFor pour les opérations asynchrones
|
|
70
|
-
|
|
71
|
-
### Étape 5 : Analyse des types de tests
|
|
72
|
-
|
|
73
|
-
Pour un échantillon représentatif :
|
|
74
|
-
- Identifier tests unitaires vs tests d'intégration
|
|
75
|
-
- Vérifier présence de tests pour :
|
|
76
|
-
- Composants UI (rendu, props, events)
|
|
77
|
-
- Hooks personnalisés
|
|
78
|
-
- Fonctions utilitaires
|
|
79
|
-
- Services/API calls (mocks)
|
|
80
|
-
- Formulaires et validation
|
|
81
|
-
- Gestion d'erreurs
|
|
82
|
-
- Évaluer la qualité des assertions
|
|
83
|
-
- Vérifier les mocks et stubs (MSW recommandé)
|
|
84
|
-
|
|
85
|
-
### Étape 6 : Calcul du score
|
|
86
|
-
|
|
87
|
-
**Score sur 25 points :**
|
|
88
|
-
- Infrastructure de test : 5 points
|
|
89
|
-
- Configuration du coverage : 4 points
|
|
90
|
-
- Coverage global : 7 points
|
|
91
|
-
- Qualité des tests unitaires : 5 points
|
|
92
|
-
- React Testing Library : 4 points
|
|
93
|
-
|
|
94
|
-
### Étape 7 : Exécution des tests et analyse
|
|
95
|
-
|
|
96
|
-
Exécuter les commandes :
|
|
51
|
+
## Analyse de la Couverture de Tests
|
|
52
|
+
|
|
53
|
+
### Objectifs de Couverture
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
// vitest.config.ts
|
|
57
|
+
export default defineConfig({
|
|
58
|
+
test: {
|
|
59
|
+
coverage: {
|
|
60
|
+
provider: 'v8',
|
|
61
|
+
reporter: ['text', 'json', 'html', 'lcov'],
|
|
62
|
+
lines: 80,
|
|
63
|
+
functions: 80,
|
|
64
|
+
branches: 75,
|
|
65
|
+
statements: 80,
|
|
66
|
+
exclude: [
|
|
67
|
+
'node_modules/',
|
|
68
|
+
'src/test/',
|
|
69
|
+
'**/*.test.{ts,tsx}',
|
|
70
|
+
'**/*.spec.{ts,tsx}',
|
|
71
|
+
'**/*.d.ts',
|
|
72
|
+
'vite.config.ts'
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Vérifier la Couverture
|
|
80
|
+
|
|
97
81
|
```bash
|
|
98
|
-
#
|
|
99
|
-
npm run test:coverage
|
|
82
|
+
# Générer le rapport de couverture
|
|
83
|
+
npm run test:coverage
|
|
84
|
+
|
|
85
|
+
# Visualiser le rapport HTML
|
|
86
|
+
open coverage/index.html
|
|
87
|
+
|
|
88
|
+
# Vérifier un seuil spécifique
|
|
89
|
+
npm run test:coverage -- --coverage.lines=90
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Types de Tests
|
|
93
|
+
|
|
94
|
+
### 1. Tests Unitaires (70% des tests)
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
// Button.test.tsx
|
|
98
|
+
import { render, screen } from '@testing-library/react';
|
|
99
|
+
import { userEvent } from '@testing-library/user-event';
|
|
100
|
+
import { Button } from './Button';
|
|
101
|
+
|
|
102
|
+
describe('Button', () => {
|
|
103
|
+
it('should render with text', () => {
|
|
104
|
+
render(<Button>Click me</Button>);
|
|
105
|
+
expect(screen.getByRole('button')).toHaveTextContent('Click me');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should call onClick when clicked', async () => {
|
|
109
|
+
const handleClick = vi.fn();
|
|
110
|
+
const user = userEvent.setup();
|
|
111
|
+
|
|
112
|
+
render(<Button onClick={handleClick}>Click me</Button>);
|
|
113
|
+
await user.click(screen.getByRole('button'));
|
|
114
|
+
|
|
115
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('should be disabled when disabled prop is true', () => {
|
|
119
|
+
render(<Button disabled>Click me</Button>);
|
|
120
|
+
expect(screen.getByRole('button')).toBeDisabled();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 2. Tests d'Intégration (20% des tests)
|
|
100
126
|
|
|
101
|
-
|
|
127
|
+
```typescript
|
|
128
|
+
// UserManagement.integration.test.tsx
|
|
129
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
130
|
+
import { userEvent } from '@testing-library/user-event';
|
|
131
|
+
import { UserManagement } from './UserManagement';
|
|
132
|
+
|
|
133
|
+
describe('UserManagement Integration', () => {
|
|
134
|
+
it('should complete full user creation flow', async () => {
|
|
135
|
+
const user = userEvent.setup();
|
|
136
|
+
render(<UserManagement />);
|
|
137
|
+
|
|
138
|
+
// Attendre le chargement
|
|
139
|
+
await waitFor(() => {
|
|
140
|
+
expect(screen.getByText('John Doe')).toBeInTheDocument();
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Cliquer sur le bouton d'ajout
|
|
144
|
+
await user.click(screen.getByRole('button', { name: /add user/i }));
|
|
145
|
+
|
|
146
|
+
// Remplir le formulaire
|
|
147
|
+
await user.type(screen.getByLabelText(/name/i), 'New User');
|
|
148
|
+
await user.type(screen.getByLabelText(/email/i), 'new@example.com');
|
|
149
|
+
|
|
150
|
+
// Soumettre
|
|
151
|
+
await user.click(screen.getByRole('button', { name: /save/i }));
|
|
152
|
+
|
|
153
|
+
// Vérifier
|
|
154
|
+
await waitFor(() => {
|
|
155
|
+
expect(screen.getByText('New User')).toBeInTheDocument();
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 3. Tests E2E (10% des tests)
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// auth.spec.ts (Playwright)
|
|
165
|
+
import { test, expect } from '@playwright/test';
|
|
166
|
+
|
|
167
|
+
test.describe('Authentication', () => {
|
|
168
|
+
test('should login successfully', async ({ page }) => {
|
|
169
|
+
await page.goto('/');
|
|
170
|
+
await page.click('text=Login');
|
|
171
|
+
|
|
172
|
+
await page.fill('input[name="email"]', 'user@example.com');
|
|
173
|
+
await page.fill('input[name="password"]', 'password123');
|
|
174
|
+
await page.click('button[type="submit"]');
|
|
175
|
+
|
|
176
|
+
await expect(page).toHaveURL('/dashboard');
|
|
177
|
+
await expect(page.locator('text=Welcome')).toBeVisible();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Vérifications de Qualité des Tests
|
|
183
|
+
|
|
184
|
+
### 1. Pattern AAA
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// ✅ BON - Arrange, Act, Assert
|
|
188
|
+
it('should increment counter', async () => {
|
|
189
|
+
// Arrange
|
|
190
|
+
const user = userEvent.setup();
|
|
191
|
+
render(<Counter initialCount={0} />);
|
|
192
|
+
|
|
193
|
+
// Act
|
|
194
|
+
await user.click(screen.getByRole('button', { name: /increment/i }));
|
|
195
|
+
|
|
196
|
+
// Assert
|
|
197
|
+
expect(screen.getByText('Count: 1')).toBeInTheDocument();
|
|
198
|
+
});
|
|
102
199
|
```
|
|
103
200
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
-
|
|
108
|
-
|
|
201
|
+
### 2. Tester le Comportement, pas l'Implémentation
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
// ❌ MAUVAIS - Tester l'implémentation
|
|
205
|
+
it('should call setState', () => {
|
|
206
|
+
const setStateSpy = vi.spyOn(React, 'useState');
|
|
207
|
+
// ...
|
|
208
|
+
});
|
|
109
209
|
|
|
110
|
-
|
|
210
|
+
// ✅ BON - Tester le comportement
|
|
211
|
+
it('should display incremented count', async () => {
|
|
212
|
+
const user = userEvent.setup();
|
|
213
|
+
render(<Counter />);
|
|
111
214
|
|
|
112
|
-
|
|
215
|
+
await user.click(screen.getByRole('button', { name: /increment/i }));
|
|
216
|
+
|
|
217
|
+
expect(screen.getByText('Count: 1')).toBeInTheDocument();
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 3. Noms de Tests Descriptifs
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// ❌ MAUVAIS - Noms vagues
|
|
225
|
+
it('works');
|
|
226
|
+
it('test 1');
|
|
227
|
+
it('should render');
|
|
228
|
+
|
|
229
|
+
// ✅ BON - Noms descriptifs
|
|
230
|
+
it('should display user name when user data is loaded');
|
|
231
|
+
it('should show error message when email is invalid');
|
|
232
|
+
it('should disable submit button while form is submitting');
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### 4. Priorité des Requêtes
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// ✅ BON - Requêtes accessibles (meilleures)
|
|
239
|
+
screen.getByRole('button', { name: /submit/i });
|
|
240
|
+
screen.getByLabelText(/email/i);
|
|
241
|
+
screen.getByText(/welcome/i);
|
|
242
|
+
|
|
243
|
+
// ⚠️ ACCEPTABLE - Requêtes sémantiques
|
|
244
|
+
screen.getByAltText(/profile/i);
|
|
245
|
+
screen.getByTitle(/close/i);
|
|
246
|
+
|
|
247
|
+
// ❌ ÉVITER - Test IDs (en dernier recours)
|
|
248
|
+
screen.getByTestId('custom-element');
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Organisation des Tests
|
|
252
|
+
|
|
253
|
+
### Structure des Dossiers
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
src/
|
|
257
|
+
├── components/
|
|
258
|
+
│ └── Button/
|
|
259
|
+
│ ├── Button.tsx
|
|
260
|
+
│ ├── Button.test.tsx # Tests unitaires
|
|
261
|
+
│ └── Button.stories.tsx # Storybook
|
|
262
|
+
│
|
|
263
|
+
├── features/
|
|
264
|
+
│ └── users/
|
|
265
|
+
│ ├── components/
|
|
266
|
+
│ │ └── UserList/
|
|
267
|
+
│ │ ├── UserList.tsx
|
|
268
|
+
│ │ └── UserList.test.tsx
|
|
269
|
+
│ ├── hooks/
|
|
270
|
+
│ │ └── useUsers.test.ts
|
|
271
|
+
│ └── UserManagement.integration.test.tsx # Intégration
|
|
272
|
+
│
|
|
273
|
+
├── test/
|
|
274
|
+
│ ├── setup.ts # Configuration des tests
|
|
275
|
+
│ ├── mocks/
|
|
276
|
+
│ │ └── handlers.ts # Handlers MSW
|
|
277
|
+
│ └── utils/
|
|
278
|
+
│ └── test-utils.tsx # Utilitaires de test
|
|
279
|
+
│
|
|
280
|
+
└── e2e/ # Tests E2E
|
|
281
|
+
├── auth.spec.ts
|
|
282
|
+
└── users.spec.ts
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Utilitaires de Test
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
// test/utils/test-utils.tsx
|
|
289
|
+
import { render, RenderOptions } from '@testing-library/react';
|
|
290
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
291
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
292
|
+
|
|
293
|
+
const AllProviders = ({ children }: { children: React.ReactNode }) => {
|
|
294
|
+
const queryClient = new QueryClient({
|
|
295
|
+
defaultOptions: {
|
|
296
|
+
queries: { retry: false },
|
|
297
|
+
mutations: { retry: false }
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
return (
|
|
302
|
+
<QueryClientProvider client={queryClient}>
|
|
303
|
+
<BrowserRouter>{children}</BrowserRouter>
|
|
304
|
+
</QueryClientProvider>
|
|
305
|
+
);
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
export const renderWithProviders = (
|
|
309
|
+
ui: React.ReactElement,
|
|
310
|
+
options?: Omit<RenderOptions, 'wrapper'>
|
|
311
|
+
) => render(ui, { wrapper: AllProviders, ...options });
|
|
312
|
+
|
|
313
|
+
export * from '@testing-library/react';
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Problèmes de Test Courants
|
|
317
|
+
|
|
318
|
+
### Problème 1 : Tests Instables (Flaky)
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
// ❌ MAUVAIS - Condition de course
|
|
322
|
+
it('should load data', () => {
|
|
323
|
+
render(<DataComponent />);
|
|
324
|
+
expect(screen.getByText('Data loaded')).toBeInTheDocument();
|
|
325
|
+
// Échoue de façon aléatoire si les données chargent lentement
|
|
326
|
+
});
|
|
327
|
+
|
|
328
|
+
// ✅ BON - Attendre les données
|
|
329
|
+
it('should load data', async () => {
|
|
330
|
+
render(<DataComponent />);
|
|
331
|
+
await waitFor(() => {
|
|
332
|
+
expect(screen.getByText('Data loaded')).toBeInTheDocument();
|
|
333
|
+
});
|
|
334
|
+
});
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Problème 2 : Avertissements Act Manquants
|
|
338
|
+
|
|
339
|
+
```typescript
|
|
340
|
+
// ❌ MAUVAIS - Mise à jour d'état en dehors de act
|
|
341
|
+
it('should update count', () => {
|
|
342
|
+
const { result } = renderHook(() => useCounter());
|
|
343
|
+
result.current.increment(); // Avertissement !
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
// ✅ BON - Envelopper dans act
|
|
347
|
+
it('should update count', () => {
|
|
348
|
+
const { result } = renderHook(() => useCounter());
|
|
349
|
+
act(() => {
|
|
350
|
+
result.current.increment();
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### Problème 3 : Nettoyage Non Effectué
|
|
356
|
+
|
|
357
|
+
```typescript
|
|
358
|
+
// ✅ BON - Nettoyage automatique
|
|
359
|
+
import { cleanup } from '@testing-library/react';
|
|
360
|
+
|
|
361
|
+
afterEach(() => {
|
|
362
|
+
cleanup();
|
|
363
|
+
});
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## MSW (Mock Service Worker)
|
|
367
|
+
|
|
368
|
+
### Configuration
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
// test/mocks/handlers.ts
|
|
372
|
+
import { http, HttpResponse } from 'msw';
|
|
373
|
+
|
|
374
|
+
export const handlers = [
|
|
375
|
+
http.get('/api/users', () => {
|
|
376
|
+
return HttpResponse.json([
|
|
377
|
+
{ id: '1', name: 'John Doe' },
|
|
378
|
+
{ id: '2', name: 'Jane Smith' }
|
|
379
|
+
]);
|
|
380
|
+
}),
|
|
381
|
+
|
|
382
|
+
http.post('/api/users', async ({ request }) => {
|
|
383
|
+
const newUser = await request.json();
|
|
384
|
+
return HttpResponse.json({ id: '3', ...newUser }, { status: 201 });
|
|
385
|
+
})
|
|
386
|
+
];
|
|
387
|
+
|
|
388
|
+
// test/mocks/server.ts
|
|
389
|
+
import { setupServer } from 'msw/node';
|
|
390
|
+
import { handlers } from './handlers';
|
|
391
|
+
|
|
392
|
+
export const server = setupServer(...handlers);
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Utilisation
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
// test/setup.ts
|
|
399
|
+
import { beforeAll, afterEach, afterAll } from 'vitest';
|
|
400
|
+
import { server } from './mocks/server';
|
|
401
|
+
|
|
402
|
+
beforeAll(() => server.listen());
|
|
403
|
+
afterEach(() => server.resetHandlers());
|
|
404
|
+
afterAll(() => server.close());
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
## Tests de Performance
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
// Vérifier les performances de rendu
|
|
411
|
+
it('should render list efficiently', () => {
|
|
412
|
+
const start = performance.now();
|
|
413
|
+
|
|
414
|
+
render(<LargeList items={items} />);
|
|
415
|
+
|
|
416
|
+
const duration = performance.now() - start;
|
|
417
|
+
expect(duration).toBeLessThan(100); // ms
|
|
418
|
+
});
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
## Rapports de Tests
|
|
422
|
+
|
|
423
|
+
### Rapport de Couverture
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# Générer le rapport HTML
|
|
427
|
+
npm run test:coverage
|
|
428
|
+
|
|
429
|
+
# Visualiser le rapport
|
|
430
|
+
open coverage/index.html
|
|
431
|
+
|
|
432
|
+
# CI : Upload vers Codecov
|
|
433
|
+
bash <(curl -s https://codecov.io/bash)
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Rapport de Conformité
|
|
113
437
|
|
|
114
438
|
```
|
|
115
439
|
═══════════════════════════════════════════════════
|
|
@@ -212,10 +536,60 @@ Anti-patterns détectés :
|
|
|
212
536
|
• https://testing-library.com/docs/queries/about/#priority
|
|
213
537
|
```
|
|
214
538
|
|
|
215
|
-
###
|
|
539
|
+
### Résultats de Tests en CI
|
|
540
|
+
|
|
541
|
+
```yaml
|
|
542
|
+
# .github/workflows/test.yml
|
|
543
|
+
name: Tests
|
|
544
|
+
|
|
545
|
+
on: [push, pull_request]
|
|
546
|
+
|
|
547
|
+
jobs:
|
|
548
|
+
test:
|
|
549
|
+
runs-on: ubuntu-latest
|
|
550
|
+
steps:
|
|
551
|
+
- uses: actions/checkout@v3
|
|
552
|
+
- uses: actions/setup-node@v3
|
|
553
|
+
|
|
554
|
+
- name: Install dependencies
|
|
555
|
+
run: npm ci
|
|
556
|
+
|
|
557
|
+
- name: Run tests
|
|
558
|
+
run: npm run test:coverage
|
|
559
|
+
|
|
560
|
+
- name: Upload coverage
|
|
561
|
+
uses: codecov/codecov-action@v3
|
|
562
|
+
```
|
|
216
563
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
-
|
|
220
|
-
-
|
|
221
|
-
-
|
|
564
|
+
## Checklist de Tests
|
|
565
|
+
|
|
566
|
+
- [ ] Tests unitaires pour tous les composants
|
|
567
|
+
- [ ] Tests unitaires pour tous les hooks
|
|
568
|
+
- [ ] Tests unitaires pour tous les utilitaires
|
|
569
|
+
- [ ] Tests d'intégration pour les features
|
|
570
|
+
- [ ] Tests E2E pour les parcours critiques
|
|
571
|
+
- [ ] Couverture > 80%
|
|
572
|
+
- [ ] Pas de tests instables (flaky)
|
|
573
|
+
- [ ] Tests rapides (< 1s chacun)
|
|
574
|
+
- [ ] MSW pour le mocking des API
|
|
575
|
+
- [ ] Utilitaires de test extraits
|
|
576
|
+
- [ ] Tests suivent le pattern AAA
|
|
577
|
+
- [ ] Tests ont des noms descriptifs
|
|
578
|
+
- [ ] Tests utilisent les requêtes accessibles
|
|
579
|
+
|
|
580
|
+
## Outils
|
|
581
|
+
|
|
582
|
+
- **Vitest** : Exécuteur de tests unitaires
|
|
583
|
+
- **React Testing Library** : Test de composants
|
|
584
|
+
- **Playwright** : Tests E2E
|
|
585
|
+
- **MSW** : Mocking des API
|
|
586
|
+
- **Testing Library User Event** : Interactions utilisateur
|
|
587
|
+
- **Codecov** : Rapport de couverture
|
|
588
|
+
|
|
589
|
+
## Ressources
|
|
590
|
+
|
|
591
|
+
- [React Testing Library](https://testing-library.com/react)
|
|
592
|
+
- [Vitest Documentation](https://vitest.dev/)
|
|
593
|
+
- [Playwright Documentation](https://playwright.dev/)
|
|
594
|
+
- [MSW Documentation](https://mswjs.io/)
|
|
595
|
+
- [Testing Best Practices](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
|