De instantáneas a comportamiento: migrar a React Testing Library
En proyectos típicos, las pruebas suelen centrarse en la estructura del código en lugar de en el funcionamiento real. Las pruebas de instantánea capturan el estado del DOM, pero fallan con cualquier refactorización: cambiar clases CSS, reordenar atributos o optimizar la renderización. Los errores lógicos reales permanecen sin detectar.
Un ejemplo problemático con Enzyme
describe("UserProfileCards", () => {
it("should render", () => {
const wrapper = shallow(
<Provider store={store}>
<UserProfileCards items={mockedUserProfiles} />
</Provider>
)
expect(wrapper).toMatchSnapshot()
})
})
Esta prueba no ofrece confianza real sobre el comportamiento del componente. Verifica la estructura, no lo que el usuario realmente experimenta.
Acoplamiento en implementación: falsos positivos
Las pruebas ligadas a detalles internos generan un problema doble: fallan durante refactorizaciones y pasan por alto errores reales.
Considera un componente CollapseIcon con un estado opened:
import CollapseIcon from "./CollapseIcon"
import { shallow } from "enzyme"
describe("CollapseIcon", () => {
it("should render", () => {
const wrapper = shallow(<CollapseIcon opened={false} />)
expect(wrapper).toMatchSnapshot()
})
it("should react to closed", () => {
const wrapper = shallow(<CollapseIcon opened={false} />)
expect(wrapper.find(".collapse__icon").hasClass("collapseIcon_closed")).toEqual(true)
})
it("should react to opened", () => {
const wrapper = shallow(<CollapseIcon opened={true} />)
expect(wrapper.find(".collapse__icon").hasClass("collapseIcon_opened")).toEqual(true)
})
})
Problemas:
- Las instantáneas no detectan errores en la lógica de animaciones.
- Las comprobaciones de clases fallan al refactorizar estilos.
- Las pruebas pasan incluso si las animaciones están rotas.
Otro caso: acoplamiento fuerte con constantes de localización:
it("should render no-answers button", () => {
const button = getButton(mockCommentsList[0])
const noAnswersText = `${mockedTranslation.t(`${tNamespace}no-answers`)}
expect(button.text()).toBe(noAnswersText)
})
Cambiar la clave en tNamespace rompe la prueba, aunque el texto del botón sea correcto. Solución: mover las constantes a un módulo compartido importado tanto por el componente como por las pruebas.
Descripciones de pruebas ambiguas empeoran la situación:
- "should show tooltip" — sin condiciones.
- "should render without tooltipLabel" — sin resultado esperado.
React Testing Library: probando el comportamiento del usuario
RTL cambia el paradigma: las pruebas simulan acciones reales del usuario y ignoran los detalles internos. No se tiene acceso al estado, props ni métodos — solo a la interfaz visible.
Beneficios de RTL:
- Enfoque centrado en el usuario: clics, escritura, lectura de pantalla.
- Seguro frente a refactorizaciones: independiente de nombres de clases, IDs o estado interno.
- API:
render(),screen.getByRole(),fireEvent.click(),waitFor(). - Soporte asíncrono:
findByRole()para carga de datos. - Accesibilidad:
getByLabelText()asegura etiquetado adecuado.
RTL está diseñado para resiliencia: las pruebas reflejan el uso real, no la estructura del DOM.
Checklist para pruebas de alta calidad
Escribir pruebas
- Propósito: define claramente lo que se está probando (por ejemplo, "muestra tooltip cuando isTooltipShow=true").
- Perspectiva del usuario: acciones como lo haría un usuario real —
getByRole('button'),fireEvent. - Aislamiento: mocks para APIs; ninguna dependencia entre pruebas.
- Descripciones: frases completas legibles sin código.
- Cobertura: camino feliz + casos extremos + estados de error.
Revisar pruebas
- ¿El objetivo es claro?
- ¿Se evitan detalles de implementación (clases, estado)?
- ¿La prueba está aislada?
- ¿Las descripciones son informativas?
- ¿Los comentarios son constructivos?
Organizar la migración del equipo
Organiza un taller de migración: reúne pruebas problemáticas, analiza ejemplos y transita a RTL. Recomendaciones:
- Divide las sesiones en bloques de 45 minutos con práctica hands-on.
- Refactoriza pruebas juntos mediante programación en pareja.
- Prioriza la práctica sobre la teoría.
Migración de legacy: escribe nuevas pruebas en RTL y reescribe gradualmente las antiguas. Caso Airbnb: 3.500 archivos reescritos en 6 semanas usando una pipeline impulsada por LLM (75% automatizada).
Conclusiones clave
- Cambio de mentalidad: de markup a comportamiento del usuario.
- RTL vs Enzyme: RTL bloquea el acceso interno; Enzyme lo fomenta.
- Checklists: obligatorios para escribir y revisar.
- Talleres: diálogo supera monólogo.
- Migración: la automatización acelera el progreso, pero entender la filosofía es esencial.
— Editorial Team
Aún no hay comentarios.