Use Cases (Actualizado: 2/6/2026)

Guía de TDD con Claude Code: desarrollo dirigido por pruebas con Vitest y node:test

Practica TDD con Claude Code usando ejemplos reales de Vitest, node:test, CI, hooks y plantillas de prompts.

Guía de TDD con Claude Code: desarrollo dirigido por pruebas con Vitest y node:test

Claude Code puede escribir código muy rápido, pero la velocidad no garantiza seguridad. Los problemas suelen aparecer después: un caso límite mal entendido, una regresión, un descuento mal calculado o una prueba que solo falla en CI.

TDD, o desarrollo dirigido por pruebas, ayuda a controlar esa velocidad. El ciclo es claro: escribir primero una prueba que falla, implementar el cambio mínimo para que pase y luego refactorizar sin cambiar el comportamiento. A esto se le llama Red-Green-Refactor. Red es la falla esperada, Green es el comportamiento funcionando y Refactor es la limpieza del código.

Claude Code encaja bien porque puede enumerar casos, leer errores, implementar cambios pequeños y ajustar CI. La condición es no pedirle simplemente “crea la función”. Primero hay que pedirle la prueba fallida. En esta guía verás ejemplos copiables con Vitest y node:test, configuración de CI, hooks actuales de Claude Code y plantillas de prompts.

Para esta actualización revisé la documentación oficial de Claude Code hooks, Claude Code memory, Claude Code settings, Vitest Getting Started, Vitest CLI y Node.js test runner. El ejemplo de hooks usa JSON por stdin y lee tool_input.file_path, que es la forma alineada con la documentación actual.

Dónde ayuda Claude Code

Claude Code puede generar pruebas, interpretar salidas fallidas, escribir la implementación mínima, añadir CI y resumir riesgos. La persona responsable debe decidir reglas de negocio, seguridad, contrato público de la API y criterio de publicación.

PasoTrabajo de Claude CodeRevisión humana
RedEscribir pruebas fallidas desde la especificaciónNo inventar requisitos
GreenHacer el cambio mínimoEvitar abstracciones innecesarias
RefactorLimpiar nombres y duplicaciónMantener el comportamiento
CIEjecutar pruebas en cada PRUsar una versión realista de Node
OperaciónFijar hábitos con hooks y CLAUDE.mdNo hacer la automatización lenta
flowchart LR
  A["Dividir la especificación"] --> B["Red: prueba fallida"]
  B --> C["Green: implementación mínima"]
  C --> D["Refactor: limpiar"]
  D --> E["CI y hooks vuelven a ejecutar"]
  E --> B

Ejemplo 1: Vitest para precios y cupones

Los cálculos de precio, cupones y suscripciones son buenos candidatos para TDD porque afectan ingresos directamente.

npm install -D vitest
{
  "type": "module",
  "scripts": {
    "test": "vitest run",
    "test:watch": "vitest"
  },
  "devDependencies": {
    "vitest": "^3.0.0"
  }
}

Crea primero src/cart.test.ts.

import { describe, expect, it } from "vitest";
import { priceCart, ValidationError } from "./cart";

describe("priceCart", () => {
  it("calculates subtotal and total without a coupon", () => {
    const result = priceCart({
      items: [
        { sku: "book", unitPriceCents: 1200, quantity: 2 },
        { sku: "video", unitPriceCents: 3000, quantity: 1 },
      ],
    });

    expect(result).toEqual({
      subtotalCents: 5400,
      discountCents: 0,
      totalCents: 5400,
    });
  });

  it("applies a valid percent coupon", () => {
    const result = priceCart(
      {
        items: [{ sku: "course", unitPriceCents: 10000, quantity: 1 }],
        coupon: {
          code: "SPRING20",
          percentOff: 20,
          expiresAt: "2026-06-30T00:00:00.000Z",
        },
      },
      { now: new Date("2026-06-02T00:00:00.000Z") },
    );

    expect(result.totalCents).toBe(8000);
    expect(result.discountCents).toBe(2000);
  });

  it("rejects expired coupons", () => {
    expect(() =>
      priceCart(
        {
          items: [{ sku: "course", unitPriceCents: 10000, quantity: 1 }],
          coupon: {
            code: "OLD20",
            percentOff: 20,
            expiresAt: "2026-05-01T00:00:00.000Z",
          },
        },
        { now: new Date("2026-06-02T00:00:00.000Z") },
      ),
    ).toThrow(ValidationError);
  });

  it("rejects zero or negative quantity", () => {
    expect(() =>
      priceCart({
        items: [{ sku: "book", unitPriceCents: 1200, quantity: 0 }],
      }),
    ).toThrow("quantity must be positive");
  });
});

Pídele a Claude Code que confirme Red.

Estamos en la fase Red. src/cart.test.ts existe, pero src/cart.ts no existe.

Haz esto:
1. Ejecuta npm test y confirma la falla.
2. Implementa solo el src/cart.ts mínimo para pasar.
3. No añadas UI, base de datos, APIs externas ni funciones futuras.
4. Refactoriza solo después de que las pruebas objetivo estén en Green.

Implementación mínima para src/cart.ts.

export class ValidationError extends Error {
  constructor(message: string) {
    super(message);
    this.name = "ValidationError";
  }
}

type CartItem = {
  sku: string;
  unitPriceCents: number;
  quantity: number;
};

type Coupon = {
  code: string;
  percentOff: number;
  expiresAt: string;
};

type CartInput = {
  items: CartItem[];
  coupon?: Coupon;
};

type PriceOptions = {
  now?: Date;
};

export function priceCart(input: CartInput, options: PriceOptions = {}) {
  if (input.items.length === 0) {
    throw new ValidationError("cart must contain at least one item");
  }

  const subtotalCents = input.items.reduce((sum, item) => {
    if (!Number.isInteger(item.quantity) || item.quantity <= 0) {
      throw new ValidationError("quantity must be positive");
    }
    if (!Number.isInteger(item.unitPriceCents) || item.unitPriceCents < 0) {
      throw new ValidationError("unitPriceCents must be a non-negative integer");
    }
    return sum + item.unitPriceCents * item.quantity;
  }, 0);

  const discountCents = calculateDiscount(subtotalCents, input.coupon, options.now ?? new Date());

  return {
    subtotalCents,
    discountCents,
    totalCents: subtotalCents - discountCents,
  };
}

function calculateDiscount(subtotalCents: number, coupon: Coupon | undefined, now: Date) {
  if (!coupon) return 0;

  if (coupon.percentOff <= 0 || coupon.percentOff > 100) {
    throw new ValidationError("percentOff must be between 1 and 100");
  }

  if (new Date(coupon.expiresAt).getTime() < now.getTime()) {
    throw new ValidationError("coupon expired");
  }

  return Math.round(subtotalCents * (coupon.percentOff / 100));
}

Ejemplo 2: node:test para límites de CLI

Para utilidades pequeñas de Node, node:test evita dependencias adicionales. Guarda esto como limit.test.mjs.

import test from "node:test";
import assert from "node:assert/strict";

export function parseLimit(value, fallback = 20) {
  if (value === undefined || value === "") return fallback;

  const parsed = Number(value);
  if (!Number.isInteger(parsed)) {
    throw new TypeError("limit must be an integer");
  }
  if (parsed < 1 || parsed > 100) {
    throw new RangeError("limit must be between 1 and 100");
  }

  return parsed;
}

test("parseLimit uses fallback when the value is empty", () => {
  assert.equal(parseLimit(undefined), 20);
  assert.equal(parseLimit("", 50), 50);
});

test("parseLimit accepts values from 1 to 100", () => {
  assert.equal(parseLimit("1"), 1);
  assert.equal(parseLimit("100"), 100);
});

test("parseLimit rejects decimals and out-of-range values", () => {
  assert.throws(() => parseLimit("1.5"), /integer/);
  assert.throws(() => parseLimit("0"), /between 1 and 100/);
  assert.throws(() => parseLimit("101"), /between 1 and 100/);
});
node --test limit.test.mjs

Ejemplo 3: una regresión de API

Cuando aparece un bug real, conviértelo en prueba antes de tocar la implementación.

Añade una prueba de regresión con TDD.

Contexto:
- POST /checkout acepta cupones vencidos por error.
- Los cupones válidos y el checkout sin cupón deben seguir funcionando.

Red:
- Añade una prueba que espera 400 con cupón vencido.
- Confirma que la implementación actual falla.

Green:
- Haz el cambio mínimo en la API.

Refactor:
- Extrae solo la comparación de fechas duplicada.

Devuelve:
- Nombre de prueba, salida fallida, archivos cambiados, comandos y riesgos.

Puedes ampliar este enfoque con la guía de pruebas de API y la guía de estrategia de pruebas.

CI y hooks

name: test
on:
  pull_request:
  push:
    branches: [main]

jobs:
  unit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm test

Hook para ejecutar Vitest relacionado tras ediciones.

{
  "$schema": "https://json.schemastore.org/claude-code-settings.json",
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|MultiEdit",
        "hooks": [
          {
            "type": "command",
            "command": "node .claude/hooks/run-related-vitest.mjs",
            "timeout": 120
          }
        ]
      }
    ]
  }
}
import { spawnSync } from "node:child_process";
import path from "node:path";

let raw = "";
for await (const chunk of process.stdin) {
  raw += chunk;
}

const event = raw ? JSON.parse(raw) : {};
const filePath = event.tool_input?.file_path;

if (typeof filePath !== "string" || !/\.[cm]?[jt]sx?$/.test(filePath)) {
  process.exit(0);
}

const target = path.isAbsolute(filePath)
  ? path.relative(process.cwd(), filePath)
  : filePath;

const result = spawnSync("npx", ["vitest", "related", target, "--run"], {
  stdio: "inherit",
  shell: process.platform === "win32",
});

process.exit(result.status ?? 1);

En CLAUDE.md, deja reglas breves.

## TDD workflow
- Behavior changes start with a failing test.
- Show the Red result before implementation.
- Implement the smallest change that makes the test pass.
- Refactor only after the targeted test is Green.
- Report the command, result, changed files, and remaining risk.

Para más contexto, consulta la guía de hooks y las buenas prácticas de CLAUDE.md.

Plantillas de prompts

Nueva función con TDD:
Objetivo:
  Añadir [función].
Especificación:
  - [caso correcto]
  - [valores límite]
  - [comportamiento de error]
Proceso:
  1. Escribe pruebas primero.
  2. Ejecuta npm test y muestra Red.
  3. Implementa el cambio mínimo para Green.
  4. Refactoriza sin cambiar comportamiento.
Devuelve:
  Salida fallida, comandos, archivos cambiados y riesgos.
Corrección de bug con TDD:
Reproducción:
  [entrada, acción o log]
Esperado:
  [comportamiento correcto]
Actual:
  [comportamiento actual]
Solicitud:
  Añade primero una prueba de regresión que falle.
  Luego haz la corrección mínima.
  No debilites ni borres pruebas existentes sin explicar por qué.
Refactor seguro:
Objetivo:
  [archivo/función]
Restricción:
  El comportamiento público no cambia.
Pasos:
  1. Añadir characterization tests del comportamiento actual.
  2. Confirmar Green.
  3. Refactorizar solo internals.
  4. Ejecutar las mismas pruebas.

Errores comunes

El primero es saltarse Red. Si la prueba pasa antes del arreglo, no protege nada. El segundo es probar detalles internos en vez de comportamiento. En precios importan total, descuento y errores. El tercero es usar tiempo real en pruebas; inyecta now. El cuarto es confiar solo en mocks cuando pagos, email o CRM necesitan contrato o staging. El quinto es permitir que Claude Code borre pruebas para llegar a Green.

CTA

Empieza con una regla de precio, un parser de CLI o una regresión de API. Si trabajas solo, usa la chuleta gratuita de Claude Code y estas plantillas. Para prompts, hooks y checklists reutilizables, revisa los productos de ClaudeCodeLab. Para equipos que necesitan TDD, CI, permisos y revisión en un repositorio real, usa formación y consultoría de Claude Code.

Resultado al probarlo

En el flujo de Masa, pedir a Claude Code primero la prueba fallida redujo el tiempo de revisión frente a pedir implementación directa. Los cupones vencidos, la cantidad cero y las rutas API sin autenticación aparecieron antes. Ejecutar todas las pruebas desde un hook fue demasiado lento, así que la configuración práctica quedó en Vitest relacionado tras ediciones y E2E completo en CI.

#Claude Code #TDD #test-driven development #testing #quality assurance
Gratis

PDF gratis: cheatsheet de Claude Code

Introduce tu email y descarga una hoja con comandos, hábitos de revisión y flujos seguros.

Cuidamos tus datos y no enviamos spam.

Masa

Sobre el autor

Masa

Ingeniero enfocado en workflows prácticos con Claude Code.