O Gerador De CPF O Gerador De CPF

Gerar CPF em React: Hook Customizado com Geração em Lote

Este hook customizado traz a geração de CPF para dentro de componentes React, com suporte a lote e formatação usando o algoritmo de módulo 11. O artigo foca na criação programática de CPFs válidos. Para validação de CPFs existentes, veja validar CPF em React.

Função de geração

function generateCPF(): string {
  const digits: number[] = [];

  for (let i = 0; i < 9; i++) {
    digits.push(Math.floor(Math.random() * 10));
  }

  for (let t = 9; t < 11; t++) {
    let sum = 0;
    for (let i = 0; i < t; i++) {
      sum += digits[i] * (t + 1 - i);
    }
    const remainder = sum % 11;
    digits.push(remainder < 2 ? 0 : 11 - remainder);
  }

  return digits.join("");
}

O primeiro laço gera 9 dígitos aleatórios. Os dois dígitos verificadores são calculados com o mesmo algoritmo de módulo 11 usado na validação: soma ponderada, resto da divisão por 11, e conversão para o dígito final.

A função auxiliar isValidCpf é usada nos testes para confirmar que os CPFs gerados são válidos:

function isValidCpf(value: string): boolean {
  const cpf = value.replace(/\D/g, "");

  if (cpf.length !== 11) return false;
  if (/^(\d)\1{10}$/.test(cpf)) return false;

  for (let t = 9; t < 11; t++) {
    let sum = 0;
    for (let c = 0; c < t; c++) {
      sum += Number(cpf[c]) * (t + 1 - c);
    }
    if (Number(cpf[t]) !== ((10 * sum) % 11) % 10) return false;
  }

  return true;
}

Hook useGenerateCPF

import { useState, useCallback } from "react";

interface UseGenerateCPF {
  cpf: string;
  formatted: string;
  generate: () => void;
  generateBatch: (n: number) => string[];
}

function formatCPF(cpf: string): string {
  return cpf.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, "$1.$2.$3-$4");
}

function useGenerateCPF(): UseGenerateCPF {
  const [cpf, setCpf] = useState("");

  const generate = useCallback(() => {
    const newCpf = generateCPF();
    setCpf(newCpf);
  }, []);

  const generateBatch = useCallback((n: number): string[] => {
    const batch: string[] = [];
    for (let i = 0; i < n; i++) {
      batch.push(generateCPF());
    }
    return batch;
  }, []);

  const formatted = cpf ? formatCPF(cpf) : "";

  return { cpf, formatted, generate, generateBatch };
}

Componente

import { useState } from "react";

function CpfGenerator() {
  const { cpf, formatted, generate, generateBatch } = useGenerateCPF();
  const [batch, setBatch] = useState<string[]>([]);

  const handleBatch = () => {
    const results = generateBatch(10);
    setBatch(results);
  };

  return (
    <div>
      <h2>Gerador de CPF</h2>

      <div style={{ display: "flex", gap: "8px" }}>
        <button onClick={generate}>Gerar</button>
        <button onClick={handleBatch}>Gerar 10</button>
      </div>

      {formatted && (
        <p data-testid="result">
          CPF gerado: <strong>{formatted}</strong>
        </p>
      )}

      {batch.length > 0 && (
        <ul aria-label="CPFs gerados">
          {batch.map((item, index) => (
            <li key={index}>{formatCPF(item)}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

Análise do código

generateCPF é uma função pura sem dependências externas. Ela gera 9 dígitos aleatórios e calcula os dois dígitos verificadores usando somas ponderadas com pesos decrescentes (10 a 2 para o primeiro, 11 a 2 para o segundo). O resultado é sempre uma string de 11 dígitos que passa na validação de módulo 11.

useGenerateCPF encapsula a geração em um hook reutilizável. generate atualiza o estado com um novo CPF, enquanto generateBatch retorna um array sem alterar o estado unitário — o componente decide como armazenar o lote. formatted é derivado do cpf atual, aplicando a máscara XXX.XXX.XXX-XX via regex.

O componente CpfGenerator combina o hook com estado local para o lote. Os dois botões separam a geração unitária da geração em lote, e a lista renderiza cada CPF formatado. O data-testid no resultado facilita a seleção nos testes sem depender de texto que pode mudar.

Testes

Testes com Vitest e Testing Library:

import { describe, it, expect } from "vitest";
import { render, screen, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

describe("generateCPF", () => {
  it("gera CPF com 11 dígitos", () => {
    const cpf = generateCPF();
    expect(cpf).toMatch(/^\d{11}$/);
  });

  it("gera CPF válido", () => {
    const cpf = generateCPF();
    expect(isValidCpf(cpf)).toBe(true);
  });

  it("gera CPFs diferentes", () => {
    const cpfs = new Set(Array.from({ length: 50 }, () => generateCPF()));
    expect(cpfs.size).toBeGreaterThan(1);
  });
});

describe("CpfGenerator", () => {
  it("gera CPF ao clicar no botão", async () => {
    const user = userEvent.setup();
    render(<CpfGenerator />);

    await user.click(screen.getByRole("button", { name: /^gerar$/i }));

    const result = screen.getByTestId("result");
    expect(result.textContent).toMatch(/\d{3}\.\d{3}\.\d{3}-\d{2}/);
  });

  it("gera lote de 10 CPFs", async () => {
    const user = userEvent.setup();
    render(<CpfGenerator />);

    await user.click(screen.getByRole("button", { name: /gerar 10/i }));

    const list = screen.getByRole("list", { name: /cpfs gerados/i });
    const items = within(list).getAllByRole("listitem");
    expect(items).toHaveLength(10);
  });

  it("exibe CPF formatado com máscara", async () => {
    const user = userEvent.setup();
    render(<CpfGenerator />);

    await user.click(screen.getByRole("button", { name: /^gerar$/i }));

    const result = screen.getByTestId("result");
    const match = result.textContent?.match(/(\d{3}\.\d{3}\.\d{3}-\d{2})/);
    expect(match).not.toBeNull();

    const digits = match![1].replace(/\D/g, "");
    expect(isValidCpf(digits)).toBe(true);
  });
});

Os testes da função pura verificam formato, validade e aleatoriedade. Os testes do componente usam userEvent para simular cliques reais e confirmam que o resultado aparece formatado com máscara. O teste de lote usa within para buscar itens dentro da lista específica, evitando falsos positivos.

Precisa validar CPFs em React? Veja validar CPF em React. Para gerar CPFs para teste sem código, use o gerador de CPF.