Desarrollo

Cómo el TDD moldeó HTML6

Agustin Brage
18 Sep 2026
4 min de lectura
TDD Testing HTML6
Cómo el TDD moldeó HTML6

Test-first, no "agregar tests después"

Antes de HTML6, mi hábito de testing era el común: construir la funcionalidad, y después agregar un puñado de tests. Confirmar que los casos obvios funcionan, seguir adelante.

Mi jefe en Eldøy me exigió algo más estricto, una práctica llamada Desarrollo Guiado por Pruebas (TDD, por sus siglas en inglés): escribir un test unitario enfocado para una función antes de escribirla. Asegurarme de que cubriera de verdad el rango de inputs que esa función podía recibir, no solo el camino feliz.

repetir, un caso de test a la vez Test que falla red Hacerlo pasar green Refactorizar sigue en verde
El ciclo detrás de cada función en HTML6: primero un test que falla, después el cambio mínimo que lo hace pasar, y una limpieza antes de pasar al siguiente caso.

Al principio se sentía más lento: escribir el test antes de la función significa decidir qué tiene que hacer antes de meterte en cómo lo va a hacer. Dejó de sentirse como carga extra en cuanto ese hábito hizo que cada función nueva arrancara desde una especificación clara y acotada, en vez de una página en blanco.

Construyendo función por función

HTML6 compila una plantilla a través de un pipeline de piezas chicas y separadas:

  • Parser — convierte HTML crudo en un árbol
  • Transpiler — convierte ese árbol en una función de renderizado
  • Masking — esconde los tags especiales (if, elsif, else, map) detrás de placeholders durante la compilación
  • Chain-walker — resuelve las secuencias de if/elsif/else entre elementos hermanos
  • Topological sort — ordena la compilación de componentes según sus dependencias

Cada una vive en su propio archivo. Cada una tuvo su propia suite de tests antes de conectarse con la siguiente pieza.

Código con una suite de tests real alrededor es código que podés cambiar con confianza. Código que solo estás probando indirectamente, a través de todo el pipeline, es código al que le tenés miedo.

Un bug que nunca llegó a producción

Acá es donde test-first se gana el nombre de verdad. El test no se escribe después de encontrar un bug. Escribirlo es cómo se encuentra el bug.

Tomá una plantilla simple: recorré una lista y renderizá cada item.

<li map="p of ps">{{p}}</li>

Cubrir el rango de inputs, como pide el hábito, significa testear qué pasa cuando la lista misma es null, no solo cuando está vacía. Escribir ese test fue lo que sacó a la luz el problema: el código compilado llamaba a .map() directamente sobre lo que llegara, y .map() sobre null explota.

Rojo primero:

return mapArg.map(function(project) { ... })

Después el fix, una línea:

return (mapArg || []).map(function(project) { ... })

Verde. Y el test que encontró el bug es el mismo que ahora lo cuida de que vuelva:

test('map - empty', async ({ t }) => {
  var page = '<ul><li map="p of ps">{{p}}</li></ul>'
  var renderer = html.compile(page)
  var data = { ps: null }
  var result = renderer.render(data)
  t.equal(result, '<ul></ul>')
})

Ese es el hábito real que construye test-first: no "nunca romper nada", sino "encontrar vos mismo el quiebre, antes que cualquier otro, testeando el caso que de otra forma te habrías salteado".

Lo que cambió

Esta disciplina es gran parte de por qué después pude encarar reescribir todo el compilador de HTML6 para que fuera más rápido con confianza real, en lugar de que fuera un salto de fe. Reescribir un código que está genuinamente cubierto, función por función, es un tipo de riesgo distinto a reescribir uno sostenido por chequeos manuales y esperanza.

¿Disfrutaste este artículo?

Seguime para más contenido sobre desarrollo web, diseño y tecnología.