@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,70 +1,58 @@
|
|
|
1
1
|
---
|
|
2
|
-
description:
|
|
2
|
+
description: Verificación de la estrategia de pruebas
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
#
|
|
5
|
+
# Verificación de la Estrategia de Pruebas
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Verifica que la aplicación React tenga una cobertura de pruebas completa y siga las mejores prácticas de testing.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Qué Hace Este Comando
|
|
10
10
|
|
|
11
|
-
1. **
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
11
|
+
1. **Análisis de Pruebas**
|
|
12
|
+
- Verificar la cobertura de pruebas
|
|
13
|
+
- Comprobar la calidad de las pruebas
|
|
14
|
+
- Validar los patrones de testing
|
|
15
|
+
- Verificar la organización de las pruebas
|
|
16
|
+
- Analizar el rendimiento de las pruebas
|
|
17
17
|
|
|
18
|
-
2. **
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
18
|
+
2. **Métricas Medidas**
|
|
19
|
+
- Cobertura de código (líneas, funciones, ramas)
|
|
20
|
+
- Recuento de pruebas por tipo (unitarias, integración, e2e)
|
|
21
|
+
- Tiempo de ejecución de las pruebas
|
|
22
|
+
- Detección de pruebas inestables (flaky tests)
|
|
23
|
+
- Rutas críticas sin pruebas
|
|
24
24
|
|
|
25
|
-
3. **
|
|
26
|
-
-
|
|
27
|
-
-
|
|
25
|
+
3. **Informe Generado**
|
|
26
|
+
- Informe de cobertura
|
|
27
|
+
- Pruebas faltantes
|
|
28
|
+
- Puntuación de calidad de pruebas
|
|
28
29
|
- Recomendaciones
|
|
29
|
-
- Tendencias en el tiempo
|
|
30
30
|
|
|
31
|
-
##
|
|
32
|
-
|
|
33
|
-
> El modo plan se activa automáticamente cuando el alcance abarca varios módulos o requiere una investigación transversal.
|
|
34
|
-
|
|
35
|
-
## Ejecutar Tests
|
|
36
|
-
|
|
37
|
-
### Modo Desarrollo
|
|
31
|
+
## Cómo Usar
|
|
38
32
|
|
|
39
33
|
```bash
|
|
40
|
-
#
|
|
41
|
-
npm run test
|
|
34
|
+
# Ejecutar todas las pruebas con cobertura
|
|
35
|
+
npm run test:coverage
|
|
42
36
|
|
|
43
|
-
#
|
|
44
|
-
npm run test:
|
|
37
|
+
# Modo observación
|
|
38
|
+
npm run test:watch
|
|
45
39
|
|
|
46
|
-
#
|
|
40
|
+
# Modo UI
|
|
47
41
|
npm run test:ui
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Generar Cobertura
|
|
51
42
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
43
|
+
# Pruebas E2E
|
|
44
|
+
npm run test:e2e
|
|
45
|
+
```
|
|
55
46
|
|
|
56
|
-
|
|
57
|
-
npm run test:coverage -- --reporter=html
|
|
47
|
+
## Modo Plan
|
|
58
48
|
|
|
59
|
-
|
|
60
|
-
npm run test:coverage -- --changed
|
|
61
|
-
```
|
|
49
|
+
> El modo plan se activa automáticamente cuando el alcance abarca varios módulos o requiere una investigación transversal.
|
|
62
50
|
|
|
63
|
-
##
|
|
51
|
+
## Análisis de Cobertura de Pruebas
|
|
64
52
|
|
|
65
|
-
###
|
|
53
|
+
### Objetivos de Cobertura
|
|
66
54
|
|
|
67
|
-
```
|
|
55
|
+
```json
|
|
68
56
|
// vitest.config.ts
|
|
69
57
|
export default defineConfig({
|
|
70
58
|
test: {
|
|
@@ -80,24 +68,30 @@ export default defineConfig({
|
|
|
80
68
|
'src/test/',
|
|
81
69
|
'**/*.test.{ts,tsx}',
|
|
82
70
|
'**/*.spec.{ts,tsx}',
|
|
83
|
-
'
|
|
71
|
+
'**/*.d.ts',
|
|
72
|
+
'vite.config.ts'
|
|
84
73
|
]
|
|
85
74
|
}
|
|
86
75
|
}
|
|
87
76
|
});
|
|
88
77
|
```
|
|
89
78
|
|
|
90
|
-
###
|
|
79
|
+
### Verificar la Cobertura
|
|
91
80
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
- **Paginas**: 70%+
|
|
96
|
-
- **Configuracion**: 50%+
|
|
81
|
+
```bash
|
|
82
|
+
# Generar informe de cobertura
|
|
83
|
+
npm run test:coverage
|
|
97
84
|
|
|
98
|
-
|
|
85
|
+
# Ver informe HTML
|
|
86
|
+
open coverage/index.html
|
|
99
87
|
|
|
100
|
-
|
|
88
|
+
# Verificar umbral específico
|
|
89
|
+
npm run test:coverage -- --coverage.lines=90
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Tipos de Pruebas
|
|
93
|
+
|
|
94
|
+
### 1. Pruebas Unitarias (70% de las pruebas)
|
|
101
95
|
|
|
102
96
|
```typescript
|
|
103
97
|
// Button.test.tsx
|
|
@@ -108,22 +102,27 @@ import { Button } from './Button';
|
|
|
108
102
|
describe('Button', () => {
|
|
109
103
|
it('should render with text', () => {
|
|
110
104
|
render(<Button>Click me</Button>);
|
|
111
|
-
expect(screen.
|
|
105
|
+
expect(screen.getByRole('button')).toHaveTextContent('Click me');
|
|
112
106
|
});
|
|
113
107
|
|
|
114
108
|
it('should call onClick when clicked', async () => {
|
|
115
109
|
const handleClick = vi.fn();
|
|
116
110
|
const user = userEvent.setup();
|
|
117
111
|
|
|
118
|
-
render(<Button onClick={handleClick}>Click</Button>);
|
|
112
|
+
render(<Button onClick={handleClick}>Click me</Button>);
|
|
119
113
|
await user.click(screen.getByRole('button'));
|
|
120
114
|
|
|
121
115
|
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
122
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
|
+
});
|
|
123
122
|
});
|
|
124
123
|
```
|
|
125
124
|
|
|
126
|
-
###
|
|
125
|
+
### 2. Pruebas de Integración (20% de las pruebas)
|
|
127
126
|
|
|
128
127
|
```typescript
|
|
129
128
|
// UserManagement.integration.test.tsx
|
|
@@ -136,22 +135,22 @@ describe('UserManagement Integration', () => {
|
|
|
136
135
|
const user = userEvent.setup();
|
|
137
136
|
render(<UserManagement />);
|
|
138
137
|
|
|
139
|
-
// Esperar carga
|
|
138
|
+
// Esperar la carga
|
|
140
139
|
await waitFor(() => {
|
|
141
140
|
expect(screen.getByText('John Doe')).toBeInTheDocument();
|
|
142
141
|
});
|
|
143
142
|
|
|
144
|
-
// Hacer clic en agregar
|
|
143
|
+
// Hacer clic en el botón agregar
|
|
145
144
|
await user.click(screen.getByRole('button', { name: /add user/i }));
|
|
146
145
|
|
|
147
|
-
//
|
|
146
|
+
// Rellenar el formulario
|
|
148
147
|
await user.type(screen.getByLabelText(/name/i), 'New User');
|
|
149
148
|
await user.type(screen.getByLabelText(/email/i), 'new@example.com');
|
|
150
149
|
|
|
151
150
|
// Enviar
|
|
152
151
|
await user.click(screen.getByRole('button', { name: /save/i }));
|
|
153
152
|
|
|
154
|
-
// Verificar
|
|
153
|
+
// Verificar
|
|
155
154
|
await waitFor(() => {
|
|
156
155
|
expect(screen.getByText('New User')).toBeInTheDocument();
|
|
157
156
|
});
|
|
@@ -159,154 +158,214 @@ describe('UserManagement Integration', () => {
|
|
|
159
158
|
});
|
|
160
159
|
```
|
|
161
160
|
|
|
162
|
-
###
|
|
161
|
+
### 3. Pruebas E2E (10% de las pruebas)
|
|
163
162
|
|
|
164
163
|
```typescript
|
|
165
|
-
//
|
|
164
|
+
// auth.spec.ts (Playwright)
|
|
166
165
|
import { test, expect } from '@playwright/test';
|
|
167
166
|
|
|
168
167
|
test.describe('Authentication', () => {
|
|
169
168
|
test('should login successfully', async ({ page }) => {
|
|
170
169
|
await page.goto('/');
|
|
171
|
-
|
|
172
170
|
await page.click('text=Login');
|
|
171
|
+
|
|
173
172
|
await page.fill('input[name="email"]', 'user@example.com');
|
|
174
173
|
await page.fill('input[name="password"]', 'password123');
|
|
175
174
|
await page.click('button[type="submit"]');
|
|
176
175
|
|
|
177
176
|
await expect(page).toHaveURL('/dashboard');
|
|
178
|
-
await expect(page.locator('text=Welcome
|
|
177
|
+
await expect(page.locator('text=Welcome')).toBeVisible();
|
|
179
178
|
});
|
|
180
179
|
});
|
|
181
180
|
```
|
|
182
181
|
|
|
183
|
-
##
|
|
182
|
+
## Verificaciones de Calidad de Pruebas
|
|
184
183
|
|
|
185
|
-
###
|
|
184
|
+
### 1. Patrón AAA
|
|
186
185
|
|
|
187
186
|
```typescript
|
|
188
|
-
// Arrange (Preparar
|
|
187
|
+
// ✅ BIEN - Arrange, Act, Assert (Preparar, Actuar, Verificar)
|
|
189
188
|
it('should increment counter', async () => {
|
|
190
|
-
// Arrange
|
|
189
|
+
// Arrange (Preparar)
|
|
191
190
|
const user = userEvent.setup();
|
|
192
191
|
render(<Counter initialCount={0} />);
|
|
193
192
|
|
|
194
|
-
// Act
|
|
193
|
+
// Act (Actuar)
|
|
195
194
|
await user.click(screen.getByRole('button', { name: /increment/i }));
|
|
196
195
|
|
|
197
|
-
// Assert
|
|
196
|
+
// Assert (Verificar)
|
|
198
197
|
expect(screen.getByText('Count: 1')).toBeInTheDocument();
|
|
199
198
|
});
|
|
200
199
|
```
|
|
201
200
|
|
|
202
|
-
###
|
|
201
|
+
### 2. Probar el Comportamiento, No la Implementación
|
|
203
202
|
|
|
204
203
|
```typescript
|
|
205
|
-
//
|
|
204
|
+
// ❌ MAL - Probar la implementación
|
|
205
|
+
it('should call setState', () => {
|
|
206
|
+
const setStateSpy = vi.spyOn(React, 'useState');
|
|
207
|
+
// ...
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// ✅ BIEN - Probar el comportamiento
|
|
211
|
+
it('should display incremented count', async () => {
|
|
212
|
+
const user = userEvent.setup();
|
|
213
|
+
render(<Counter />);
|
|
214
|
+
|
|
215
|
+
await user.click(screen.getByRole('button', { name: /increment/i }));
|
|
216
|
+
|
|
217
|
+
expect(screen.getByText('Count: 1')).toBeInTheDocument();
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 3. Nombres de Prueba Descriptivos
|
|
222
|
+
|
|
223
|
+
```typescript
|
|
224
|
+
// ❌ MAL - Nombres vagos
|
|
225
|
+
it('works');
|
|
226
|
+
it('test 1');
|
|
227
|
+
it('should render');
|
|
228
|
+
|
|
229
|
+
// ✅ BIEN - Nombres descriptivos
|
|
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. Prioridad de Consultas
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
// ✅ BIEN - Consultas accesibles (las mejores)
|
|
206
239
|
screen.getByRole('button', { name: /submit/i });
|
|
207
240
|
screen.getByLabelText(/email/i);
|
|
208
|
-
screen.getByPlaceholderText(/search/i);
|
|
209
241
|
screen.getByText(/welcome/i);
|
|
210
242
|
|
|
211
|
-
//
|
|
212
|
-
screen.getByAltText(/profile
|
|
243
|
+
// ⚠️ ACEPTABLE - Consultas semánticas
|
|
244
|
+
screen.getByAltText(/profile/i);
|
|
213
245
|
screen.getByTitle(/close/i);
|
|
214
246
|
|
|
215
|
-
//
|
|
247
|
+
// ❌ EVITAR - IDs de prueba (último recurso)
|
|
216
248
|
screen.getByTestId('custom-element');
|
|
217
249
|
```
|
|
218
250
|
|
|
219
|
-
|
|
251
|
+
## Organización de Pruebas
|
|
252
|
+
|
|
253
|
+
### Estructura de Carpetas
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
src/
|
|
257
|
+
├── components/
|
|
258
|
+
│ └── Button/
|
|
259
|
+
│ ├── Button.tsx
|
|
260
|
+
│ ├── Button.test.tsx # Pruebas unitarias
|
|
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 # Integración
|
|
272
|
+
│
|
|
273
|
+
├── test/
|
|
274
|
+
│ ├── setup.ts # Configuración de pruebas
|
|
275
|
+
│ ├── mocks/
|
|
276
|
+
│ │ └── handlers.ts # Manejadores MSW
|
|
277
|
+
│ └── utils/
|
|
278
|
+
│ └── test-utils.tsx # Utilidades de prueba
|
|
279
|
+
│
|
|
280
|
+
└── e2e/ # Pruebas E2E
|
|
281
|
+
├── auth.spec.ts
|
|
282
|
+
└── users.spec.ts
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Utilidades de Prueba
|
|
220
286
|
|
|
221
287
|
```typescript
|
|
222
|
-
//
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
}
|
|
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
|
+
};
|
|
232
307
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
})
|
|
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';
|
|
237
314
|
```
|
|
238
315
|
|
|
239
|
-
##
|
|
316
|
+
## Problemas Comunes de Pruebas
|
|
240
317
|
|
|
241
|
-
### Tests
|
|
318
|
+
### Problema 1: Pruebas Inestables (Flaky Tests)
|
|
242
319
|
|
|
243
320
|
```typescript
|
|
244
|
-
// ❌ MAL -
|
|
321
|
+
// ❌ MAL - Condición de carrera
|
|
245
322
|
it('should load data', () => {
|
|
246
323
|
render(<DataComponent />);
|
|
247
|
-
|
|
248
|
-
// No espera la carga asincrona
|
|
249
324
|
expect(screen.getByText('Data loaded')).toBeInTheDocument();
|
|
325
|
+
// Falla aleatoriamente si los datos tardan en cargar
|
|
250
326
|
});
|
|
251
327
|
|
|
252
|
-
// ✅ BIEN -
|
|
328
|
+
// ✅ BIEN - Esperar los datos
|
|
253
329
|
it('should load data', async () => {
|
|
254
330
|
render(<DataComponent />);
|
|
255
|
-
|
|
256
|
-
// Espera la carga asincrona
|
|
257
331
|
await waitFor(() => {
|
|
258
332
|
expect(screen.getByText('Data loaded')).toBeInTheDocument();
|
|
259
333
|
});
|
|
260
334
|
});
|
|
261
335
|
```
|
|
262
336
|
|
|
263
|
-
###
|
|
337
|
+
### Problema 2: Advertencias de Act Faltante
|
|
264
338
|
|
|
265
339
|
```typescript
|
|
266
|
-
// ❌ MAL -
|
|
267
|
-
it('should update
|
|
268
|
-
const {
|
|
269
|
-
|
|
270
|
-
rerender(<Component value={3} />);
|
|
271
|
-
rerender(<Component value={4} />);
|
|
340
|
+
// ❌ MAL - Actualización de estado fuera de act
|
|
341
|
+
it('should update count', () => {
|
|
342
|
+
const { result } = renderHook(() => useCounter());
|
|
343
|
+
result.current.increment(); // ¡Advertencia!
|
|
272
344
|
});
|
|
273
345
|
|
|
274
|
-
// ✅ BIEN -
|
|
275
|
-
it('should update
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
expect(screen.getByText('Updated')).toBeInTheDocument();
|
|
346
|
+
// ✅ BIEN - Envolver en act
|
|
347
|
+
it('should update count', () => {
|
|
348
|
+
const { result } = renderHook(() => useCounter());
|
|
349
|
+
act(() => {
|
|
350
|
+
result.current.increment();
|
|
351
|
+
});
|
|
281
352
|
});
|
|
282
353
|
```
|
|
283
354
|
|
|
284
|
-
|
|
355
|
+
### Problema 3: No Limpiar Después de las Pruebas
|
|
285
356
|
|
|
286
357
|
```typescript
|
|
287
|
-
//
|
|
288
|
-
import {
|
|
289
|
-
import { useCounter } from './useCounter';
|
|
290
|
-
|
|
291
|
-
describe('useCounter', () => {
|
|
292
|
-
it('should initialize with default value', () => {
|
|
293
|
-
const { result } = renderHook(() => useCounter());
|
|
294
|
-
expect(result.current.count).toBe(0);
|
|
295
|
-
});
|
|
296
|
-
|
|
297
|
-
it('should increment count', () => {
|
|
298
|
-
const { result } = renderHook(() => useCounter());
|
|
299
|
-
|
|
300
|
-
act(() => {
|
|
301
|
-
result.current.increment();
|
|
302
|
-
});
|
|
358
|
+
// ✅ BIEN - Limpieza automática
|
|
359
|
+
import { cleanup } from '@testing-library/react';
|
|
303
360
|
|
|
304
|
-
|
|
305
|
-
|
|
361
|
+
afterEach(() => {
|
|
362
|
+
cleanup();
|
|
306
363
|
});
|
|
307
364
|
```
|
|
308
365
|
|
|
309
|
-
##
|
|
366
|
+
## MSW (Mock Service Worker)
|
|
367
|
+
|
|
368
|
+
### Configuración
|
|
310
369
|
|
|
311
370
|
```typescript
|
|
312
371
|
// test/mocks/handlers.ts
|
|
@@ -318,6 +377,11 @@ export const handlers = [
|
|
|
318
377
|
{ id: '1', name: 'John Doe' },
|
|
319
378
|
{ id: '2', name: 'Jane Smith' }
|
|
320
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 });
|
|
321
385
|
})
|
|
322
386
|
];
|
|
323
387
|
|
|
@@ -326,20 +390,50 @@ import { setupServer } from 'msw/node';
|
|
|
326
390
|
import { handlers } from './handlers';
|
|
327
391
|
|
|
328
392
|
export const server = setupServer(...handlers);
|
|
393
|
+
```
|
|
329
394
|
|
|
330
|
-
|
|
331
|
-
describe('UserList', () => {
|
|
332
|
-
it('should display users', async () => {
|
|
333
|
-
render(<UserList />);
|
|
395
|
+
### Uso
|
|
334
396
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
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
|
+
## Pruebas de Rendimiento
|
|
408
|
+
|
|
409
|
+
```typescript
|
|
410
|
+
// Verificar el rendimiento de renderizado
|
|
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
|
|
339
418
|
});
|
|
340
419
|
```
|
|
341
420
|
|
|
342
|
-
##
|
|
421
|
+
## Informes de Pruebas
|
|
422
|
+
|
|
423
|
+
### Informe de Cobertura
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# Generar informe HTML
|
|
427
|
+
npm run test:coverage
|
|
428
|
+
|
|
429
|
+
# Ver informe
|
|
430
|
+
open coverage/index.html
|
|
431
|
+
|
|
432
|
+
# CI: Subir a Codecov
|
|
433
|
+
bash <(curl -s https://codecov.io/bash)
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Resultados de Pruebas en CI
|
|
343
437
|
|
|
344
438
|
```yaml
|
|
345
439
|
# .github/workflows/test.yml
|
|
@@ -350,12 +444,9 @@ on: [push, pull_request]
|
|
|
350
444
|
jobs:
|
|
351
445
|
test:
|
|
352
446
|
runs-on: ubuntu-latest
|
|
353
|
-
|
|
354
447
|
steps:
|
|
355
448
|
- uses: actions/checkout@v3
|
|
356
449
|
- uses: actions/setup-node@v3
|
|
357
|
-
with:
|
|
358
|
-
node-version: '22'
|
|
359
450
|
|
|
360
451
|
- name: Install dependencies
|
|
361
452
|
run: npm ci
|
|
@@ -365,34 +456,37 @@ jobs:
|
|
|
365
456
|
|
|
366
457
|
- name: Upload coverage
|
|
367
458
|
uses: codecov/codecov-action@v3
|
|
368
|
-
with:
|
|
369
|
-
files: ./coverage/lcov.info
|
|
370
459
|
```
|
|
371
460
|
|
|
372
|
-
## Lista de
|
|
373
|
-
|
|
374
|
-
- [ ]
|
|
375
|
-
- [ ]
|
|
376
|
-
- [ ]
|
|
377
|
-
- [ ]
|
|
378
|
-
- [ ]
|
|
379
|
-
- [ ]
|
|
380
|
-
- [ ]
|
|
381
|
-
- [ ]
|
|
382
|
-
- [ ]
|
|
383
|
-
- [ ]
|
|
461
|
+
## Lista de Verificación de Pruebas
|
|
462
|
+
|
|
463
|
+
- [ ] Pruebas unitarias para todos los componentes
|
|
464
|
+
- [ ] Pruebas unitarias para todos los hooks
|
|
465
|
+
- [ ] Pruebas unitarias para todas las utilidades
|
|
466
|
+
- [ ] Pruebas de integración para las funcionalidades
|
|
467
|
+
- [ ] Pruebas E2E para los flujos críticos
|
|
468
|
+
- [ ] Cobertura > 80%
|
|
469
|
+
- [ ] Sin pruebas inestables (flaky tests)
|
|
470
|
+
- [ ] Las pruebas son rápidas (< 1s cada una)
|
|
471
|
+
- [ ] MSW para el mocking de API
|
|
472
|
+
- [ ] Utilidades de prueba extraídas
|
|
473
|
+
- [ ] Las pruebas siguen el patrón AAA
|
|
474
|
+
- [ ] Las pruebas tienen nombres descriptivos
|
|
475
|
+
- [ ] Las pruebas usan consultas accesibles
|
|
384
476
|
|
|
385
477
|
## Herramientas
|
|
386
478
|
|
|
387
|
-
- **Vitest
|
|
388
|
-
- **React Testing Library
|
|
389
|
-
- **Playwright
|
|
390
|
-
- **MSW
|
|
391
|
-
- **
|
|
479
|
+
- **Vitest**: Ejecutor de pruebas unitarias
|
|
480
|
+
- **React Testing Library**: Pruebas de componentes
|
|
481
|
+
- **Playwright**: Pruebas E2E
|
|
482
|
+
- **MSW**: Mocking de API
|
|
483
|
+
- **Testing Library User Event**: Interacciones de usuario
|
|
484
|
+
- **Codecov**: Reportes de cobertura
|
|
392
485
|
|
|
393
486
|
## Recursos
|
|
394
487
|
|
|
395
|
-
- [Documentacion Vitest](https://vitest.dev/)
|
|
396
488
|
- [React Testing Library](https://testing-library.com/react)
|
|
397
|
-
- [
|
|
398
|
-
- [
|
|
489
|
+
- [Documentación de Vitest](https://vitest.dev/)
|
|
490
|
+
- [Documentación de Playwright](https://playwright.dev/)
|
|
491
|
+
- [Documentación de MSW](https://mswjs.io/)
|
|
492
|
+
- [Mejores Prácticas de Testing](https://kentcdodds.com/blog/common-mistakes-with-react-testing-library)
|