Módulo 5: Prueba en sandbox antes de producción
3. Generar datos sintéticos
Descripción
Al terminar esta lección vas a poder crear un conjunto de datos sintéticos —pedidos falsos pero realistas— para probar order-triage, sin usar ni un solo dato de un cliente real. Vas a saber generarlos de dos formas: con un dataset fijo escrito a mano y con un nodo Code que los arma en memoria. Y —lo más importante— vas a diseñar esos datos a propósito para cubrir los casos borde y los datos sucios, de modo que tu prueba se parezca a la realidad difícil y no a un caso feliz de folleto.
Esto importa por dos razones que se refuerzan. La primera es de privacidad: probar con datos reales de clientes expone información personal —nombres, correos, montos, direcciones— en un entorno de desarrollo que no tiene por qué verla, y eso es un riesgo legal y ético que no vale la pena correr. La segunda es de calidad: los datos reales que tienes a mano suelen ser casos normales, porque los raros son raros por definición. Si pruebas solo con lo que tienes, nunca ves el pedido de 50 000 pesos ni el que trae el nombre vacío hasta que llega en producción. Los datos sintéticos te dejan fabricar el caso difícil en vez de esperar a que aparezca.
Conexión con el módulo: en la lección 2 conectaste order-triage a un destino seguro —la llave sandbox del CRM—. Pero un destino seguro con entradas pobres es media prueba. Esta lección le da las entradas: los pedidos con los que vas a alimentar el workflow. Es el segundo punto del checklist. En la lección 5 vas a fijar estos datos sintéticos para que la prueba sea reproducible, y en las lecciones 7 y 8 vas a escribir aserciones que dicen, para cada uno de estos pedidos, qué clasificación esperabas del agente. Así que los datos que diseñes aquí son la columna vertebral de todo lo que sigue: elígelos bien.
Los maniquíes de prueba de choque
Piensa en cómo prueban la seguridad de un auto. No suben a una persona real y la estrellan contra un muro para ver si sobrevive —sería monstruoso y, además, un mal experimento, porque cada persona es distinta y no podrías repetir la prueba—. Usan maniquíes de prueba de choque: muñecos fabricados a propósito para parecerse a un cuerpo humano en lo que importa para la prueba —el peso, la altura, cómo se doblan las articulaciones, dónde están los órganos— pero que no son nadie. Y no usan un solo maniquí: usan una familia entera. Uno del tamaño de un adulto grande, uno de una mujer promedio, uno de un niño, uno de un bebé en su sillita. Porque un cinturón que protege a un adulto de 80 kilos puede estrangular a un niño de 20, y solo lo descubres si pruebas con los dos.
Los datos sintéticos son los maniquíes de tu workflow. Son falsos —no corresponden a ningún cliente real, así que nadie sale lastimado si algo se rompe— pero representativos: se parecen a los datos reales en lo que importa para la prueba, la forma del pedido, los campos que trae, los rangos de los montos. Y, como los maniquíes, no usas uno: usas una familia que cubre el rango de casos, incluidos los peligrosos. El pedido normal es el adulto promedio. El pedido de 50 000 pesos es el maniquí grande. El pedido con el nombre vacío es el bebé en la sillita: el caso raro donde tu "cinturón de seguridad" —la lógica del workflow— tiene más probabilidad de fallar.
Definamos el término con precisión, porque lo vas a usar todo el módulo. Un dato sintético es un dato generado artificialmente para una prueba, que imita la estructura y el comportamiento de los datos reales sin ser uno de ellos. "Sintético" es lo opuesto de "recolectado": no lo sacaste de la operación real de Cumbre, lo fabricaste. La palabra viene de "síntesis", armar algo a partir de partes; aquí armas un pedido creíble a partir de tu conocimiento de cómo son los pedidos, sin copiar ninguno.
Por qué no se prueba con datos reales
Es tentador tomar un puñado de pedidos reales de Cumbre —"ya los tengo, son realistas, ¿para qué inventar?"— y probar con ellos. No lo hagas, por tres razones.
Privacidad y datos personales. Un pedido real trae información de una persona o un negocio real: el nombre de la cafetería, quizás el nombre de quien la atiende, un correo, un teléfono, montos que revelan cuánto compra ese cliente. Eso es información personal (a veces llamada PII, por Personally Identifiable Information: información que identifica a una persona). Meterla en tu entorno de dev —que quizás corre en tu laptop, que quizás respaldas sin cifrar, cuyos datos quizás terminan en un log— la expone donde no debería estar. Muchas regulaciones de protección de datos lo prohíben directamente, y aunque la tuya no lo hiciera, es una responsabilidad que no ganas nada asumiendo. La regla simple: los datos de clientes reales no salen de producción.
Los datos reales son casi todos casos felices. Aquí hay una trampa estadística. La mayoría de tus pedidos reales son normales —por eso son la mayoría—. Si tomas veinte pedidos reales al azar para probar, es probable que los veinte sean casos que el workflow ya maneja bien, y que ni uno sea el pedido gigante o el incompleto que rompe la lógica. Probar con datos reales te da una falsa sensación de cobertura: probaste veinte cosas, pero eran veinte veces la misma cosa fácil.
No puedes fabricar el caso que necesitas. Si quieres probar qué hace order-triage con un pedido de exactamente 50 000 pesos sin nombre de cliente, con datos reales tendrías que esperar a que ese pedido exista —y ojalá no exista nunca en producción sin haberlo probado antes—. Con datos sintéticos lo fabricas en diez segundos. El control total sobre la entrada es justo lo que necesitas para probar los bordes.
Forma 1: un dataset fijo escrito a mano
La forma más simple y, para muchas pruebas, la mejor: escribes a mano un conjunto pequeño de pedidos que cubre los casos que te importan. "Fijo" significa que no cambia entre corridas —los mismos pedidos, siempre—, y eso es una virtud: una prueba con entradas fijas es reproducible, que es justo lo que la lección 5 va a explotar.
Para order-triage, los casos se organizan solos alrededor de las tres salidas del agente —aprobar, revisión manual, falta información— más una categoría que ninguna guía debería saltarse: los datos sucios. Aquí está el dataset, pensado como una familia de maniquíes:
[
{
"case": "happy-path-approve",
"order_id": "ORD-TEST-001",
"customer_name": "Café Aurora",
"amount": 1200,
"currency": "MXN",
"items": 3,
"note": "pedido normal, monto bajo, debe aprobarse solo"
},
{
"case": "large-order-manual-review",
"order_id": "ORD-TEST-002",
"customer_name": "Tostaduría del Sur",
"amount": 52000,
"currency": "MXN",
"items": 40,
"note": "monto alto, debe ir a revisión manual"
},
{
"case": "missing-customer-name",
"order_id": "ORD-TEST-003",
"customer_name": "",
"amount": 900,
"currency": "MXN",
"items": 2,
"note": "falta el nombre del cliente, debe marcarse como incompleto"
},
{
"case": "dirty-amount-as-string",
"order_id": "ORD-TEST-004",
"customer_name": "Rincón del Café",
"amount": "3,500.00",
"currency": "MXN",
"items": 8,
"note": "el monto viene como texto con comas, no como número"
},
{
"case": "dirty-whitespace-and-case",
"order_id": "ord-test-005 ",
"customer_name": " bodega LA MONTAÑA ",
"amount": 1500,
"currency": "MXN",
"items": 5,
"note": "espacios de sobra y mayúsculas inconsistentes en los textos"
},
{
"case": "edge-zero-amount",
"order_id": "ORD-TEST-006",
"customer_name": "Café Aurora",
"amount": 0,
"currency": "MXN",
"items": 0,
"note": "borde: monto y cantidad en cero, ¿pedido válido o error?"
}
]
Fíjate en cómo está construido cada maniquí. El campo case no es parte de un pedido real —Cumbre no manda un case en sus pedidos—; es una etiqueta que te agregaste a ti mismo para saber qué prueba cada fila y qué esperas de ella. En la lección 7 esa etiqueta se vuelve la llave para escribir la aserción correcta ("el caso large-order-manual-review debe salir como revisión manual"). El campo note es un comentario para humanos, por la misma razón. Los demás campos —order_id, customer_name, amount, currency, items— imitan la forma de un pedido real de Cumbre.
Y mira los seis casos como una familia:
happy-path-approvees el adulto promedio: el caso fácil que el workflow debe manejar bien. Si este falla, algo está muy roto.large-order-manual-reviewes el maniquí grande: prueba que el umbral de revisión manual funciona.missing-customer-namees el bebé en la sillita: el caso incompleto donde la lógica tiene que detectar la falta.dirty-amount-as-stringydirty-whitespace-and-caseson datos sucios: pedidos que en el mundo real llegan mal formateados —el monto como texto con comas, los nombres con espacios de sobra y mayúsculas al azar—. Casi todo pedido real trae algo de esta suciedad, y un workflow que solo probaste con datos limpios se rompe con el primer pedido de verdad.edge-zero-amountes un borde deliberado: un caso donde ni tú sabes bien qué debería pasar. ¿Un pedido de cero pesos es válido? ¿Es un error? Incluirlo te obliga a decidirlo antes de que producción lo decida por ti.
Este dataset vive en el repositorio cumbre-automations, en un archivo como test/fixtures/orders.json —"fixture" es el nombre estándar para un conjunto de datos de prueba fijos—. Que viva en Git tiene una ventaja grande: es versionado igual que el workflow, así que cuando alguien agrega un caso nuevo, queda registrado, y cuando pruebas, todos en el equipo prueban con los mismos maniquíes.
Forma 2: un nodo Code que los genera en memoria
Cuando necesitas más volumen —cien pedidos en vez de seis, para ver cómo se comporta el workflow con carga— escribir cada uno a mano es tedioso. Ahí entra el nodo Code, que puede fabricar items en memoria.
Una aclaración importante para esta guía, porque es un límite real de n8n 2.0: el nodo Code no puede llamar a una API para traer datos —nada de fetch, nada de axios, nada de require de librerías externas (solo crypto y moment), nada de acceso al sistema de archivos—. Pero sí puede crear y transformar datos en memoria, y eso es justo lo que necesitamos: no vamos a traer pedidos de ningún lado, los vamos a inventar con código. Generar datos sintéticos es exactamente la clase de cosa que el nodo Code sí puede hacer.
Este es un nodo Code, en modo "Run Once for All Items" (correr una vez para todos los items), que genera una tanda de pedidos sintéticos:
// Genera pedidos sintéticos en memoria para probar order-triage.
// No trae datos de ninguna API: los inventa. Eso el nodo Code SÍ puede hacerlo.
// Piezas para armar pedidos creíbles pero falsos.
const customers = ["Café Aurora", "Tostaduría del Sur", "Rincón del Café", "Bodega La Montaña"];
const currencies = ["MXN", "COP", "PEN"];
const orders = [];
// Generamos 100 pedidos "normales" para probar el comportamiento con volumen.
for (let i = 1; i <= 100; i++) {
// Un número de pedido con ceros a la izquierda: ORD-TEST-0001, 0002, ...
const orderId = "ORD-TEST-" + String(i).padStart(4, "0");
// Elegimos cliente y moneda rotando por las listas (determinista, no al azar).
const customer = customers[i % customers.length];
const currency = currencies[i % currencies.length];
// Montos que suben en escalón para cubrir un rango, incluido el umbral de 5000.
const amount = 500 + (i * 137) % 8000; // va de ~500 a ~8500, cruza el umbral
orders.push({
json: {
case: "generated-normal",
order_id: orderId,
customer_name: customer,
amount: amount,
currency: currency,
items: (i % 12) + 1,
},
});
}
// Devolvemos los 100 pedidos como items de n8n.
// Cada item es un objeto { json: {...} }; ese es el formato que n8n espera.
return orders;
Se corre así: pones este nodo Code al inicio de un workflow de prueba, lo ejecutas, y en su salida ves los 100 items generados.
Qué esperar: el nodo devuelve 100 pedidos, cada uno un item con su order_id, customer_name, amount, currency e items. Los montos suben en escalón y cruzan el umbral de 5000, así que entre los 100 hay pedidos que deben aprobarse solos y pedidos que deben ir a revisión manual, sin que hayas escrito ninguno a mano. La generación es determinista —no usa azar, sino aritmética sobre el contador i—, así que si corres el nodo diez veces, obtienes los mismos 100 pedidos las diez veces. Eso es a propósito, y es clave para la lección 5: una prueba reproducible necesita entradas reproducibles, y un generador determinista te las da.
Sobre el azar: podrías usar
crypto(que el nodo Code sí permite) para meter aleatoriedad y que los pedidos se vean más variados. Ten cuidado: el azar pelea contra la reproducibilidad. Si cada corrida genera pedidos distintos, no puedes comparar el resultado de hoy con el de ayer, porque cambiaron las entradas y no solo el workflow. Para pruebas que quieres repetir —casi todas— prefiere la generación determinista, como la de arriba. El azar tiene su lugar en pruebas de estrés o de fuzzing, que son otra historia.
Combinar las dos formas: el dataset fijo para los casos, el generador para el volumen
En la práctica, lo mejor de los dos mundos es usarlos juntos. El dataset fijo de la Forma 1 cubre los casos que te importan uno por uno, con su etiqueta y su resultado esperado —es tu batería de maniquíes cuidadosamente elegidos—. El generador de la Forma 2 agrega volumen para ver el comportamiento bajo carga y para cazar el caso raro que no se te ocurrió escribir a mano. Un pase de prueba serio suele correr primero los seis casos etiquetados (donde sabes exactamente qué esperar) y después la tanda de cien (donde verificas que nada explota con volumen). En la lección 8 vas a armar justo esa combinación.
Un punto medio: datos reales anonimizados
Hay un tercer camino, entre inventar desde cero y usar datos reales, que vale la pena conocer para casos especiales: anonimizar datos reales. Anonimizar es tomar un pedido real y reemplazar todo lo que identifica a una persona o negocio —el nombre, el correo, el teléfono— por valores falsos, conservando solo la estructura y las proporciones: los mismos rangos de montos, la misma frecuencia de campos vacíos, la misma variedad de formatos.
¿Cuándo conviene? Cuando la forma exacta de tus datos reales es difícil de imaginar y quieres que la prueba herede su desorden real. Por ejemplo, si los pedidos de Cumbre tienen una mezcla peculiar de monedas y formatos que no se te ocurriría inventar, anonimizar una muestra te da esa textura sin exponer a nadie.
La advertencia honesta: anonimizar bien es más difícil de lo que parece. Es fácil olvidar un campo —un identificador escondido, un comentario libre donde alguien escribió un nombre— y dejar información personal filtrada en datos que creías limpios. Por eso, para la mayoría de las pruebas, inventar desde cero (Formas 1 y 2) es más simple y más seguro: si nunca hubo un dato real, no hay nada que filtrar. Reserva la anonimización para cuando de verdad necesites la textura de lo real, y hazla con cuidado.
Cómo se los das al workflow
Tener los datos sintéticos es media historia; la otra media es meterlos al workflow para que corran por él. order-triage en producción recibe sus pedidos por un Webhook —un nodo que espera a que alguien le mande un pedido por HTTP—. Pero al probar no quieres depender de que algo externo te dispare el webhook; quieres controlar la entrada tú. Hay tres formas de inyectar los datos sintéticos, de menos a más elaborada, y cada una tiene su momento:
A mano, un pedido a la vez. El editor de n8n te deja disparar un Webhook con un cuerpo (body) que escribes tú, o poner un Manual Trigger (disparador manual) temporal seguido de un nodo Edit Fields con un pedido. Sirve para probar un caso puntual rápido. Es lo más simple y lo menos repetible.
Con un nodo Code o Edit Fields al inicio. Pones el dataset fijo (Forma 1) o el generador (Forma 2) como primer nodo de un workflow de prueba, y de ahí sale hacia el resto de la lógica de order-triage. Así corres los seis casos —o los cien— de una pasada. Es la forma que vas a usar en el pase completo de la lección 8.
Fijando los datos en el nodo de entrada. Esta es la más potente y la que la lección 5 te va a enseñar a fondo: n8n te deja fijar (pin) la salida de un nodo, de modo que el Webhook —o el nodo Code— "recuerde" exactamente estos datos sintéticos y los use en cada corrida sin que tengas que volver a inyectarlos. Es lo que vuelve la prueba reproducible de verdad. Por ahora quédate con que existe; la lección 5 la desarrolla.
La conexión que quiero que veas: los datos sintéticos que diseñaste en esta lección son los datos que vas a fijar en la lección 5, evaluar en la 7 y correr en el pase completo de la 8. No son un ejercicio suelto; son el insumo del resto del módulo. Guárdalos bien en cumbre-automations.
Una recomendación de organización que te va a servir en la lección 7: guarda junto a cada caso, además de sus datos, la respuesta esperada. Es decir, no solo "este es el pedido de 52 000", sino "este pedido de 52 000 debe clasificarse como manual_review". Todavía no vas a usar ese campo —las aserciones son la lección 7— pero anotarlo ahora, mientras diseñas el caso y tienes fresco en la cabeza qué debería pasar, es mucho más fácil que reconstruirlo después. El campo case que ya le pusiste es la etiqueta; agrégale un expected con la clasificación correcta, y tus fixtures quedan listos para evaluarse sin trabajo extra más adelante. Diseñar el dato y su respuesta correcta al mismo tiempo es un hábito que se paga solo.
Los datos sucios: la parte que casi todos saltan
Vale la pena detenerse en los datos sucios, porque es lo que separa una prueba de juguete de una prueba seria, y es lo que casi todos saltan.
Los datos reales son sucios. No llegan como en el folleto —montos redondos, nombres bien escritos, todos los campos presentes—. Llegan con la mugre del mundo real: un monto que viene como texto "3,500.00" en vez del número 3500, un nombre con espacios de sobra " bodega LA MONTAÑA ", un order_id en minúsculas cuando esperabas mayúsculas, un campo que a veces viene y a veces no, un carácter acentuado o una comilla que rompe tu parseo, una fecha en un formato distinto al que esperabas, un null donde esperabas un texto. Cada una de estas suciedades es un pedido que en producción va a pasar por order-triage, y si tu prueba nunca las vio, el workflow tampoco, y se va a topar con ellas por primera vez con un pedido real de por medio.
La disciplina es sencilla de enunciar y fácil de olvidar: por cada caso limpio que pruebas, prueba también su versión sucia. ¿Probaste un pedido normal? Prueba uno igual pero con el monto como texto. ¿Probaste un pedido con nombre? Prueba uno con el nombre lleno de espacios. Los dos casos dirty- del dataset de arriba son el mínimo; en un sistema real tendrías más. La pregunta guía es: "¿cómo llegaría este dato si el sistema de origen lo mandara mal?" —y ese "mal" incluye vacíos, tipos equivocados, formatos raros, duplicados y caracteres inesperados—.
Hay un beneficio extra en probar datos sucios con order-triage en particular, y es que su clasificador es un nodo AI Agent. Un agente de IA es, por naturaleza, más tolerante al desorden que un if rígido —puede que entienda "3,500.00" como tres mil quinientos sin que tú hagas nada—, pero también es más impredecible: quizás lo entiende, quizás no, quizás lo interpreta como 3.5. Probar los datos sucios contra el agente te dice cuál de esas tres cosas hace, que es información que no tienes hasta que la pruebas. Esto lo vas a explotar en las lecciones 6 y 7.
Errores comunes
Probar con un solo caso, el feliz (conceptual). Qué pasa: alguien genera o escribe un pedido bonito, ve que order-triage lo aprueba, y da la prueba por buena. Es el "corrió una vez y salió bien" de la lección 1, ahora en los datos. Por qué pasa: el caso feliz es el que tienes en la cabeza cuando piensas en tu workflow, así que es el que escribes primero, y es fácil parar ahí. Cómo detectarlo: cuenta tus casos de prueba y clasifícalos. Si todos son "normales" y ninguno es grande, incompleto, sucio o borde, tienes un solo maniquí. Cómo corregirlo: usa la familia de maniquíes como checklist —¿tengo el grande, el incompleto, el sucio, el borde?—. Un dataset de prueba sin al menos un caso difícil no está probando, está confirmando lo que ya sabías.
Usar datos reales "porque son más realistas" (práctico y riesgoso). Qué pasa: alguien copia pedidos reales de producción a su entorno de dev para probar con ellos. Ahora hay información personal de clientes de Cumbre en una laptop de desarrollo. Por qué pasa: los datos reales están a mano y se sienten más fieles. Cómo detectarlo: si tus datos de prueba tienen nombres, correos o montos que corresponden a clientes reales, estás exponiendo información personal. Cómo corregirlo: genera datos sintéticos. Son igual de fieles en la forma —que es lo que importa para la prueba— sin cargar el riesgo de exponer a nadie. Si de verdad necesitas que se parezcan a datos reales específicos, anonimízalos: reemplaza los nombres, correos y montos reales por falsos, conservando solo la estructura. Pero para la mayoría de las pruebas, inventar desde cero es más simple y más seguro.
Meter azar donde querías reproducibilidad (práctico). Qué pasa: alguien genera sus datos de prueba con valores al azar para que se vean variados, y después no entiende por qué su prueba da un resultado distinto cada vez. Por qué pasa: el azar parece "más realista" y es fácil agregarlo. Cómo detectarlo: si corres tu generador dos veces y obtienes datos distintos, tu prueba no es reproducible, y eso va a chocar de frente con la lección 5. Cómo corregirlo: genera de forma determinista —aritmética sobre un contador, listas que rotas, valores fijos—, no con Math.random(). Guarda el azar para pruebas de estrés donde la variedad es el punto; para verificar comportamiento, quieres las mismas entradas siempre.
Ejercicios
Ejercicio 1 — Diseña la familia de maniquíes. order-triage va a agregar una regla: los pedidos de clientes nuevos (que el CRM no conoce) van a revisión manual, sin importar el monto. Diseña cuatro casos de prueba sintéticos para cubrir esta regla nueva, con su etiqueta case y una nota de qué esperas. Piensa en la familia completa, no solo en el caso feliz.
Ver solución
Una familia razonable:
[
{ "case": "known-customer-small", "customer_name": "Café Aurora", "amount": 1000, "note": "cliente conocido, monto bajo → aprobar" },
{ "case": "new-customer-small", "customer_name": "Cafetería Recién Nacida", "amount": 1000, "note": "cliente NUEVO, monto bajo → revisión manual por la regla nueva" },
{ "case": "new-customer-large", "customer_name": "Startup del Café", "amount": 60000, "note": "cliente nuevo Y monto alto → revisión manual (dos razones)" },
{ "case": "known-customer-large", "customer_name": "Tostaduría del Sur", "amount": 60000, "note": "cliente conocido pero monto alto → revisión manual por el umbral" }
]
Por qué funciona: la regla nueva introduce una dimensión —cliente conocido/nuevo— que se cruza con la que ya existía —monto bajo/alto—. Una buena familia cubre las cuatro combinaciones de esas dos dimensiones, para verificar que cada razón de "revisión manual" funciona sola y que no se pisan entre sí. El caso new-customer-small es el crítico: es el único donde la regla nueva es la única razón para ir a revisión, así que si algo falla, ahí se ve.
Ejercicio 2 — Ensucia un caso limpio. Toma este pedido limpio y escribe tres versiones sucias de él, cada una con un tipo distinto de suciedad. Explica qué probaría cada una. Pedido limpio: { "order_id": "ORD-TEST-010", "customer_name": "Café Aurora", "amount": 2500 }.
Ver solución
Tres suciedades de distinta naturaleza:
{ "order_id": "ORD-TEST-010", "customer_name": "Café Aurora", "amount": "2.500" }
Prueba: el monto viene como texto con un separador de miles distinto (punto, estilo europeo/latino). ¿El workflow lo lee como 2500 o como 2.5? Es la más peligrosa: si lo lee como 2.5, un pedido de 2500 pesos parece de 2.5.
{ "order_id": "ORD-TEST-010", "customer_name": null, "amount": 2500 }
Prueba: el nombre viene como null, no como texto vacío "". Un workflow que revisa if name === "" no atrapa un null; son dos formas distintas de "falta el nombre".
{ "order_id": "ORD-TEST-010", "customer_name": "Café Aurora 🎉☕", "amount": 2500 }
Prueba: el nombre trae emojis y caracteres especiales. ¿El CRM los acepta? ¿Rompen algún parseo o alguna URL? Los caracteres inesperados en textos libres son una fuente clásica de fallas.
Por qué funciona: las tres suciedades son de tipos distintos —formato de número, valor nulo vs vacío, caracteres especiales—, y esa variedad es el punto. Ensuciar de una sola forma (siempre el mismo tipo de mugre) deja huecos; la realidad ensucia de todas las formas a la vez.
Ejercicio 3 — Determinista o no. Mira este fragmento de un nodo Code que genera montos de prueba y di si es reproducible. Si no lo es, arréglalo para que lo sea, conservando la variedad de montos.
const amount = Math.floor(Math.random() * 10000);
Ver solución
No es reproducible. Math.random() devuelve un número distinto cada vez, así que cada corrida del nodo genera montos diferentes. Una prueba con esta entrada da un resultado distinto en cada corrida, lo que hace imposible comparar el efecto de un cambio en el workflow contra el de un cambio en los datos.
Una forma determinista que conserva la variedad, usando el contador del bucle:
// Suponiendo que estás dentro de un for con el contador i:
const amount = 500 + (i * 137) % 9500; // varía entre corridas de i, pero es el mismo para el mismo i
El (i * 137) % 9500 produce montos que saltan por todo el rango —el 137 es un número que "revuelve" bien— pero de forma determinista: el pedido número 7 siempre tiene el mismo monto, corras el nodo cuando lo corras. Tienes variedad sin perder reproducibilidad.
Por qué funciona: la reproducibilidad no pelea con la variedad; pelea con el azar no controlado. Un generador puede producir cien montos muy distintos entre sí y aun así dar los mismos cien cada vez que corre, mientras la "variación" venga de algo fijo (el contador) y no de algo aleatorio (Math.random). Esa distinción es la que la lección 5 necesita para que tus pruebas se repitan idénticas.
Resumen y siguiente paso
En esta lección viste qué son los datos sintéticos —pedidos falsos pero representativos, los maniquíes de prueba de choque de tu workflow— y por qué no se prueba con datos reales: por privacidad (la información personal de los clientes no sale de producción) y por cobertura (los datos reales son casi todos casos felices, y no te dejan fabricar el caso difícil que necesitas). Aprendiste dos formas de generarlos: un dataset fijo escrito a mano, con casos etiquetados que cubren la familia completa —feliz, grande, incompleto, sucio, borde— y que vive versionado en cumbre-automations; y un nodo Code que los fabrica en memoria para volumen, de forma determinista para no perder la reproducibilidad. Y te detuviste en los datos sucios —montos como texto, nombres con espacios, valores nulos, caracteres raros—, la parte que casi todos saltan y la que más rompe workflows en producción, con la disciplina de "por cada caso limpio, prueba también su versión sucia".
Con esto marcas el segundo punto del checklist: usas datos sintéticos que cubren casos borde y datos sucios.
Antes de avanzar deberías poder: explicar en una frase por qué no se prueba con datos reales; nombrar la familia de casos que todo dataset de prueba debería cubrir; y decir por qué la generación determinista importa para una prueba reproducible.
Ya tienes un destino seguro (lección 2) y entradas seguras y variadas (esta lección). Pero hay un peligro que ni la llave sandbox ni los datos sintéticos resuelven del todo: el workflow todavía dispara sus efectos secundarios al correr. La lección 4 entra en el dry run y la protección de los efectos secundarios: qué es exactamente un dry run, por qué en n8n no es un botón sino un patrón de diseño que tú montas, y cómo cortar el workflow antes del nodo que escribe al CRM —o desviarlo a un nodo que no hace nada— para observar su comportamiento sin disparar la acción irreversible.
Recursos
- Data mocking and pinning — n8n Docs — cómo simular datos de prueba en n8n, incluido el uso de nodos como Code y Edit Fields para generar datasets.
- Code node — n8n Docs — el nodo Code, sus modos ("Run Once for All Items" vs por item) y sus límites en n8n 2.0 (sin HTTP ni sistema de archivos).
- Edit Fields (Set) node — n8n Docs — una alternativa sin código para fijar un dataset pequeño de prueba campo por campo.
- Data structure — n8n Docs — el formato de items de n8n (
{ json: {...} }), el que devuelve el nodo Code al generar pedidos.