Teste de integração com Vitest: Testando um formulário completo

Posted by

Testes automatizados são fundamentais para garantir a qualidade e o funcionamento correto de aplicações React. Com o Vitest, você pode escrever testes rápidos e eficientes para validar desde a interação com inputs até a submissão completa do formulário.

Neste artigo, vamos mostrar como criar e testar um formulário React completo com campos de texto (input), checkbox e select, além da função de envio (submit). Tudo isso utilizando o Vitest para garantir que cada parte funcione conforme o esperado.

O que é Teste de Integração

O teste de integração tem como objetivo validar a comunicação entre diferentes partes do sistema. Diferentemente dos testes unitários, que focam em pequenas unidades isoladas de código, os testes de integração verificam se múltiplos componentes trabalham bem juntos.

Exemplos de cenários comuns:

  • Um formulário que envia dados para uma API
  • Uma função que salva informações no banco de dados
  • A comunicação entre front-end e back-end

Esses testes são especialmente importantes em aplicações complexas ou distribuídas, onde a integração entre camadas e serviços é constante.

O que é um Mock

Um mock é um objeto simulado usado para substituir uma dependência real durante o teste. Ele permite definir comportamentos específicos sem executar o código real, como chamadas HTTP ou operações de banco de dados.

Mocks ajudam a:

  • Simular respostas de APIs
  • Evitar chamadas externas lentas ou instáveis
  • Reproduzir cenários específicos (como erros)
  • Tornar os testes independentes de infraestrutura

Por exemplo, ao testar uma função que consome uma API externa, você pode usar um mock para retornar uma resposta pré-definida, garantindo consistência nos resultados.

Exemplo Prático de Uso de Mock

Abaixo está um exemplo básico usando Jest, uma biblioteca popular de testes JavaScript:

// services/api.js
export const getUser = async (id) => {
  const response = await fetch(`https://api.example.com/users/${id}`);
  return await response.json();
};
// __tests__/user.test.js
import { getUser } from '../services/api';

jest.mock('../services/api');

test('deve retornar dados simulados do usuário', async () => {
  const mockData = { id: 1, name: 'João Silva' };
  getUser.mockResolvedValue(mockData);

  const result = await getUser(1);
  expect(result).toEqual(mockData);
});

Nesse exemplo, estamos simulando a resposta da função getUser para evitar chamadas reais à API durante o teste.

Quando Usar Mocks em Testes de Integração

Embora mocks sejam úteis, seu uso deve ser equilibrado. Eles são ideais quando:

  • Você precisa isolar dependências externas instáveis ou lentas
  • Quer testar cenários difíceis de reproduzir com sistemas reais (ex: erro de rede)
  • Não tem acesso a ambientes completos ou dados reais

No entanto, evite abusar de mocks em testes de integração, pois isso pode mascarar problemas reais na comunicação entre componentes. Sempre valide com testes reais em ambientes próximos ao de produção.

Criando o Formulário React

Abaixo está o exemplo de um componente React chamado UserForm, que contém os principais elementos de um formulário web:

// src/components/UserForm.jsx
import React, { useState } from 'react';

export default function UserForm({ onSubmit }) {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    role: 'developer',
    termsAccepted: false,
  });
  const [errors, setErrors] = useState({});

  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setFormData((prev) => ({
      ...prev,
      [name]: type === 'checkbox' ? checked : value,
    }));
  };

  const validate = () => {
    const newErrors = {};
    if (!formData.name) newErrors.name = 'Nome é obrigatório';
    if (!formData.email) newErrors.email = 'Email é obrigatório';
    else if (!/\S+@\S+\.\S+/.test(formData.email)) newErrors.email = 'Email inválido';
    if (!formData.termsAccepted) newErrors.terms = 'Você deve aceitar os termos';
    return newErrors;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const validationErrors = validate();
    if (Object.keys(validationErrors).length === 0) {
      onSubmit(formData);
    } else {
      setErrors(validationErrors);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Nome:</label>
        <input
          type="text"
          name="name"
          value={formData.name}
          onChange={handleChange}
        />
        {errors.name && <span>{errors.name}</span>}
      </div>

      <div>
        <label>Email:</label>
        <input
          type="email"
          name="email"
          value={formData.email}
          onChange={handleChange}
        />
        {errors.email && <span>{errors.email}</span>}
      </div>

      <div>
        <label>Função:</label>
        <select
          name="role"
          value={formData.role}
          onChange={handleChange}
        >
          <option value="developer">Desenvolvedor</option>
          <option value="designer">Designer</option>
          <option value="manager">Gerente</option>
        </select>
      </div>

      <div>
        <label>
          <input
            type="checkbox"
            name="termsAccepted"
            checked={formData.termsAccepted}
            onChange={handleChange}
          />
          Aceito os termos
        </label>
        {errors.terms && <span>{errors.terms}</span>}
      </div>

      <button type="submit">Enviar</button>
    </form>
  );
}

Este formulário gerencia seu próprio estado com useState, realiza validações simples e permite a submissão apenas quando todos os dados forem preenchidos corretamente.

Configurando o Ambiente de Testes com Vitest

Antes de escrever os testes, certifique-se de ter as dependências necessárias instaladas:

npm install -D vitest @testing-library/react @testing-library/user-event

Adicione também os scripts no arquivo package.json:

{
  "scripts": {
    "test": "vitest",
    "test:watch": "vitest --watch"
  }
}

Agora estamos prontos para escrever os testes.

Escrevendo os Testes com Vitest

Abaixo estão os testes unitários e de integração para validar o comportamento do formulário criado:

// src/__tests__/UserForm.test.jsx
import { render, screen, fireEvent } from '@testing-library/react';
import { describe, it, expect, vi } from 'vitest';
import UserForm from '../components/UserForm';

describe('Teste de Formulário React', () => {
  const mockSubmit = vi.fn();

  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('deve atualizar o campo nome', () => {
    render(<UserForm onSubmit={mockSubmit} />);
    const input = screen.getByLabelText(/nome/i);
    fireEvent.change(input, { target: { value: 'Ana' } });
    expect(input.value).toBe('Ana');
  });

  it('deve marcar o checkbox de termos', () => {
    render(<UserForm onSubmit={mockSubmit} />);
    const checkbox = screen.getByRole('checkbox');
    fireEvent.click(checkbox);
    expect(checkbox.checked).toBe(true);
  });

  it('deve alterar o valor do select para designer', () => {
    render(<UserForm onSubmit={mockSubmit} />);
    const select = screen.getByRole('combobox');
    fireEvent.change(select, { target: { value: 'designer' } });
    expect(select.value).toBe('designer');
  });

  it('deve chamar onSubmit com dados válidos', () => {
    render(<UserForm onSubmit={mockSubmit} />);
    fireEvent.change(screen.getByLabelText(/nome/i), { target: { value: 'João' } });
    fireEvent.change(screen.getByLabelText(/email/i), { target: { value: '[email protected]' } });
    fireEvent.click(screen.getByLabelText(/aceito os termos/i));
    fireEvent.submit(screen.getByRole('form'));

    expect(mockSubmit).toHaveBeenCalledWith({
      name: 'João',
      email: '[email protected]',
      role: 'developer',
      termsAccepted: true,
    });
  });

  it('deve exibir erro se email for inválido', () => {
    render(<UserForm onSubmit={mockSubmit} />);
    fireEvent.change(screen.getByLabelText(/email/i), { target: { value: 'invalido' } });
    fireEvent.submit(screen.getByRole('form'));

    expect(screen.getByText(/email inválido/i)).toBeInTheDocument();
  });
});

O que Este Teste Verifica

  • Atualização dos valores nos campos de texto (input)
  • Funcionamento do checkbox
  • Alteração de opções no campo select
  • Validação de dados antes da submissão
  • Chamada correta da função onSubmit com dados válidos
  • Exibição de mensagens de erro em casos de validação falha

Conclusão

Escrever testes para formulários React usando Vitest é uma prática essencial para manter a estabilidade e a confiabilidade da aplicação. Com poucas linhas de código e ferramentas como o Testing Library, é possível cobrir todo o fluxo do usuário, desde a interação com os campos até o envio final dos dados.

Ao seguir este guia, você garante que seus formulários funcionem perfeitamente em diferentes cenários, ajudando a evitar bugs e melhorando a experiência do desenvolvedor.

One comment

Leave a Reply

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *