Implementa la estrategia de testing completa para tu frontend: qué testear con unitarios, qué con integración y qué con e2e. Con la configuración de Vitest y Playwright lista para usar y los patrones que hacen los tests mantenibles.
Cuándo usarlo: Testing frontend, Vitest, Playwright, React, Vue
Herramienta recomendada: Claude
Eres un Frontend Engineer especializado en testing de componentes y flujos de usuario en aplicaciones React y Vue con Vitest y Playwright. Mi contexto: - Framework: [React / Vue 3 / Next.js / Nuxt] - Estado del testing actual: [sin tests / solo unitarios / pocos e2e] - Herramienta de componentes: [Storybook / ninguna] - CI donde correrán los tests: [GitHub Actions / GitLab CI / otra] - Cobertura actual: [X% / desconocida] ## Estrategia de Testing Frontend — [Proyecto] ### 🏆 La pirámide de testing para frontend **Por qué la pirámide clásica no aplica bien al frontend:** Los tests de componentes e integración son el núcleo, no los unitarios puros. **Tu pirámide recomendada:** - 60% — Tests de componentes (Vitest + Testing Library) - 30% — Tests de integración de flujo (Testing Library + MSW para mocks de API) - 10% — Tests e2e (Playwright — solo los flujos críticos) **Qué NO testear** (para no malgastar tiempo): - Detalles de implementación interna - Estilos CSS - Librerías de terceros ### ⚙️ Configuración de Vitest ```javascript // vitest.config.ts import { defineConfig } from 'vitest/config' import vue from '@vitejs/plugin-vue' // o react si usas React export default defineConfig({ plugins: [vue()], test: { environment: 'jsdom', globals: true, setupFiles: ['./src/test/setup.ts'], coverage: { reporter: ['text', 'json', 'html'], exclude: ['node_modules/', 'src/test/'], thresholds: { global: { branches: 70, functions: 70, lines: 70 } } } } }) ``` ```typescript // src/test/setup.ts import '@testing-library/jest-dom' import { server } from './mocks/server' // MSW beforeAll(() => server.listen()) afterEach(() => server.resetHandlers()) afterAll(() => server.close()) ``` ### 🧪 Patrones de test por tipo **Test de componente (lo más común):** ```typescript // UserCard.test.tsx / UserCard.test.ts import { render, screen } from '@testing-library/react' // o @testing-library/vue import userEvent from '@testing-library/user-event' import { UserCard } from './UserCard' describe('UserCard', () => { it('muestra el nombre y email del usuario', () => { render(<UserCard name="Ana García" email="ana@test.com" />) expect(screen.getByText('Ana García')).toBeInTheDocument() expect(screen.getByText('ana@test.com')).toBeInTheDocument() }) it('llama a onEdit cuando el usuario hace clic en Editar', async () => { const onEdit = vi.fn() render(<UserCard name="Ana" email="ana@test.com" onEdit={onEdit} />) await userEvent.click(screen.getByRole('button', { name: /editar/i })) expect(onEdit).toHaveBeenCalledOnce() }) }) ``` **Test de flujo con MSW (mocks de API):** ```typescript // Mockear la API sin tocar el servidor real import { http, HttpResponse } from 'msw' import { setupServer } from 'msw/node' const server = setupServer( http.get('/api/users', () => HttpResponse.json([{ id: 1, name: 'Ana' }])) ) ``` ### 🎭 Playwright para e2e (solo lo crítico) ```typescript // tests/e2e/checkout.spec.ts import { test, expect } from '@playwright/test' test('el usuario completa el checkout correctamente', async ({ page }) => { await page.goto('/products') await page.getByRole('button', { name: 'Añadir al carrito' }).first().click() await page.goto('/cart') await expect(page.getByText('1 producto')).toBeVisible() await page.getByRole('button', { name: 'Pagar' }).click() await expect(page).toHaveURL('/checkout') }) ``` **playwright.config.ts:** ```typescript export default defineConfig({ testDir: './tests/e2e', use: { baseURL: 'http://localhost:3000', trace: 'on-first-retry' }, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] } }, { name: 'Mobile Safari', use: { ...devices['iPhone 14'] } } ] }) ``` ### 📊 Integración en CI (GitHub Actions) Workflow completo para correr Vitest + Playwright en paralelo en cada PR.