Jest
react native
mobile development
testing
monitoring
quality-assurance
Cuando construyes una aplicación móvil, el verdadero reto no es escribir código, es asegurar que funcione bien hoy, mañana y después de futuras modificaciones. Sin testing ni monitoreo, ocurre que cada cambio en el código es un riesgo, los bugs llegan a producción sin que te des cuenta, dependes del usuario final para saber si algo falló.
Por otro lado con una estrategia adecuada de pruebas y monitoreo podemos, detectar errores antes de que lleguen al usuario, reducir costos de mantenimiento y soporte, como tambien tomar decisiones informadas con datos reales del funcionamiento de la app.
Testing = prevención Monitoreo = detección y análisis
Y ambos son complementarios.
Probar significa verificar que el código hace lo que debería hacer, de manera consistente y sin efectos inesperados. Cuando no hay pruebas automatizadas, la única forma de validar cambios es entrar a la app, navegar, tocar botones y esperar no romper nada. Esto es costoso, lento y muy poco confiable.
Con testing automatizado:
| Tipo de test | Objetivo | Herramienta | Ejemplo de uso |
|---|---|---|---|
| Unitario | Validar lógica pura | Jest | verificar cálculos, validaciones, formateo de datos |
| De componentes (UI) | Validar comportamientos de pantalla | React Native Testing Library | verificar que un botón incremente un contador |
| Integración | Validar interacción entre módulos | Jest + mocks | validar que un componente llame correctamente a un servicio |
Regla clave: los tests deben validar comportamientos, no implementaciones.
Primero, algo simple: una función que calcula el total de una compra.
1// utils/calculateTotal.ts 2export const calculateTotal = (price: number, qty: number) => price * qty;
Creemos un test que valide ese comportamiento:
1// __tests__/calculateTotal.test.ts 2import { calculateTotal } from "../utils/calculateTotal"; 3 4test("calcula correctamente el total", () => { 5 expect(calculateTotal(10, 3)).toBe(30); 6});
Con este test garantizas que si alguien cambia esa función o su comportamiento, serás alertado inmediatamente.
Aquí no probamos cómo está hecho el componente, sino lo que hace cuando el usuario interactúa.
1// components/Counter.tsx 2import React, { useState } from "react"; 3import { Button, Text } from "react-native"; 4 5export const Counter = () => { 6 const [count, setCount] = useState(0); 7 8 return ( 9 <> 10 <Text testID="count-label">{count}</Text> 11 <Button title="Incrementar" onPress={() => setCount(count + 1)} /> 12 </> 13 ); 14};
Test:
1// __tests__/Counter.test.tsx 2import React from "react"; 3import { render, fireEvent } from "@testing-library/react-native"; 4import { Counter } from "../components/Counter"; 5 6test("incrementa el contador al presionar", () => { 7 const { getByText, getByTestId } = render(<Counter />); 8 9 fireEvent.press(getByText("Incrementar")); 10 11 expect(getByTestId("count-label").props.children).toBe(1); 12});
Qué estamos validando:
Aunque los tests previenen errores, ningún sistema está libre de fallas en producción. Por lo tanto, necesitas saber qué pantalla se estaba usando cuando falló, qué acción ejecutó el usuario, qué datos estaban en juego; ahí entra el logging estructurado.
1console.log("User logged in", user);
Problemas:
1console.log(JSON.stringify({ 2 event: "USER_LOGIN", 3 userId: user.id, 4 timestamp: Date.now(), 5}));
Ventajas:
1// utils/logger.ts 2export const logEvent = (event: string, payload = {}) => { 3 console.log(JSON.stringify({ event, payload, timestamp: Date.now() })); 4};
Uso:
1logEvent("API_REQUEST", { endpoint: "/products" });
Este patrón permite centralizar la responsabilidad del logging.
Una de las dudas más frecuentes al comenzar a testear en React Native es: “¿Debo testear todo mi código?”. La respuesta es no, testear no significa replicar cada componente o línea de código, significa proteger las partes del sistema que, si fallan, afectan directamente al usuario o al negocio.
A continuación se desarrollan cuatro buenas prácticas esenciales aplicadas específicamente a proyectos con React Native CLI.
Testear la lógica que pueda romper la app: En React Native, la mayor parte de las decisiones importantes no se toman en los componentes, sino en:
Esa lógica suele ser independiente de la UI, lo que facilita testearla sin necesidad del renderizado de una pantalla.
1// utils/formatCurrency.ts 2export const formatCurrency = (amount: number) => `$${amount.toFixed(2)}`;
Test unitario:
1test("formatea un número a moneda", () => { 2 expect(formatCurrency(10)).toBe("$10.00"); 3});
¿Por qué importa? Si alguien modifica esta función en el futuro (por ejemplo, para soportar otra moneda), un test evitará que introduzca un error sin querer.
Casos típicos en una app móvil:
| Caso crítico | Riesgo si falla | Qué testear |
|---|---|---|
| Login | El usuario no puede usar la app | Validación de formularios, llamadas al backend |
| Procesos de compra/pago | Pérdidas económicas | Cálculos, totales, métodos de pago |
| Formularios con reglas | Mal funcionamiento del flujo | Mensajes de error y estados del botón |
Esto te da cobertura del 80% del riesgo con 20% de esfuerzo.
__DEV__) vemos la consola, pero en producción la app corre dentro de un dispositivo al que no tenemos acceso. Por eso, los logs deben ser estructurados, consistentes y con contexto.1console.log("Error en el login");
1logEvent("LOGIN_FAILED", { 2 email, 3 reason: error.message, 4});
Este formato permite:
Implementación mínima en React Native CLI:
1// utils/logger.ts 2export const logEvent = (event: string, payload = {}) => { 3 const log = { event, payload, timestamp: Date.now() }; 4 5 if (__DEV__) { 6 console.log(JSON.stringify(log, null, 2)); 7 } else { 8 // producción → enviar a un proveedor externo 9 // Sentry.captureMessage(JSON.stringify(log)); 10 } 11};
console.log sin estructuraEn React Native CLI, la calidad de la app no solo depende de lo bien que esté desarrollada, sino de lo bien que puedas saber cuándo algo deja de funcionar, el testing asegura que tu app funciona como debe y el monitoreo asegura que sabrás cuando deje de hacerlo. Una app profesional requiere ambos.