Las pruebas de componentes son un buen punto de partida para comenzar a demostrar código de prueba práctico. Las pruebas de componentes son más sustanciales que las pruebas de unidades simples y menos complejas que pruebas de extremo a extremo y demuestran la interacción con el DOM. Más filosóficamente, el uso de React ha facilitado a los desarrolladores web el pensamiento de sitios web o aplicaciones web como componentes.
Por lo tanto, probar componentes individuales, independientemente de la complejidad que sean, es una buena para probar una aplicación nueva o existente.
En esta página, se explica cómo probar un componente pequeño con código externo complejo dependencias. Es fácil probar un componente que no interactúa con ningún otro código, como hacer clic en un botón y confirmar que un número aumenta. En realidad, muy poco código es así, y probar código que no tiene interacciones pueden tener un valor limitado.
(esto no pretende ser un instructivo completo, sino una sección posterior, “Pruebas automáticas) en la práctica, probaremos un sitio real con código de muestra que que puedes usar como instructivo. Sin embargo, esta página aún abarcará varios ejemplos de pruebas prácticas de componentes).
El componente que se está probando
Usaremos Vitest y su entorno de JSDOM para probar un componente de React. Esto permite ejecutamos rápidamente las pruebas con Node en la línea de comandos mientras emulamos un navegador.
Este componente de React llamado UserList
recupera una lista de usuarios de la red
y te permite seleccionar uno de ellos. La lista de usuarios se obtiene a través de
fetch
dentro de una useEffect
, y el controlador de selección se pasa
Context
Este es su código:
import React, { useEffect, useState, useContext } from 'react';
import { UserContext } from './UserContext.tsx';
import { UserRow } from './UserRow.tsx';
export function UserList({ count = 4 }: { count?: number }) {
const [users, setUsers] = useState<any[]>([]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users?_limit=' + count)
.then((response) => response.json())
.then((json) => setUsers(json));
}, [count]);
const c = useContext(UserContext);
return (
<div>
<h2>Users</h2>
<ul>
{users.map((u) => (
<li key={u.id}>
<button onClick={() => c.userChosen(u.id)}>Choose</button>{' '}
<UserRow u={u} />
</li>
))}
</ul>
</div>
);
}
Este ejemplo no demuestra las prácticas recomendadas de React (por ejemplo, usa
fetch
dentro de useEffect
), pero es probable que la base de código contenga muchos casos.
les gusta. Más precisamente, estos casos pueden parecer tercos a probar al principio.
una mirada. Una sección futura de este curso
hablará sobre cómo escribir código que se puede probar
en detalle.
Aquí están los elementos que estamos probando en este ejemplo:
- Verifica que se creen algunos DOM correctos en respuesta a los datos de la red.
- Confirma que, cuando un usuario hace clic en él, se active una devolución de llamada.
Cada componente es diferente. ¿Por qué es interesante probar este tema?
- Usa el
fetch
global para solicitar datos reales de la red, que podría ser inestable o lenta cuando se hace la prueba. - Importa otra clase,
UserRow
, que quizás no queramos probar de forma implícita. - Usa un
Context
que no forma parte específicamente del código que se está probando. por lo general, la proporciona un componente superior.
Escribe una prueba rápida para comenzar
Podemos probar rápidamente algo muy básico sobre este componente. Para ser claros, este
este ejemplo no es muy útil. Pero es útil configurar el código estándar en un grupo
llamado UserList.test.tsx
(recuerda que los ejecutores de pruebas como Vitest, por
De forma predeterminada, ejecuta archivos que terminan con .test.js
o similares, incluido .tsx
):
import { vi, test, assert, afterAll } from 'vitest';
import { render } from '@testing-library/react';
import { UserList } from './UserList.tsx';
import React, { ContextType } from 'react';
test('render', async () => {
const c = render(<UserList />);
const headingNode = await c.findAllByText(/Users);
assert.isNotNull(headingNode);
});
Esta prueba afirma que, cuando se renderiza el componente, contiene el texto "Users".
Funciona aunque el componente tenga un efecto secundario de enviar un fetch
a
la red. El fetch
todavía está en progreso al final de la prueba, sin
establecer extremo. No podemos confirmar que se muestra información del usuario cuando
finaliza la prueba, al menos sin esperar un tiempo de espera.
fetch()
de prueba
La simulación es el acto de reemplazar una función o clase real por algo el control para una prueba. Esta es una práctica común en casi todos los tipos de pruebas, excepto las pruebas de unidades más simples. Este tema se abordará más a fondo en Aserciones y otras primitivas.
Puedes simular fetch()
para tu prueba, de modo que se complete rápidamente y muestre
datos que esperas, y no "del mundo real" o desconocidos. fetch
es una entidad global,
lo que significa que no tenemos que import
o require
en nuestro código.
En Vitest, puedes simular un global llamando a vi.stubGlobal
con un especial
objeto que muestra vi.fn()
: esto crea un modelo que podemos modificar más adelante. Estos
se analizarán con más detalle en una sección posterior de este curso, pero
puedes verlas en práctica en el siguiente código:
test('render', async () => {
const fetchMock = vi.fn();
fetchMock.mockReturnValue(
Promise.resolve({
json: () => Promise.resolve([{ name: 'Sam', id: 'sam' }]),
}),
);
vi.stubGlobal('fetch', fetchMock);
const c = render(<UserList />);
const headingNode = await c.queryByText(/Users);
assert.isNotNull(headingNode);
await waitFor(async () => {
const samNode = await c.queryByText(/Sam);
assert.isNotNull(samNode);
});
});
afterAll(() => {
vi.unstubAllGlobals();
});
Este código agrega una simulación y describe una “falsa”. versión de la recuperación de red
Response
y espera a que aparezca. Si el texto no aparece,
Para verificar esto, cambia la consulta en queryByText
por un nombre nuevo:
la prueba fallará.
En este ejemplo, se usaron los asistentes de simulación integrados de Vitest, pero
los frameworks tienen enfoques similares a la simulación. Vitest es único en el sentido de que debes
llama a vi.unstubAllGlobals()
después de todas las pruebas o establece un valor global equivalente
. Sin "deshacer" nuestro trabajo,
la simulación de fetch
puede afectar a otras pruebas y se responderán todas las solicitudes
con nuestra extraña pila de JSON.
Importaciones de prueba
Quizás hayas notado que el componente UserList
importa un componente
llamada UserRow
. Si bien no incluimos su código, puedes ver que
renderiza el nombre del usuario: la prueba anterior busca "Sam", y ese no es
se renderiza directamente dentro de UserList
, por lo que debe provenir de UserRow
.
Sin embargo, UserRow
podría ser un componente complejo. Es posible que obtenga
del usuario ni tener efectos secundarios que no son relevantes para nuestra prueba. Quitando eso
de la variabilidad hará que las pruebas sean más útiles, especialmente cuando los componentes
que quieren probar, se hacen más complejos
y se entrelazan más con sus dependencias.
Puedes usar Vitest para simular ciertas importaciones, incluso si tu prueba no los usa directamente, de modo que cualquier código que los usa se proporciona con versión simple o conocida:
vi.mock('./UserRow.tsx', () => {
return {
UserRow(arg) {
return <>{arg.u.name}</>;
},
}
});
test('render', async () => {
// ...
});
Al igual que simular el fetch
global, esta es una herramienta poderosa, pero puede convertirse
insostenible si el código
tiene muchas dependencias. Una vez más, la mejor solución para
que consiste en escribir código que se puede probar.
Hacer clic y proporcionar contexto
React y otras bibliotecas como Lit,
tienen un concepto llamado Context
. El código de muestra incluye un UserContext
que
Invoca el método si se elige un usuario. Esto suele verse como una alternativa a
"Desglose de prop", donde la devolución de llamada se pasa directamente a UserList
.
El agente de prueba que escribimos no proporcionó UserContext
. Agregando un clic
acción a la prueba de React sin ella; esto, en el peor de los casos, generará una falla en la prueba o,
si se proporciona una instancia predeterminada en otro lugar, causarás algún comportamiento
nuestro control (similar a un UserRow
desconocido mencionado anteriormente):
const c = render(<UserList />);
const chooseButton = await c.getByText(/Choose);
chooseButton.click();
En cambio, cuando renderizas el componente, puedes proporcionar tu propio Context
. Esta
En este ejemplo, se usa una instancia de vi.fn()
, una función de simulación de Vitest, que puede usarse.
después del hecho para verificar que se hizo una llamada y los argumentos que se hicieron
tus amigos. En nuestro caso, esto interactúa con el fetch
simulado en la versión anterior
ejemplo, y la prueba puede confirmar que el ID que se pasó era "sam":
const userChosenFn = vi.fn();
const ucForTest: ContextType<typeof UserContext> = { userChosen: userChosenFn as any };
const c = render(
<UserContext.Provider value={ucForTest}>
<UserList />
</UserContext.Provider>,
);
const chooseButton = await c.getByText(/Choose);
chooseButton.click();
assert.deepStrictEqual(userChosenFn.mock.calls, [['sam']]);
Se trata de un patrón simple pero poderoso que puede permitirte quitar dependencias del componente principal que intentas probar.
En resumen
Este fue un ejemplo rápido y simplificado que demuestra cómo crear un
de componentes de React para probar y proteger un componente de React difícil de probar,
centrarse en garantizar que el componente interactúe correctamente con su
dependencias (el global fetch
, un subcomponente importado y un Context
)
Verifica tus conocimientos
¿Qué enfoques se utilizaron para probar el componente de React?