Talently
Talently
Testing Library

Testing Library

La librería de testing centrada en el comportamiento del usuario

Testing Library es una familia de librerías de testing para JavaScript que promueve escribir tests desde la perspectiva del usuario en lugar de los detalles de implementación. Disponible para React, Vue, Angular, Svelte y otros frameworks, provee utilidades para buscar elementos como los usuarios los perciben, mediante texto, roles ARIA y labels, haciendo los tests más robustos y significativos.

JavaScriptTypeScriptReactTesting

Demanda del mercado

Testing Library es la librería de testing de componentes más adoptada en el ecosistema React y tiene alta demanda en cualquier posición frontend que incluya testing. Es el estándar recomendado por el equipo de React para tests de componentes.

Estándar de testing en ecosistema ReactAlta demanda en posiciones frontend con testingRecomendada oficialmente por el equipo de React

Requisitos técnicos

Intermediate

Requiere dominio de JavaScript o TypeScript y del framework de componentes usado. Familiaridad con conceptos de testing como mocking, assertions y Jest es esencial. Conocimiento de accesibilidad web y roles ARIA facilita escribir tests con los selectores correctos.

Casos de uso

Proyectos Reales

Testing Library se utiliza para desarrollar:

  • Tests de componentes React, Vue o Angular en aislamiento
  • Tests de integración de múltiples componentes que interactúan
  • Tests de custom hooks con renderHook
  • Tests de formularios con validaciones y flujos de usuario

Tipos de Empresa

Testing Library es adoptado por:

  • Equipos frontend con React, Vue o Angular que incluyen testing
  • Empresas con cultura de TDD o BDD en el frontend
  • Startups con cobertura de tests en componentes críticos
  • Organizaciones con requisitos de calidad y cobertura de código

Escenarios de Producción

Testing Library es ampliamente utilizado en entornos productivos como:

  • Tests unitarios de componentes en pipelines CI/CD
  • Tests de regresión de componentes críticos de la UI
  • Tests de accesibilidad integrados en el flujo de desarrollo
  • Tests de formularios complejos con validaciones y estados

Escalabilidad

Testing Library ofrece múltiples mecanismos para escalar aplicaciones:

  • Integración con Jest o Vitest para ejecución rápida
  • MSW para mockear APIs en tests de integración
  • Custom render con providers para componentes con contextos
  • Screen.debug para debugging visual del DOM en tests

Ventajas y Desventajas

Ventajas

Selectores basados en accesibilidad que promueven interfaces accesibles por diseño.

Tests resistentes a refactoring ya que no dependen de detalles de implementación.

API intuitiva con userEvent que simula interacciones reales del usuario.

Desventajas

Curva de aprendizaje inicial para developers acostumbrados a testear por implementación.

Algunos casos de uso avanzados requieren configuración adicional de providers y mocks.

No cubre tests E2E que requieren un navegador real con todas las APIs del navegador.

Comparación

Ventajas de Enzyme

  • Mayor acceso a detalles internos del componente
  • Más fácil para testear estado interno y métodos
  • Más familiar para developers de React antiguo

Consideraciones

Enzyme permite acceder a los internos de los componentes como estado y métodos, pero genera tests frágiles que se rompen con refactoring. Testing Library promueve tests más robustos centrados en el comportamiento visible, siendo la opción recomendada actualmente.

Preguntas básicas

Los tests que verifican el estado interno, los nombres de funciones o la estructura interna del componente se rompen con refactoring aunque el comportamiento visible no cambie. Testing Library promueve testear lo que el usuario ve y puede hacer, haciendo los tests más resilientes a cambios de implementación y más significativos como documentación del comportamiento.
getBy lanza un error si el elemento no existe, siendo adecuado cuando el elemento debe estar presente. queryBy devuelve null si no existe, siendo adecuado para verificar ausencia de elementos. findBy devuelve una Promise y espera a que el elemento aparezca, siendo adecuado para elementos que aparecen de forma asíncrona.
Los queries por clase CSS o id son frágiles ante cambios de estilo o refactoring del markup. Los queries por getByRole o getByText reflejan cómo los usuarios y los lectores de pantalla perciben la interfaz, siendo más resistentes a cambios de implementación y promoviendo que los componentes sean accesibles para que los tests funcionen.
userEvent simula las interacciones del usuario de forma más realista disparando todos los eventos que ocurrirían en una interacción real como mousedown, focus, keydown y keyup al escribir en un input. fireEvent dispara un único evento DOM sintético. userEvent es preferible por generar interacciones más cercanas a las del usuario real.
Usando Mock Service Worker con msw que intercepta las peticiones a nivel de Service Worker y devuelve respuestas mockeadas, o mockeando el módulo de fetch o axios con jest.mock. MSW es preferible porque intercepta las peticiones reales sin modificar el código del componente, siendo más cercano al comportamiento real.
Testing Library con Jest o Vitest es más rápido y adecuado para la mayoría de tests de componentes en aislamiento. Cypress Component Testing es preferible para componentes que dependen de APIs del navegador que jsdom no implementa como IntersectionObserver, ResizeObserver o APIs de Canvas. Testing Library cubre el 90% de los casos con menor overhead.
Usando renderHook de @testing-library/react que monta el hook en un componente de test mínimo y expone su valor de retorno. Se puede acceder al resultado con result.current y actualizar el hook con act para disparar cambios de estado, verificando el comportamiento del hook sin necesidad de crear un componente real para probarlo.
Para tests de componentes y tests de integración de múltiples componentes donde se quiere verificar el comportamiento desde la perspectiva del usuario, tests de formularios con validaciones, tests de accesibilidad usando queries por rol y label, y tests de hooks con renderHook. Es el complemento ideal de los tests unitarios de lógica pura con Jest.

Preguntas técnicas

Creando una función customRender que envuelve el render de Testing Library con los providers necesarios como el store de Redux, el router de React, el theme provider o el contexto de autenticación. Se exporta esta función en lugar del render de Testing Library y todos los tests la usan, garantizando que los componentes tienen acceso a sus dependencias sin repetir la configuración.
Usando expect(screen.queryByText('texto')).not.toBeInTheDocument() con queryBy que devuelve null en lugar de lanzar error cuando el elemento no existe. Usar getBy para verificar ausencia lanzaría un error antes de que expect pueda hacer la assertion, por lo que queryBy es siempre la variante correcta para verificar que algo no está presente.
Envolviendo las interacciones que disparan actualizaciones asíncronas en act o usando waitFor que reintenta la assertion hasta que pasa o expira el timeout. Con userEvent las interacciones se manejan automáticamente con act. findBy también espera automáticamente a que el elemento aparezca sin necesidad de waitFor explícito.
Usando queries por getByRole con el rol ARIA correcto y el nombre accesible del elemento, verificando que los formularios tienen labels correctos con getByLabelText, usando jest-axe para ejecutar análisis de accesibilidad automático sobre el componente renderizado y verificando que los mensajes de error están asociados correctamente con sus inputs con aria-describedby.
Envolviendo el componente bajo test en el Provider del contexto con el valor deseado para el test dentro del wrapper del customRender, o usando la opción wrapper en render para componentes que consumen contexto. Para testear el comportamiento con distintos valores del contexto se llama al render con distintos valores del Provider.
Llamando a screen.debug() que imprime el HTML actual del DOM de prueba en la consola, o screen.debug(element) para imprimir solo un elemento específico. Es la herramienta principal para entender qué está renderizando el componente en el momento del fallo y qué selectores están disponibles cuando un query no encuentra el elemento esperado.
Renderizando el formulario, interactuando con los campos usando userEvent.type y userEvent.clear para simular la escritura, disparando el submit con userEvent.click en el botón de envío, y verificando con expect que los mensajes de error aparecen con getByText o getByRole para los mensajes de validación, y que los mensajes desaparecen al corregir los campos.
Usando jest.mock('nombre-del-modulo') para mockear módulos completos, jest.spyOn para mockear métodos específicos manteniendo el resto del módulo real, o mockResolvedValue y mockRejectedValue para controlar las respuestas de funciones que devuelven Promises. Para APIs de red se prefiere MSW que mocka a nivel de red sin modificar el código.

Preguntas avanzadas

Definiendo tests de comportamiento para cada componente que verifican las interacciones y estados visibles, tests de accesibilidad con jest-axe para cada componente, tests de los casos edge como estados vacíos y errores, y tests de integración para combinaciones frecuentes de componentes. Los tests documentan el comportamiento esperado y sirven como contrato del API pública de cada componente.
Configurando MSW con los handlers que definen las respuestas para cada endpoint, iniciando el servidor mock en setupTests con server.listen() y reseteando los handlers en afterEach con server.resetHandlers() para garantizar aislamiento entre tests. En tests específicos se pueden sobrescribir handlers con server.use() para simular errores o casos edge sin afectar otros tests.
Verificando que los tests usan queries accesibles como getByRole y getByLabelText en lugar de getByTestId o selectores CSS, que los tests verifican comportamiento visible en lugar de estado interno, que los tests fallan por razones correctas simulando bugs reales, que el ratio de falsos positivos y falsos negativos es bajo y que los tests son rápidos y no tienen waitFor innecesarios con timeouts arbitrarios.
Usando fake timers de Jest con jest.useFakeTimers() para avanzar el tiempo manualmente y verificar el estado después de la animación, o usando waitFor para esperar a que el elemento llegue al estado final después de la transición. Para animaciones de entrada se espera a que el elemento sea visible con waitFor y para las de salida se espera a que desaparezca con waitForElementToBeRemoved.
Migrando test a test comenzando por los componentes con más cambios frecuentes para obtener el beneficio de tests más robustos antes, usando el codemod de migración disponible para cambios mecánicos, reescribiendo los tests que acceden a state o props internos para que verifiquen el comportamiento visible en lugar de la implementación, y aprovechando la migración para mejorar la accesibilidad de los componentes que no tienen queries accesibles.
Estableciendo reglas de ESLint con eslint-plugin-testing-library que detectan anti-patrones como el uso incorrecto de queries, revisando en code review que los tests no acceden a detalles de implementación, escribiendo tests que documentan el comportamiento esperado de cada componente desde la perspectiva del usuario y actualizando los tests cuando el comportamiento cambia intencionalmente como parte del proceso de desarrollo.

Errores comunes en entrevistas

Abusar de data-testid cuando existen queries accesibles como getByRole o getByLabelText refleja no entender la filosofía de Testing Library. data-testid debe ser el último recurso cuando no hay selector accesible disponible, no el default. Su uso excesivo indica que el componente puede no ser accesible.
Usar getBy para verificar ausencia de elementos genera un error en lugar de una assertion fallida, haciendo el mensaje de error confuso. No conocer estas variantes y sus casos de uso refleja experiencia limitada con Testing Library.
fireEvent dispara eventos sintéticos individuales que no replican fielmente el comportamiento del usuario. userEvent simula la secuencia completa de eventos que ocurren en una interacción real. Preferir fireEvent por desconocer userEvent refleja práctica desactualizada con Testing Library.
Verificar que el estado de React tiene cierto valor o que se llamó a una función interna del componente rompe la abstracción y genera tests frágiles. Testing Library deliberadamente no expone acceso al estado interno para forzar tests de comportamiento visible.
Mockear fetch o axios directamente con jest.mock en lugar de usar MSW genera mocks más frágiles y menos realistas. No conocer MSW como herramienta estándar para mockear APIs en tests de integración refleja desactualización en el ecosistema de testing JavaScript.
Repetir la configuración de providers en cada test o tener tests que fallan porque el componente necesita un contexto no disponible refleja no haber trabajado en proyectos reales con Testing Library donde los componentes siempre tienen dependencias de contexto.