Skip to content
FakeBuilder Generator logo

FakeBuilder Generator

Gera FakeBuilders para agregados DDD usando Chance.js seguindo padrão do projeto com PropOrFactory, type augmentation e dados realistas para testes.

SKILL.md

Full skill instructions

FakeBuilder Generator Skill

Objetivo

Esta Skill orienta Claude Code a gerar FakeBuilders completos para agregados DDD seguindo o padrão estabelecido no projeto: Chance.js para dados fake realistas, fluent API, type augmentation e suporte a factories.

Quando usar

Ative esta Skill quando:

  • Criar um novo agregado que precisa de fake builder para testes
  • Gerar dados de teste realistas para testes unitários ou integração
  • Implementar test fixtures com Chance.js
  • Criar builders com padrão fluent API
  • Precisar de dados fake válidos (CPF, CNPJ, emails, etc)
  • Configurar test data factories

Entradas esperadas

  • agregado: Classe do agregado/​entidade para o qual gerar o builder
  • propriedades: Lista de propriedades e seus tipos
  • validacoes_especiais: Regras específicas (CPF/​CNPJ válido, códigos hierárquicos, etc)
  • caminho_arquivo: Onde salvar o builder (geralmente [modulo]/​domain/[nome].fake-builder.ts)

Saídas esperadas

  • Arquivo .fake-builder.ts completo e funcional
  • Type augmentation para adicionar método .fake() no agregado
  • Comentários explicativos quando necessário
  • Exemplos de uso no topo do arquivo
  • Suporte a PropOrFactory<T> para valores fixos ou funções

Estrutura do FakeBuilder

Template Base

import { Chance } from 'chance';
import { [Agregado], Create[Agregado]Props } from './[agregado].aggregate';

type PropOrFactory<T> = T | ((index: number) => T);

export class [Agregado]FakeBuilder<TBuild = any> {
  private chance: Chance.Chance;
  private countObjs: number;
  private baseIndex: number;
  private static globalIndex = 0;

  // Propriedades com valores padrão usando factories
  private _empresaId: PropOrFactory<string> = () => this.chance.guid();
  private _propriedade1: PropOrFactory<tipo> = (index: number) => {
    // Lógica de geração
  };

  private constructor(countObjs: number = 1) {
    this.countObjs = countObjs;
    this.chance = new Chance();
    this.baseIndex = [Agregado]FakeBuilder.globalIndex * 100;
    [Agregado]FakeBuilder.globalIndex += 1;
  }

  static anEntity() {
    return new [Agregado]FakeBuilder<[Agregado]>(1);
  }

  static theEntities(countObjs: number) {
    return new [Agregado]FakeBuilder<[Agregado][]>(countObjs);
  }

  with[Propriedade](valueOrFactory: PropOrFactory<tipo>) {
    this._propriedade = valueOrFactory;
    return this;
  }

  build(): TBuild {
    const entities = new Array(this.countObjs)
      .fill(undefined)
      .map((_, index) => {
        const props: Create[Agregado]Props = {
          empresaId: this.callFactory(this._empresaId, index),
          propriedade1: this.callFactory(this._propriedade1, index),
          // ... outras propriedades
        };

        const entity = [Agregado].create(props);
        return entity;
      });

    return this.countObjs === 1 ? (entities[0] as any) : (entities as any);
  }

  private callFactory(factoryOrValue: PropOrFactory<any>, index: number) {
    return typeof factoryOrValue === 'function'
      ? factoryOrValue(index)
      : factoryOrValue;
  }
}

// Adicionar método estático ao agregado
[Agregado].fake = function () {
  return [Agregado]FakeBuilder;
};

// Type augmentation
declare module './[agregado].aggregate' {
  export interface [Agregado] {
    fake?: typeof [Agregado]FakeBuilder;
  }
  namespace [Agregado] {
    export let fake: () => typeof [Agregado]FakeBuilder;
  }
}

Padrões Específicos por Tipo de Dado

1. Códigos Simples (3 dígitos)

Para bancos:

private _codigo: PropOrFactory<string> = (index: number) => {
  const value = (this.baseIndex + index) % 900; // 0-899
  return (value + 100).toString().padStart(3, '0'); // 100-999
};

2. Códigos Sequenciais

Para centro de custo:

private _codigo: PropOrFactory<string> = (index: number) =>
  `CC${(this.baseIndex + index + 1).toString().padStart(3, '0')}`;

3. Códigos Hierárquicos

Para plano de contas:

private _codigo: PropOrFactory<string> = (index: number) => {
  const level1 = ((this.baseIndex + index) % 9) + 1;
  const level2 = ((this.baseIndex + index) % 99) + 1;
  const level3 = (index % 999) + 1;
  return `${level1}.${level2.toString().padStart(2, '0')}.${level3.toString().padStart(3, '0')}`;
};

4. CPF/​CNPJ Válidos

Para clientes/​fornecedores:

private _documento: PropOrFactory<string> = (index: number) => {
  return this._tipoPessoa === 'PF'
    ? this.generateValidCPF()
    : this.generateValidCNPJ();
};

private generateValidCPF(): string {
  const digits = Array.from({ length: 9 }, () =>
    this.chance.integer({ min: 0, max: 9 })
  );

  const d1 = this.calculateCPFDigit(digits, 10);
  const d2 = this.calculateCPFDigit([...digits, d1], 11);

  return [...digits, d1, d2].join('');
}

private calculateCPFDigit(digits: number[], weight: number): number {
  const sum = digits.reduce((acc, digit, idx) => {
    return acc + digit * (weight - idx);
  }, 0);

  const remainder = sum % 11;
  return remainder < 2 ? 0 : 11 - remainder;
}

private generateValidCNPJ(): string {
  const digits = Array.from({ length: 12 }, () =>
    this.chance.integer({ min: 0, max: 9 })
  );

  const d1 = this.calculateCNPJDigit(digits, [5,4,3,2,9,8,7,6,5,4,3,2]);
  const d2 = this.calculateCNPJDigit([...digits, d1], [6,5,4,3,2,9,8,7,6,5,4,3,2]);

  return [...digits, d1, d2].join('');
}

private calculateCNPJDigit(digits: number[], weights: number[]): number {
  const sum = digits.reduce((acc, digit, idx) => {
    return acc + digit * weights[idx];
  }, 0);

  const remainder = sum % 11;
  return remainder < 2 ? 0 : 11 - remainder;
}

5. Nomes Realistas

Usando Chance.js:

private _nome: PropOrFactory<string> = (index: number) =>
  this.chance.name();

// Para empresas
private _razaoSocial: PropOrFactory<string> = (index: number) =>
  `${this.chance.company()} ${this.chance.pickone(['Ltda', 'S.A.', 'ME', 'EIRELI'])}`;

6. Emails

private _email: PropOrFactory<string | null> = (index: number) =>
  this.chance.email();

// Ou null por padrão se opcional
private _email: PropOrFactory<string | null> = () => null;

7. Telefones

private _telefone: PropOrFactory<string | null> = (index: number) =>
  `11${this.chance.integer({ min: 900000000, max: 999999999 })}`;

8. Enums

private _tipo: PropOrFactory<TipoPlanoContas> = (index: number) =>
  this.chance.pickone(['RECEITA', 'DESPESA']);

private _status: PropOrFactory<Status> = () => 'ATIVO';

9. Campos Opcionais

private _descricao: PropOrFactory<string | null> = () => null;

// Ou com valor gerado
private _descricao: PropOrFactory<string | null> = (index: number) =>
  this.chance.sentence({ words: 10 });

10. Relacionamentos (IDs)

private _parentId: PropOrFactory<string | null> = () => null;

// Para forçar relacionamento
withParentId(valueOrFactory: PropOrFactory<string>) {
  this._parentId = valueOrFactory;
  return this;
}

Chance.js - Métodos Úteis

// Identificadores
this.chance.guid()                    // UUID
this.chance.hash({ length: 10 })      // Hash aleatório

// Textos
this.chance.name()                    // Nome de pessoa
this.chance.company()                 // Nome de empresa
this.chance.email()                   // Email
this.chance.sentence({ words: 10 })   // Frase
this.chance.paragraph()               // Parágrafo

// Números
this.chance.integer({ min: 0, max: 999 })
this.chance.floating({ min: 0, max: 100, fixed: 2 })

// Datas
this.chance.date()
this.chance.timestamp()

// Endereços
this.chance.address()
this.chance.city()
this.chance.state()
this.chance.zip()
this.chance.country()

// Telefones
this.chance.phone()

// Seleção
this.chance.pickone(['A', 'B', 'C'])
this.chance.shuffle(['A', 'B', 'C'])

// Booleanos
this.chance.bool()
this.chance.bool({ likelihood: 70 })  // 70% true

Exemplos Completos

Exemplo 1: Banco (Simples)

import { Chance } from 'chance';
import { Banco, CreateBancoProps } from './​banco.aggregate';

type PropOrFactory<T> = T | ((index: number) => T);

export class BancoFakeBuilder<TBuild = any> {
  private chance: Chance.Chance;
  private countObjs: number;
  private baseIndex: number;
  private static globalIndex = 0;

  private _empresaId: PropOrFactory<string> = () => this.chance.guid();

  private _codigo: PropOrFactory<string> = (index: number) => {
    const value = (this.baseIndex + index) % 900;
    return (value + 100).toString().padStart(3, '0');
  };

  private _nome: PropOrFactory<string> = (index: number) =>
    `Banco ${this.baseIndex + index + 1}`;

  private constructor(countObjs: number = 1) {
    this.countObjs = countObjs;
    this.chance = new Chance();
    this.baseIndex = BancoFakeBuilder.globalIndex * 100;
    BancoFakeBuilder.globalIndex += 1;
  }

  static anEntity() {
    return new BancoFakeBuilder<Banco>(1);
  }

  static theEntities(countObjs: number) {
    return new BancoFakeBuilder<Banco[]>(countObjs);
  }

  withEmpresaId(valueOrFactory: PropOrFactory<string>) {
    this._empresaId = valueOrFactory;
    return this;
  }

  withCodigo(valueOrFactory: PropOrFactory<string>) {
    this._codigo = valueOrFactory;
    return this;
  }

  withNome(valueOrFactory: PropOrFactory<string>) {
    this._nome = valueOrFactory;
    return this;
  }

  build(): TBuild {
    const entities = new Array(this.countObjs)
      .fill(undefined)
      .map((_, index) => {
        const props: CreateBancoProps = {
          empresaId: this.callFactory(this._empresaId, index),
          codigo: this.callFactory(this._codigo, index),
          nome: this.callFactory(this._nome, index),
        };

        const banco = Banco.create(props);
        return banco;
      });

    return this.countObjs === 1 ? (entities[0] as any) : (entities as any);
  }

  private callFactory(factoryOrValue: PropOrFactory<any>, index: number) {
    return typeof factoryOrValue === 'function'
      ? factoryOrValue(index)
      : factoryOrValue;
  }
}

Banco.fake = function () {
  return BancoFakeBuilder;
};

declare module './​banco.aggregate' {
  export interface Banco {
    fake?: typeof BancoFakeBuilder;
  }
  namespace Banco {
    export let fake: () => typeof BancoFakeBuilder;
  }
}

Exemplo 2: PlanoContas (Hierárquico)

Uso dos FakeBuilders

Single Entity

const banco = Banco.fake()
  .anEntity()
  .build();

Multiple Entities

const bancos = Banco.fake()
  .theEntities(5)
  .build();

Custom Properties

const banco = Banco.fake()
  .anEntity()
  .withCodigo('001')
  .withNome('Banco do Brasil')
  .build();

Factory Functions

const bancos = Banco.fake()
  .theEntities(10)
  .withCodigo((index) => (index + 1).toString().padStart(3, '0'))
  .withEmpresaId(() => 'same-empresa-id')
  .build();

Test Data Setup

describe('BancoService', () => {
  let empresaId: string;
  let bancos: Banco[];

  beforeEach(() => {
    empresaId = 'test-empresa-id';

    bancos = Banco.fake()
      .theEntities(5)
      .withEmpresaId(empresaId)
      .build();
  });

  it('should have all bancos with same empresaId', () => {
    expect(bancos.every(b => b.empresaId === empresaId)).toBe(true);
  });
});

Checklist de Implementação

Ao gerar um FakeBuilder, SEMPRE inclua:

Estrutura Base

  • Import de Chance
  • Import do agregado e suas props
  • Type PropOrFactory<T>
  • Classe com TBuild generic
  • Propriedades privadas com factories
  • Constructor privado
  • Métodos estáticos anEntity() e theEntities()
  • Métodos withX() para cada propriedade
  • Método build()
  • Método auxiliar callFactory()

Type Augmentation

  • Adicionar método .fake() ao agregado
  • Declare module correto
  • Export do tipo correto

Dados Realistas

  • Usar Chance.js apropriadamente
  • CPF/​CNPJ válidos quando necessário
  • Códigos únicos usando baseIndex
  • Emails válidos
  • Nomes em português quando apropriado

Índice Global

  • Static globalIndex para evitar colisões
  • baseIndex calculado no constructor
  • Incremento do globalIndex

Quando NÃO usar esta Skill

  • Para criar in-memory repositories
  • Para refatorações de código existente

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View