@arkyn/components 3.0.1-beta.123 → 3.0.1-beta.124
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/TESTING_MAP.md +613 -0
- package/dist/bundle.js +86831 -14006
- package/dist/bundle.umd.cjs +3591 -53
- package/dist/components/mapView/index.d.ts +3 -9
- package/dist/components/mapView/index.d.ts.map +1 -1
- package/dist/components/mapView/index.js +12 -15
- package/dist/components/mapView/mapView.client.d.ts +17 -0
- package/dist/components/mapView/mapView.client.d.ts.map +1 -0
- package/dist/components/mapView/mapView.client.js +51 -0
- package/dist/style.css +1 -1
- package/package.json +5 -1
- package/vitest.setup.ts +1 -0
package/TESTING_MAP.md
ADDED
|
@@ -0,0 +1,613 @@
|
|
|
1
|
+
# 🧪 Mapa de Geração de Testes para Componentes React
|
|
2
|
+
|
|
3
|
+
Este documento serve como guia padronizado para IAs gerarem testes de componentes React utilizando **Vitest** e **React Testing Library**.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📋 Índice
|
|
8
|
+
|
|
9
|
+
1. [Pré-requisitos](#1-pré-requisitos)
|
|
10
|
+
2. [Estrutura de Arquivos](#2-estrutura-de-arquivos)
|
|
11
|
+
3. [Anatomia de um Teste](#3-anatomia-de-um-teste)
|
|
12
|
+
4. [Categorias de Testes](#4-categorias-de-testes)
|
|
13
|
+
5. [Padrões de Nomenclatura](#5-padrões-de-nomenclatura)
|
|
14
|
+
6. [Checklist de Cobertura](#6-checklist-de-cobertura)
|
|
15
|
+
7. [Exemplos Práticos](#7-exemplos-práticos)
|
|
16
|
+
8. [Boas Práticas](#8-boas-práticas)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 1. Pré-requisitos
|
|
21
|
+
|
|
22
|
+
### Dependências necessárias:
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"vitest": "^4.x",
|
|
28
|
+
"@testing-library/react": "^16.x",
|
|
29
|
+
"@testing-library/jest-dom": "^6.x",
|
|
30
|
+
"@testing-library/user-event": "^14.x",
|
|
31
|
+
"jsdom": "^28.x"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Configuração do `vitest.config.ts`:
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { defineConfig } from "vitest/config";
|
|
40
|
+
import react from "@vitejs/plugin-react";
|
|
41
|
+
|
|
42
|
+
export default defineConfig({
|
|
43
|
+
plugins: [react()],
|
|
44
|
+
test: {
|
|
45
|
+
environment: "jsdom",
|
|
46
|
+
globals: true,
|
|
47
|
+
setupFiles: ["./vitest.setup.ts"],
|
|
48
|
+
include: ["src/**/*.{test,spec}.{ts,tsx}"],
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Configuração do `vitest.setup.ts`:
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import "@testing-library/jest-dom/vitest";
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 2. Estrutura de Arquivos
|
|
62
|
+
|
|
63
|
+
### Localização dos testes:
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
src/
|
|
67
|
+
└── components/
|
|
68
|
+
└── [componentName]/
|
|
69
|
+
├── index.tsx # Componente
|
|
70
|
+
├── styles.css # Estilos
|
|
71
|
+
└── index.test.tsx # Testes (mesmo diretório)
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
**OU** centralizado:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
src/
|
|
78
|
+
└── components/
|
|
79
|
+
├── __test__/
|
|
80
|
+
│ └── [componentName].test.tsx
|
|
81
|
+
└── [componentName]/
|
|
82
|
+
├── index.tsx
|
|
83
|
+
└── styles.css
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## 3. Anatomia de um Teste
|
|
89
|
+
|
|
90
|
+
### Estrutura básica do arquivo de teste:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
94
|
+
import { render, screen, fireEvent, waitFor } from "@testing-library/react";
|
|
95
|
+
import userEvent from "@testing-library/user-event";
|
|
96
|
+
|
|
97
|
+
import { ComponentName } from "./index";
|
|
98
|
+
|
|
99
|
+
// ============================================
|
|
100
|
+
// MOCKS (se necessário)
|
|
101
|
+
// ============================================
|
|
102
|
+
vi.mock("../dependency", () => ({
|
|
103
|
+
dependency: vi.fn(),
|
|
104
|
+
}));
|
|
105
|
+
|
|
106
|
+
// ============================================
|
|
107
|
+
// HELPERS/FIXTURES
|
|
108
|
+
// ============================================
|
|
109
|
+
const defaultProps = {
|
|
110
|
+
// props padrão para os testes
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const renderComponent = (props = {}) => {
|
|
114
|
+
return render(<ComponentName {...defaultProps} {...props} />);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
// ============================================
|
|
118
|
+
// TESTES
|
|
119
|
+
// ============================================
|
|
120
|
+
describe("ComponentName", () => {
|
|
121
|
+
beforeEach(() => {
|
|
122
|
+
vi.clearAllMocks();
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Grupo 1: Renderização
|
|
126
|
+
describe("Rendering", () => {
|
|
127
|
+
it("should render correctly with default props", () => {});
|
|
128
|
+
it("should render children when provided", () => {});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Grupo 2: Props
|
|
132
|
+
describe("Props", () => {
|
|
133
|
+
it("should apply custom className", () => {});
|
|
134
|
+
it("should handle variant prop correctly", () => {});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Grupo 3: Interações
|
|
138
|
+
describe("Interactions", () => {
|
|
139
|
+
it("should call onClick when clicked", () => {});
|
|
140
|
+
it("should handle keyboard navigation", () => {});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
// Grupo 4: Estados
|
|
144
|
+
describe("States", () => {
|
|
145
|
+
it("should display loading state", () => {});
|
|
146
|
+
it("should display disabled state", () => {});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Grupo 5: Acessibilidade
|
|
150
|
+
describe("Accessibility", () => {
|
|
151
|
+
it("should have correct ARIA attributes", () => {});
|
|
152
|
+
it("should be focusable", () => {});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## 4. Categorias de Testes
|
|
160
|
+
|
|
161
|
+
### 4.1 Testes de Renderização
|
|
162
|
+
|
|
163
|
+
Verificam se o componente renderiza corretamente.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
describe("Rendering", () => {
|
|
167
|
+
it("should render correctly with default props", () => {
|
|
168
|
+
renderComponent();
|
|
169
|
+
expect(screen.getByRole("button")).toBeInTheDocument();
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("should render children content", () => {
|
|
173
|
+
renderComponent({ children: "Click me" });
|
|
174
|
+
expect(screen.getByText("Click me")).toBeInTheDocument();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("should not render when condition is false", () => {
|
|
178
|
+
renderComponent({ show: false });
|
|
179
|
+
expect(screen.queryByRole("button")).not.toBeInTheDocument();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 4.2 Testes de Props
|
|
185
|
+
|
|
186
|
+
Verificam se as props são aplicadas corretamente.
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
describe("Props", () => {
|
|
190
|
+
it("should apply size prop correctly", () => {
|
|
191
|
+
renderComponent({ size: "lg" });
|
|
192
|
+
expect(screen.getByRole("button")).toHaveClass("lg");
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
it("should apply variant prop correctly", () => {
|
|
196
|
+
renderComponent({ variant: "outline" });
|
|
197
|
+
expect(screen.getByRole("button")).toHaveClass("outline");
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("should merge custom className with base classes", () => {
|
|
201
|
+
renderComponent({ className: "custom-class" });
|
|
202
|
+
expect(screen.getByRole("button")).toHaveClass("custom-class");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("should spread additional HTML attributes", () => {
|
|
206
|
+
renderComponent({ "data-testid": "custom-button", id: "btn-1" });
|
|
207
|
+
expect(screen.getByTestId("custom-button")).toHaveAttribute("id", "btn-1");
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### 4.3 Testes de Interação
|
|
213
|
+
|
|
214
|
+
Verificam eventos e comportamentos do usuário.
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
describe("Interactions", () => {
|
|
218
|
+
it("should call onClick handler when clicked", async () => {
|
|
219
|
+
const handleClick = vi.fn();
|
|
220
|
+
renderComponent({ onClick: handleClick });
|
|
221
|
+
|
|
222
|
+
await userEvent.click(screen.getByRole("button"));
|
|
223
|
+
|
|
224
|
+
expect(handleClick).toHaveBeenCalledTimes(1);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it("should not call onClick when disabled", async () => {
|
|
228
|
+
const handleClick = vi.fn();
|
|
229
|
+
renderComponent({ onClick: handleClick, disabled: true });
|
|
230
|
+
|
|
231
|
+
await userEvent.click(screen.getByRole("button"));
|
|
232
|
+
|
|
233
|
+
expect(handleClick).not.toHaveBeenCalled();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it("should handle double click", async () => {
|
|
237
|
+
const handleDoubleClick = vi.fn();
|
|
238
|
+
renderComponent({ onDoubleClick: handleDoubleClick });
|
|
239
|
+
|
|
240
|
+
await userEvent.dblClick(screen.getByRole("button"));
|
|
241
|
+
|
|
242
|
+
expect(handleDoubleClick).toHaveBeenCalledTimes(1);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
it("should handle keyboard events", async () => {
|
|
246
|
+
const handleKeyDown = vi.fn();
|
|
247
|
+
renderComponent({ onKeyDown: handleKeyDown });
|
|
248
|
+
|
|
249
|
+
screen.getByRole("button").focus();
|
|
250
|
+
await userEvent.keyboard("{Enter}");
|
|
251
|
+
|
|
252
|
+
expect(handleKeyDown).toHaveBeenCalled();
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### 4.4 Testes de Estado
|
|
258
|
+
|
|
259
|
+
Verificam estados visuais e comportamentais.
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
describe("States", () => {
|
|
263
|
+
it("should show loading spinner when isLoading is true", () => {
|
|
264
|
+
renderComponent({ isLoading: true });
|
|
265
|
+
expect(screen.getByRole("button")).toHaveClass("loadingTrue");
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("should display loading text when provided", () => {
|
|
269
|
+
renderComponent({ isLoading: true, loadingText: "Loading..." });
|
|
270
|
+
expect(screen.getByText("Loading...")).toBeInTheDocument();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should be disabled when disabled prop is true", () => {
|
|
274
|
+
renderComponent({ disabled: true });
|
|
275
|
+
expect(screen.getByRole("button")).toBeDisabled();
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("should be disabled when loading", () => {
|
|
279
|
+
renderComponent({ isLoading: true });
|
|
280
|
+
expect(screen.getByRole("button")).toBeDisabled();
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 4.5 Testes de Acessibilidade
|
|
286
|
+
|
|
287
|
+
Verificam conformidade com padrões de acessibilidade.
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
describe("Accessibility", () => {
|
|
291
|
+
it("should have correct role", () => {
|
|
292
|
+
renderComponent();
|
|
293
|
+
expect(screen.getByRole("button")).toBeInTheDocument();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it("should support aria-label", () => {
|
|
297
|
+
renderComponent({ "aria-label": "Close modal" });
|
|
298
|
+
expect(screen.getByLabelText("Close modal")).toBeInTheDocument();
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it("should support aria-describedby", () => {
|
|
302
|
+
renderComponent({ "aria-describedby": "help-text" });
|
|
303
|
+
expect(screen.getByRole("button")).toHaveAttribute(
|
|
304
|
+
"aria-describedby",
|
|
305
|
+
"help-text",
|
|
306
|
+
);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("should be focusable when not disabled", () => {
|
|
310
|
+
renderComponent();
|
|
311
|
+
const button = screen.getByRole("button");
|
|
312
|
+
button.focus();
|
|
313
|
+
expect(button).toHaveFocus();
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it("should have type button by default to prevent form submission", () => {
|
|
317
|
+
renderComponent({ type: "button" });
|
|
318
|
+
expect(screen.getByRole("button")).toHaveAttribute("type", "button");
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### 4.6 Testes de Variações/Combinações
|
|
324
|
+
|
|
325
|
+
Verificam diferentes combinações de props.
|
|
326
|
+
|
|
327
|
+
```typescript
|
|
328
|
+
describe("Variations", () => {
|
|
329
|
+
const sizes = ["xs", "sm", "md", "lg"] as const;
|
|
330
|
+
const variants = ["solid", "outline", "ghost"] as const;
|
|
331
|
+
const schemes = ["primary", "success", "danger"] as const;
|
|
332
|
+
|
|
333
|
+
sizes.forEach((size) => {
|
|
334
|
+
it(`should render correctly with size="${size}"`, () => {
|
|
335
|
+
renderComponent({ size });
|
|
336
|
+
expect(screen.getByRole("button")).toHaveClass(size);
|
|
337
|
+
});
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
variants.forEach((variant) => {
|
|
341
|
+
it(`should render correctly with variant="${variant}"`, () => {
|
|
342
|
+
renderComponent({ variant });
|
|
343
|
+
expect(screen.getByRole("button")).toHaveClass(variant);
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
schemes.forEach((scheme) => {
|
|
348
|
+
it(`should render correctly with scheme="${scheme}"`, () => {
|
|
349
|
+
renderComponent({ scheme });
|
|
350
|
+
expect(screen.getByRole("button")).toHaveClass(scheme);
|
|
351
|
+
});
|
|
352
|
+
});
|
|
353
|
+
});
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
### 4.7 Testes de Ícones (se aplicável)
|
|
357
|
+
|
|
358
|
+
Verificam renderização de ícones.
|
|
359
|
+
|
|
360
|
+
```typescript
|
|
361
|
+
describe("Icons", () => {
|
|
362
|
+
it("should render left icon when provided", () => {
|
|
363
|
+
const MockIcon = () => <svg data-testid="left-icon" />;
|
|
364
|
+
renderComponent({ leftIcon: MockIcon });
|
|
365
|
+
expect(screen.getByTestId("left-icon")).toBeInTheDocument();
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it("should render right icon when provided", () => {
|
|
369
|
+
const MockIcon = () => <svg data-testid="right-icon" />;
|
|
370
|
+
renderComponent({ rightIcon: MockIcon });
|
|
371
|
+
expect(screen.getByTestId("right-icon")).toBeInTheDocument();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it("should render both icons simultaneously", () => {
|
|
375
|
+
const LeftMock = () => <svg data-testid="left-icon" />;
|
|
376
|
+
const RightMock = () => <svg data-testid="right-icon" />;
|
|
377
|
+
renderComponent({ leftIcon: LeftMock, rightIcon: RightMock });
|
|
378
|
+
|
|
379
|
+
expect(screen.getByTestId("left-icon")).toBeInTheDocument();
|
|
380
|
+
expect(screen.getByTestId("right-icon")).toBeInTheDocument();
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## 5. Padrões de Nomenclatura
|
|
388
|
+
|
|
389
|
+
### Formato do `describe`:
|
|
390
|
+
|
|
391
|
+
- Use o nome do componente como primeiro `describe`
|
|
392
|
+
- Agrupe testes relacionados em `describe` aninhados
|
|
393
|
+
|
|
394
|
+
### Formato do `it`:
|
|
395
|
+
|
|
396
|
+
Use o padrão: `should [comportamento esperado] when [condição]`
|
|
397
|
+
|
|
398
|
+
**Exemplos:**
|
|
399
|
+
|
|
400
|
+
- ✅ `should render correctly with default props`
|
|
401
|
+
- ✅ `should call onClick when button is clicked`
|
|
402
|
+
- ✅ `should be disabled when isLoading is true`
|
|
403
|
+
- ✅ `should apply custom className when provided`
|
|
404
|
+
- ❌ `test button click` (muito vago)
|
|
405
|
+
- ❌ `onClick works` (não descreve o cenário)
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## 6. Checklist de Cobertura
|
|
410
|
+
|
|
411
|
+
### Antes de considerar os testes completos, verifique:
|
|
412
|
+
|
|
413
|
+
#### Renderização
|
|
414
|
+
|
|
415
|
+
- [ ] Renderiza com props padrão
|
|
416
|
+
- [ ] Renderiza children corretamente
|
|
417
|
+
- [ ] Aplica className customizada
|
|
418
|
+
- [ ] Propaga atributos HTML adicionais (data-\*, id, etc.)
|
|
419
|
+
|
|
420
|
+
#### Props
|
|
421
|
+
|
|
422
|
+
- [ ] Cada prop documentada tem pelo menos 1 teste
|
|
423
|
+
- [ ] Valores default são testados
|
|
424
|
+
- [ ] Diferentes valores de cada prop são testados
|
|
425
|
+
|
|
426
|
+
#### Interações
|
|
427
|
+
|
|
428
|
+
- [ ] onClick é chamado corretamente
|
|
429
|
+
- [ ] Eventos de teclado funcionam (se aplicável)
|
|
430
|
+
- [ ] Comportamento quando disabled
|
|
431
|
+
- [ ] Foco e blur (se aplicável)
|
|
432
|
+
|
|
433
|
+
#### Estados
|
|
434
|
+
|
|
435
|
+
- [ ] Estado de loading (se aplicável)
|
|
436
|
+
- [ ] Estado disabled
|
|
437
|
+
- [ ] Estados visuais (hover, active, focus via classes)
|
|
438
|
+
|
|
439
|
+
#### Acessibilidade
|
|
440
|
+
|
|
441
|
+
- [ ] Role correto
|
|
442
|
+
- [ ] Suporte a aria-label
|
|
443
|
+
- [ ] Focusable quando apropriado
|
|
444
|
+
- [ ] Anúncio de estados para screen readers
|
|
445
|
+
|
|
446
|
+
#### Edge Cases
|
|
447
|
+
|
|
448
|
+
- [ ] Props undefined ou null
|
|
449
|
+
- [ ] Strings vazias
|
|
450
|
+
- [ ] Combinações incomuns de props
|
|
451
|
+
|
|
452
|
+
---
|
|
453
|
+
|
|
454
|
+
## 7. Exemplos Práticos
|
|
455
|
+
|
|
456
|
+
### Exemplo completo de teste para um Button:
|
|
457
|
+
|
|
458
|
+
Veja o arquivo `/packages/components/src/components/__test__/button.test.tsx` para um exemplo completo e real de como os testes devem ser estruturados.
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## 8. Boas Práticas
|
|
463
|
+
|
|
464
|
+
### ✅ FAÇA:
|
|
465
|
+
|
|
466
|
+
1. **Teste comportamento, não implementação**
|
|
467
|
+
|
|
468
|
+
```typescript
|
|
469
|
+
// ✅ Bom - testa o comportamento
|
|
470
|
+
expect(screen.getByRole("button")).toBeDisabled();
|
|
471
|
+
|
|
472
|
+
// ❌ Ruim - testa implementação
|
|
473
|
+
expect(component.state.disabled).toBe(true);
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
2. **Use queries apropriadas**
|
|
477
|
+
|
|
478
|
+
```typescript
|
|
479
|
+
// Prioridade de queries:
|
|
480
|
+
// 1. getByRole (mais acessível)
|
|
481
|
+
// 2. getByLabelText
|
|
482
|
+
// 3. getByText
|
|
483
|
+
// 4. getByTestId (último recurso)
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
3. **Aguarde operações assíncronas**
|
|
487
|
+
|
|
488
|
+
```typescript
|
|
489
|
+
await userEvent.click(button);
|
|
490
|
+
await waitFor(() => expect(mockFn).toHaveBeenCalled());
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
4. **Use userEvent ao invés de fireEvent**
|
|
494
|
+
|
|
495
|
+
```typescript
|
|
496
|
+
// ✅ Simula comportamento real do usuário
|
|
497
|
+
await userEvent.click(button);
|
|
498
|
+
|
|
499
|
+
// ❌ Dispara evento diretamente
|
|
500
|
+
fireEvent.click(button);
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
5. **Limpe mocks entre testes**
|
|
504
|
+
```typescript
|
|
505
|
+
beforeEach(() => {
|
|
506
|
+
vi.clearAllMocks();
|
|
507
|
+
});
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### ❌ NÃO FAÇA:
|
|
511
|
+
|
|
512
|
+
1. **Não teste bibliotecas externas**
|
|
513
|
+
- Não teste se o React renderiza
|
|
514
|
+
- Não teste comportamento do browser
|
|
515
|
+
|
|
516
|
+
2. **Não use snapshots como teste principal**
|
|
517
|
+
- Snapshots são frágeis e difíceis de manter
|
|
518
|
+
|
|
519
|
+
3. **Não duplique testes**
|
|
520
|
+
- Cada comportamento deve ser testado uma vez
|
|
521
|
+
|
|
522
|
+
4. **Não ignore erros do console**
|
|
523
|
+
- Warnings e errors indicam problemas reais
|
|
524
|
+
|
|
525
|
+
5. **Não dependa de timeouts arbitrários**
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
// ❌ Ruim
|
|
529
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
530
|
+
|
|
531
|
+
// ✅ Bom
|
|
532
|
+
await waitFor(() => expect(element).toBeVisible());
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
---
|
|
536
|
+
|
|
537
|
+
## 📝 Template Rápido
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
541
|
+
import { render, screen } from "@testing-library/react";
|
|
542
|
+
import userEvent from "@testing-library/user-event";
|
|
543
|
+
|
|
544
|
+
import { ComponentName } from "./index";
|
|
545
|
+
|
|
546
|
+
const defaultProps = {};
|
|
547
|
+
|
|
548
|
+
const renderComponent = (props = {}) => {
|
|
549
|
+
return render(<ComponentName {...defaultProps} {...props} />);
|
|
550
|
+
};
|
|
551
|
+
|
|
552
|
+
describe("ComponentName", () => {
|
|
553
|
+
beforeEach(() => {
|
|
554
|
+
vi.clearAllMocks();
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
describe("Rendering", () => {
|
|
558
|
+
it("should render correctly with default props", () => {
|
|
559
|
+
renderComponent();
|
|
560
|
+
// adicione assertions
|
|
561
|
+
});
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
describe("Props", () => {
|
|
565
|
+
// testes de props
|
|
566
|
+
});
|
|
567
|
+
|
|
568
|
+
describe("Interactions", () => {
|
|
569
|
+
// testes de interação
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
describe("States", () => {
|
|
573
|
+
// testes de estado
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
describe("Accessibility", () => {
|
|
577
|
+
// testes de acessibilidade
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
---
|
|
583
|
+
|
|
584
|
+
## 🔄 Fluxo de Trabalho para IAs
|
|
585
|
+
|
|
586
|
+
Ao receber um componente para testar, siga este fluxo:
|
|
587
|
+
|
|
588
|
+
1. **Analise o componente**
|
|
589
|
+
- Identifique todas as props e seus tipos
|
|
590
|
+
- Identifique valores default
|
|
591
|
+
- Identifique estados possíveis
|
|
592
|
+
- Identifique eventos/handlers
|
|
593
|
+
|
|
594
|
+
2. **Crie a estrutura do teste**
|
|
595
|
+
- Use o template fornecido
|
|
596
|
+
- Organize em grupos lógicos
|
|
597
|
+
|
|
598
|
+
3. **Implemente os testes**
|
|
599
|
+
- Comece pelos testes de renderização
|
|
600
|
+
- Siga com props, interações, estados
|
|
601
|
+
- Finalize com acessibilidade e edge cases
|
|
602
|
+
|
|
603
|
+
4. **Valide a cobertura**
|
|
604
|
+
- Use o checklist da seção 6
|
|
605
|
+
- Garanta que cada prop/comportamento está coberto
|
|
606
|
+
|
|
607
|
+
5. **Revise a nomenclatura**
|
|
608
|
+
- Todos os `it` seguem o padrão `should...when...`?
|
|
609
|
+
- Os grupos fazem sentido?
|
|
610
|
+
|
|
611
|
+
---
|
|
612
|
+
|
|
613
|
+
**Última atualização:** Março 2026
|