Igualdad sensible al formato.
Una prueba verifica el comportamiento comparando la representación en cadena de un objeto (toString(), JSON.stringify(), HTML renderizado) con un literal de cadena esperado, acoplando la prueba al formato accidental en lugar de a los valores que realmente importan.
##Signs and Symptoms
Reconoces la Igualdad sensible al formato cuando el lado real de una aserción serializa un objeto a texto y su lado esperado es un literal de cadena que agrupa muchos campos junto con separadores, comillas, corchetes y espacios en blanco.
Señales reveladoras:
- El valor real proviene de
.toString(),String(x), un literal de plantilla,JSON.stringify(...),wrapper.html(),el.outerHTMLo un snapshot de un bloque serializado. - El valor esperado es una cadena literal larga (a menudo pegada de una ejecución fallida anterior) y no puedes saber de un vistazo qué parte de ella es lo que se está probando.
- La prueba se rompe ante cambios que no afectan al comportamiento: claves reordenadas, espacios en blanco añadidos o eliminados, precisión numérica, formato de fecha, configuración regional, zona horaria, u orden de iteración de
Map/Set/objetos.
// Comparando una forma serializada con un literal de cadena
expect(JSON.stringify(user)).toBe('{"name":"Bob","age":30}');
// Comprobando la salida de toString()
expect(order.toString()).toBe('Order[id=7, total=42.00, items=2]');
// Comparando todo el HTML renderizado con un literal
expect(wrapper.html()).toBe('<div class="card"><h2>Bob</h2><span>30</span></div>');
// Comparación de cadenas sensible a la configuración regional/zona horaria
expect(d.toString()).toBe('Mon Jun 15 2026 00:00:00 GMT+0000 (UTC)');
##Reasons for the Problem
Por qué ocurre
- Es rápido y fácil. Como señalan van Deursen et al. en Refactoring Test Code, es rápido calcular un resultado real, convertirlo en una cadena y compararlo con un literal de cadena que representa el valor esperado; a menudo el literal se copia directamente de una ejecución fallida. Las herramientas de snapshots hacen esto aún más tentador.
- El objeto no tiene una igualdad significativa (
equals/comparador profundo) configurada, o el grafo de objetos es grande, de modo que volcarlo a una cadena parece más sencillo que comprobar campo por campo.
Por qué es perjudicial
- Fragilidad / fallos falsos. La cadena arrastra muchos detalles irrelevantes: comas, comillas, espacios, orden de las claves, precisión de coma flotante, configuración regional, zona horaria, orden de iteración de las colecciones. Cada vez que cambia el formato de
toString()/serialización, pruebas no relacionadas empiezan a fallar aunque el comportamiento sea correcto. Esta es una causa clásica de Prueba frágil. - Mantenibilidad. Un único cambio de formato o de biblioteca obliga a editar muchas pruebas, y el enorme literal esperado es tedioso de actualizar y fácil de equivocar sutilmente.
- Legibilidad / intención oscurecida. Un valor esperado que es un muro de texto oculta lo que en realidad se está verificando; un revisor no puede ver el único campo que le importa a la prueba.
- Falsa confianza. Un bloque convertido en cadena puede pasar por los motivos equivocados (dos estados distintos que se serializan al mismo texto), y empuja a los desarrolladores a volver a registrar el literal/snapshot cuando falla, sin comprobar que el nuevo valor sea realmente correcto.
- Inestabilidad (flakiness). Las cadenas sensibles a la configuración regional, la zona horaria y el orden hacen que los resultados dependan del entorno en el que se ejecuta la prueba.
##Treatment
Haz aserciones sobre los datos, no sobre su representación.
- Compara valores estructurados con igualdad profunda en lugar de igualdad de cadenas (
toEqual/toStrictEqual), que es independiente del orden y de los espacios en blanco para los objetos. - Verifica solo los atributos relevantes con comparadores parciales (
toMatchObject,expect.objectContaining) para que un cambio de formato en otro lugar no pueda romper la prueba. - Parsea, no compares cadenas. Cuando recibas una carga útil serializada (por ejemplo, un cuerpo JSON de una API), parséala de nuevo a una estructura y compara estructuras.
- Introduce un método de igualdad/comparación en el objeto (la refactorización que recomiendan van Deursen et al.) y comprueba la igualdad de objetos en lugar de la igualdad de
toString(). - Si debes comparar una salida serializada, canonízala primero —ordena las claves, fija la configuración regional/zona horaria, fija la precisión numérica— y prefiere un snapshot revisado a un literal en línea pegado a mano.
- Para pruebas de DOM/componentes, consulta de forma semántica (Testing Library
getByRole,toHaveTextContent) en lugar de comparar todo el HTML.
// Antes — Igualdad sensible al formato
expect(JSON.stringify(user)).toBe('{"name":"Bob","age":30}');
// Después — igualdad estructural (independiente del orden de claves / espacios en blanco)
expect(user).toEqual({ name: 'Bob', age: 30 });
// Después — comprueba solo el campo bajo prueba
expect(user).toMatchObject({ age: 30 });
// Antes — comparación de cadenas de una carga útil de API
expect(res.text).toBe('{"id":7,"total":42}');
// Después — compara estructuras parseadas
expect(JSON.parse(res.text)).toEqual({ id: 7, total: 42 });