frontend-test

SKILL.md

Frontend Test Skill

Escribe tests para componentes React, hooks y contextos del frontend Ocralis.

When to Activate

  • Anadir tests a un componente o pantalla existente
  • Testear hooks custom o contextos (AuthContext, ThemeContext)
  • Validar formularios y flujos de usuario
  • Mockear llamadas API
  • Mejorar cobertura de tests del frontend

Setup

Instalacion

cd ocralis_frontend
npm install -D vitest @testing-library/react @testing-library/jest-dom @testing-library/user-event jsdom

vitest.config.ts (extender vite.config.ts)

/// <reference types="vitest" />
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  plugins: [react()],
  test: {
    globals: true,
    environment: "jsdom",
    setupFiles: "./src/test/setup.ts",
    css: true,
  },
});

Setup File (src/test/setup.ts)

import "@testing-library/jest-dom";

Script en package.json

{
  "scripts": {
    "test": "vitest",
    "test:run": "vitest run",
    "test:coverage": "vitest run --coverage"
  }
}

Patrones de Test

Test de Componente/Pantalla

// src/screens/Login/__tests__/Login.test.tsx
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { BrowserRouter } from "react-router-dom";
import { AuthProvider } from "../../../context/AuthContext";
import Login from "../Login";

const renderLogin = () => {
  render(
    <BrowserRouter>
      <AuthProvider>
        <Login />
      </AuthProvider>
    </BrowserRouter>
  );
};

describe("Login", () => {
  it("deberia mostrar formulario de login", () => {
    renderLogin();
    expect(screen.getByPlaceholderText(/email/i)).toBeInTheDocument();
    expect(screen.getByPlaceholderText(/password/i)).toBeInTheDocument();
  });

  it("deberia mostrar error con campos vacios", async () => {
    renderLogin();
    const submitBtn = screen.getByRole("button", { name: /iniciar/i });
    await userEvent.click(submitBtn);
    await waitFor(() => {
      expect(screen.getByText(/requerido/i)).toBeInTheDocument();
    });
  });
});

Test de Contexto

// src/context/__tests__/AuthContext.test.tsx
import { renderHook, act } from "@testing-library/react";
import { AuthProvider, useAuth } from "../AuthContext";

describe("AuthContext", () => {
  it("deberia iniciar sin usuario", () => {
    const { result } = renderHook(() => useAuth(), {
      wrapper: AuthProvider,
    });
    expect(result.current.user).toBeNull();
  });

  it("deberia guardar usuario al hacer login", () => {
    const { result } = renderHook(() => useAuth(), {
      wrapper: AuthProvider,
    });
    act(() => {
      result.current.login("token", "refresh", {
        id: 1,
        name: "Test",
        email: "t@t.com",
      });
    });
    expect(result.current.user).toBeTruthy();
    expect(result.current.user?.email).toBe("t@t.com");
  });
});

Mock de API

import { vi } from "vitest";

vi.mock("../../lib/api", () => ({
  default: {
    get: vi.fn(),
    post: vi.fn(),
    put: vi.fn(),
    delete: vi.fn(),
  },
}));

Mock de Servicio

import { vi } from "vitest";

vi.mock("../../services/company.service", () => ({
  getCompanies: vi.fn().mockResolvedValue([
    { id: 1, nombre: "Empresa Test", cif: "B12345678" },
  ]),
  createCompany: vi.fn().mockResolvedValue({ id: 2, nombre: "Nueva" }),
}));

Helper: Wrapper con Providers

// src/test/helpers.tsx
import { BrowserRouter } from "react-router-dom";
import { AuthProvider } from "../context/AuthContext";
import { ThemeProvider } from "../context/ThemeContext";

export const AllProviders = ({ children }: { children: React.ReactNode }) => (
  <BrowserRouter>
    <AuthProvider>
      <ThemeProvider>
        {children}
      </ThemeProvider>
    </AuthProvider>
  </BrowserRouter>
);

Estructura de Tests

src/
├── test/
│   ├── setup.ts
│   └── helpers.tsx
├── screens/
│   └── Login/__tests__/Login.test.tsx
├── context/
│   └── __tests__/AuthContext.test.tsx
├── components/
│   └── __tests__/ProtectedRoute.test.tsx
└── services/
    └── __tests__/company.service.test.ts

Convenciones

Concepto Convencion
Framework Vitest + Testing Library + jsdom
Naming {Component}.test.tsx en carpeta __tests__/
Wrappers Siempre wrappear con BrowserRouter + AuthProvider
Async Usar waitFor para operaciones asincronas
User events Preferir userEvent sobre fireEvent
Descripciones En espanol
Queries Preferir getByRole > getByText > getByTestId

Checklist

  • vitest.config.ts configurado con jsdom
  • Setup file con @testing-library/jest-dom
  • Tests de componentes con providers wrapping
  • Tests de contextos con renderHook
  • Mocks de API y servicios
  • Tests de formularios (validacion, submit)
  • Tests async con waitFor
  • Helper de providers reutilizable
Weekly Installs
1
First Seen
6 days ago
Installed on
amp1
cline1
trae1
trae-cn1
opencode1
cursor1