Refactor y tests en paralelo con Cursor 2.0: el atajo real a código más limpio
Los equipos que iteran rápido no escriben más código: escriben mejor código con menos fricción. La nueva interfaz multi‑agente de Cursor 2.0 permite orquestar tareas en paralelo —por ejemplo, refactorizar un módulo y generar tests de unidad— sin esperar a que termine una para iniciar la otra. En esta guía te muestro, paso a paso, cómo hacerlo con un ejemplo práctico en Node.js.
¿Por qué multi‑agente para refactor + tests?
- Paralelismo real: un agente refactoriza mientras otro redacta y valida tests. Menos tiempo en cola, más tiempo entregando valor.
- Aislamiento seguro: cada agente trabaja en su propio contexto (worktree/entorno), evitando conflictos.
- Feedback temprano: los tests se escriben con la intención de la nueva API, forzando mejores contratos.
- Menos deuda: refactor y cobertura avanzan juntos, no como tareas separadas “para después”.
Lo que vas a construir
Partiremos de un módulo Node.js con cierta deuda técnica (funciones con efectos colaterales, nombres ambiguos y validaciones mezcladas). Usaremos Cursor 2.0 para:
- Refactorizar a una API más expresiva, pura y testeable.
- Generar y ajustar tests con Jest en paralelo.
- Revisar cambios y aplicar diffs de múltiples archivos en una sola vista.
Requisitos
- Node.js 18+ y npm.
- Cursor 2.0 actualizado con la interfaz multi‑agente habilitada.
- Git inicializado en el repo (se recomienda activar worktrees para aislamiento).
Repo de ejemplo
Estructura mínima:
- /src/priceCalculator.js
- /package.json
- /__tests__/ (se generará)
Código inicial (antes del refactor)
Este módulo acumula responsabilidades y tiene validaciones dispersas. Es perfecto para que el agente de refactor lo mejore.
// src/priceCalculator.js (versión inicial)
function applyDiscount(price, coupon) {
if (!price || price < 0) return 0;
if (!coupon) return price;
if (coupon.type === 'percent') {
return Math.round(price - (price * coupon.value) / 100);
}
if (coupon.type === 'absolute') {
const v = price - coupon.value;
return v < 0 ? 0 : v;
}
// side effect (logging arbitrario)
console.log('Unknown coupon type');
return price;
}
function calcTotal(items, coupon) {
// items: [{ price, qty }]
if (!Array.isArray(items)) return 0;
let total = 0;
for (let i = 0; i < items.length; i++) {
const it = items[i];
total += (it.price || 0) * (it.qty || 1);
}
return applyDiscount(total, coupon);
}
module.exports = { calcTotal, applyDiscount };
Configura Jest rápidamente
Agrega Jest y un script de test:
{
"name": "cursor-multi-agent-demo",
"version": "1.0.0",
"type": "commonjs",
"scripts": {
"test": "jest --passWithNoTests"
},
"devDependencies": {
"jest": "^29.7.0"
}
}
Instala dependencias: npm i
Crea tus agentes en Cursor 2.0
- Agente 1 – Refactor (objetivo: pureza, legibilidad, validaciones claras, sin side effects ni console.log en flujo de dominio).
- Agente 2 – Tests (objetivo: generar suite de Jest con casos nominales, bordes y errores; preparar mocks si fueran necesarios).
Prompts sugeridos para iniciar cada agente:
- Refactor Agent: “Refactoriza src/priceCalculator.js para lograr funciones puras, validar entradas con mensajes útiles, documentar TS JSDoc y separar cálculo de descuentos. No cambies behavior salvo donde haya bugs evidentes.”
- Tests Agent: “Genera tests con Jest para calcTotal y applyDiscount. Cubre percent/absolute, valores límite (precio 0, cupón desconocido), múltiples ítems y qty inválido.”
Ejecuta en paralelo con aislamiento
- Habilita trabajo aislado (p. ej., Git worktrees o entornos sandbox) para cada agente. Así, los cambios no colisionan.
- Activa el Plan mode para que Cursor descomponga la tarea en pasos y archivos a tocar.
- Deja corriendo ambos agentes. Observa cómo uno propone la nueva API mientras el otro adapta los tests a esa API.
Revisión y aplicación de cambios
Cuando ambos agentes concluyan una iteración, usa el panel de review diffs de Cursor:
- Revisa cambios por archivo en una sola vista.
- Evalúa si el contrato de la función refactorizada coincide con lo que cubren los tests.
- Aplica cambios selectivamente o solicita otra pasada al agente correspondiente.
Resultado del refactor (después)
// src/priceCalculator.js (refactorizado)
/**
* @typedef {Object} Coupon
* @property {('percent'|'absolute')} type
* @property {number} value
*/
/** Valida que sea un número finito y >= 0 */
function asNonNegativeNumber(n, fallback = 0) {
const v = Number.isFinite(n) ? n : fallback;
return v < 0 ? 0 : v;
}
/** Aplica el cupón de forma pura, sin efectos colaterales */
function applyDiscount(price, coupon) {
const p = asNonNegativeNumber(price, 0);
if (!coupon) return p;
if (coupon.type === 'percent') {
const pct = asNonNegativeNumber(coupon.value, 0);
const discounted = p - (p * pct) / 100;
return Math.round(discounted < 0 ? 0 : discounted);
}
if (coupon.type === 'absolute') {
const abs = asNonNegativeNumber(coupon.value, 0);
const diff = p - abs;
return diff < 0 ? 0 : diff;
}
// Cupón desconocido => no aplica
return p;
}
/**
* Calcula el total de items con qty y price, luego aplica descuento.
* @param {{price:number, qty?:number}[]} items
* @param {Coupon=} coupon
*/
function calcTotal(items, coupon) {
if (!Array.isArray(items) || items.length === 0) return 0;
const sum = items.reduce((acc, it) => {
const price = asNonNegativeNumber(it?.price, 0);
const qty = asNonNegativeNumber(it?.qty ?? 1, 1);
return acc + price * qty;
}, 0);
return applyDiscount(sum, coupon);
}
module.exports = { calcTotal, applyDiscount, asNonNegativeNumber };
Suite de tests generada por el agente
// __tests__/priceCalculator.test.js
const { calcTotal, applyDiscount } = require('../src/priceCalculator');
describe('applyDiscount', () => {
test('sin cupón devuelve el mismo precio', () => {
expect(applyDiscount(100, null)).toBe(100);
});
test('percent aplica porcentaje y redondea', () => {
expect(applyDiscount(200, { type: 'percent', value: 10 })).toBe(180);
});
test('absolute resta valor sin ir bajo cero', () => {
expect(applyDiscount(50, { type: 'absolute', value: 80 })).toBe(0);
});
test('cupón desconocido no altera el precio', () => {
expect(applyDiscount(120, { type: 'weird', value: 10 })).toBe(120);
});
});
describe('calcTotal', () => {
test('lista vacía => 0', () => {
expect(calcTotal([], null)).toBe(0);
});
test('suma price*qty y aplica cupón percent', () => {
const items = [{ price: 100, qty: 2 }, { price: 50 }];
expect(calcTotal(items, { type: 'percent', value: 10 })).toBe(225);
});
test('valores inválidos se normalizan a 0/1', () => {
const items = [{ price: -10, qty: -3 }, { price: 30, qty: NaN }];
expect(calcTotal(items, null)).toBe(30);
});
});
Ejecuta y valida
- Corre npm test en la terminal sandbox de Cursor para validar sin salir del editor.
- Si falla algún caso, pide al agente de tests que explique el fallo y proponga el ajuste mínimo (en test o en implementación).
- Cuando todo pase en verde, aplica cambios y realiza el commit.
Buenas prácticas para prompts y orquestación
- Contratos claros: define en el prompt del agente de refactor la API pública esperada y restricciones (pureza, errores manejados, tipos).
- Desacople: pide separar validación, cálculo y side effects en funciones distintas. Los tests respiran mejor.
- Iteraciones cortas: activa el planning y limita el alcance por PR: 1 módulo + 1 suite de tests por iteración.
- Contexto suficiente: comparte al agente archivos relacionados (p. ej., README o casos de negocio) para decisiones informadas.
Más allá del “hola mundo” de los agentes
- Browser integrado: si trabajas en frontend, permite a un agente validar el comportamiento de la UI en tiempo real.
- Voice mode: dispara correcciones rápidas sin romper el flujo de teclado.
- LSP optimizados: notarás diagnósticos más ágiles en TypeScript/JS, útiles en refactors amplios.
- Auditoría y seguridad: usa terminales sandbox para comandos y activa reglas de ejecución compartidas en equipo.
Integración con CI (opcional, recomendado)
Agrega una verificación mínima en tu pipeline (GitHub Actions, GitLab CI o similar) para que no se fusionen cambios sin tests verdes. De esta forma, el multi‑agente no solo acelera localmente, también eleva el estándar del repo.
Solución de problemas comunes
- Conflictos entre agentes: usa worktrees/ramas separadas y aplica diffs de forma incremental en review.
- Tests “frágiles”: solicita al agente criterios más deterministas o inyecta dependencias para evitar acoplamientos.
- Cobertura superficial: exige casos de borde y mutación leve (p. ej., cambiar entradas) para fortalecer la suite.
¿Y en Laravel?
El mismo patrón aplica con Pest o PHPUnit. Un agente refactoriza un Service o Controller y otro genera pruebas con factories y fakes. Define prompts equivalentes y deja que corran en paralelo; revisa diffs y ejecuta php artisan test en la terminal sandbox de Cursor.
Checklist final para llevarte a producción
- Refactor pequeño, atómico, centrado en una unidad funcional.
- Tests que documenten intención y bordes: percent/absolute, entradas inválidas, acumulación.
- Review visual de diffs multiarchivo y commit con mensaje claro.
- CI con regla: “no merge si tests fallan”.
Cierre
El multi‑agente de Cursor 2.0 no es solo “más rápido”: cambia el patrón de trabajo. Cuando refactor y tests avanzan a la par, el resultado es una base de código más confiable, menos regresiones y un equipo que itera con confianza. ¿Te gustó este flujo? Déjame tus dudas en comentarios, comparte con tu equipo o sigue el blog para más guías aplicadas.