Jest · fixture · globalSetup

Gerador de CPF em Jest

Setup completo pra usar CPF válido em testes Jest sem gambiarra. Fixture reutilizável, globalSetup pra pré-carregar batch, mock de service que consome CPF, snapshot fixture pra tests determinísticos. Tudo com SDK fakeforge-br.

TL;DR

npm install --save-dev fakeforge-br

// tests/fixtures/cpf.ts
import { FakeForge } from "fakeforge-br"
export const ff = new FakeForge()

Free 50 chamadas/dia sem cadastro. Cachea entre testes pra economizar.

Fixture reutilizável

// tests/fixtures/customer-fixture.ts
import { FakeForge } from "fakeforge-br"

const ff = new FakeForge()

// Cachea entre testes pra economizar quota
let cache: string[] | null = null

export async function getCPFs(quantity = 20): Promise<string[]> {
  if (!cache || cache.length < quantity) {
    cache = await ff.cpf(Math.max(quantity, 50))
  }
  return cache.slice(0, quantity)
}

export async function getCustomer(): Promise<{
  nome: string; cpf: string; email: string; telefone: string
}> {
  const [c] = await ff.preset("customer", 1)
  return c
}

globalSetup: pré-carrega batch

Se muitos testes usam CPF, faz sentido carregar 1 vez no globalSetup e reusar via arquivo:

// jest.config.js
export default {
  globalSetup: "./tests/global-setup.ts",
}

// tests/global-setup.ts
import { FakeForge } from "fakeforge-br"
import fs from "fs"

export default async function globalSetup() {
  const ff = new FakeForge()
  const [cpfs, customers, fintech] = await Promise.all([
    ff.cpf(500),
    ff.preset("customer", 100),
    ff.preset("fintech", 50),
  ])
  fs.writeFileSync(".test-fixtures.json", JSON.stringify({ cpfs, customers, fintech }))
  console.log("Loaded fixtures: 500 CPFs + 100 customers + 50 fintech")
}

// tests/setup.ts
import fs from "fs"
const fixtures = JSON.parse(fs.readFileSync(".test-fixtures.json", "utf-8"))
globalThis.testFixtures = fixtures

Teste E2E de signup

// tests/signup.test.ts
import { describe, test, expect, beforeAll } from "@jest/globals"
import request from "supertest"
import app from "../src/app"
import { getCPFs } from "./fixtures/customer-fixture"

describe("POST /signup", () => {
  let cpfs: string[]

  beforeAll(async () => {
    cpfs = await getCPFs(10)
  })

  test.each(cpfs)("aceita CPF válido %s", async (cpf) => {
    const res = await request(app).post("/signup").send({
      cpf,
      email: `user-${Date.now()}@test.com`,
      password: "test1234",
    })
    expect(res.status).toBe(201)
  })

  test("rejeita CPF inválido", async () => {
    const res = await request(app).post("/signup").send({
      cpf: "111.111.111-11",  // sequência inválida
      email: "user@test.com",
    })
    expect(res.status).toBe(400)
  })
})

Mock de service que consome CPF

// tests/customer.service.test.ts
import { CustomerService } from "../src/customer.service"
import { getCustomer } from "./fixtures/customer-fixture"

jest.mock("../src/serasa.client", () => ({
  consultarScore: jest.fn().mockResolvedValue({ score: 750 }),
}))

describe("CustomerService", () => {
  test("cria customer com score do Serasa", async () => {
    const dadosFake = await getCustomer()
    const service = new CustomerService()

    const customer = await service.criar(dadosFake)

    expect(customer.cpf).toBe(dadosFake.cpf)
    expect(customer.score).toBe(750)
  })
})

Snapshot fixture determinística

Se você quer testes 100% reprodutíveis (sem chamada API a cada run), gera fixture uma vez e commita:

# scripts/gen-fixtures.js - roda 1 vez, commita output
import { FakeForge } from "fakeforge-br"
import fs from "fs"

const ff = new FakeForge()
const data = {
  cpfs: await ff.cpf(100),
  customers: await ff.preset("customer", 20),
}
fs.writeFileSync("tests/fixtures/snapshot.json", JSON.stringify(data, null, 2))

// tests/fixture-loader.ts
import snapshot from "./fixtures/snapshot.json"
export const { cpfs, customers } = snapshot

Trade-off: fixture fica igual pra sempre (ideal pra snapshot tests) mas não capta bug que só aparece com dado diferente.

Próximos passos