web-dev-qa-db-fra.com

Comment se moquer d'un crochet personnalisé à l'intérieur d'un composant React que vous souhaitez tester?

Si vous avez un composant React qui appelle un hook personnalisé qui récupère les données, quelle est la meilleure façon de se moquer du résultat du hook personnalisé interne lors du test du composant React ? Je vois 2 approches principales:

1) Jest.mock le crochet personnalisé. Cela semble être l'approche la plus recommandée, mais il semble que cela nécessite que le test ait plus de connaissances sur les détails de l'implémentation interne et ce dont il pourrait avoir besoin de se moquer que ce que l'interface des accessoires du composant pourrait suggérer (en supposant l'utilisation de prop-types ou Manuscrit)

2) Utilisez une approche d'injection de dépendance. Déclarez le crochet en tant qu'accessoire, mais définissez-le par défaut sur le vrai crochet afin de ne pas avoir à le définir partout où vous rendez le composant, mais autorisez le remplacement avec une maquette pour les tests. Voici un exemple de code et de boîte artificiel avec un test qui se moque d'un crochet personnalisé:

https://codesandbox.io/s/dependency-inject-custom-hook-for-testing-mjqlf?fontsize=14&module=%2Fsrc%2FApp.js

2 nécessite plus de frappe, mais semble plus facile à utiliser pour les tests. Cependant, les tests doivent déjà connaître les détails d'implémentation interne du composant pour tester toute logique conditionnelle pour la sortie rendue, donc ce n'est peut-être pas important et 1 est la meilleure approche. Est-ce que 1 est le chemin à parcourir? Quels compromis voyez-vous? Suis-je complètement absent d'une autre approche?

9
sschottler

Cette question remonte à quelques mois, mais si vous n'avez pas trouvé de bonne solution, j'ai écrit un package qui pourrait vous aider. J'ai suivi un processus de réflexion similaire, y compris "et si j'injecte les crochets dans le composant?" Les choses sont devenues étranges.

Je voulais essentiellement un connecteur pour éviter un wrapper supplémentaire pour les composants de présentation juste pour les tester.

Je suis venu avec react-hooks-compose, qui vous permet de séparer vos crochets et vos présentateurs et de les tester individuellement ou ensemble: https://www.npmjs.com/package/react-hooks-compose

export const useFetch = () => {
  const [user, setUser] = useState();

  useEffect(() => {
    fetchData('some-url') // <-- Fetches data on mount
      .then(res => setUser(res.data));
  }, []);

  return {user};
}

// composeHooks passes the values from your hooks as props
export const UserPresenter = ({user}) => {
  return <div>You fetched data for: {user.name}</div>;
}

export default composeHooks({ useFetch })(DataPresenter);

Maintenant, vous n'avez pas à vous moquer du crochet, vous pouvez simplement tester le présentateur avec un accessoire:

it('presents user', () => {
  const { queryByText } = render(<UserPresenter user={{name: 'Mary'}} />); // <-- Named export
  expect(queryByText('Mary')).toBeTruthy();
});

Ou, vous avez la possibilité d'un test d'intégration de niveau supérieur:

it('fetches data', () => {
  fetchData.mockResolvedValue('Mary');
  const { queryByText } = render(<UserWithData />); // <-- Default export
  expect(queryByText('Mary')).toBeFalsy();
  return wait(() => {
    expect(queryByText('Mary')).toBeTruthy();
  });
});

Vous pouvez même tester le crochet à l'unité si vous le souhaitez.

1
helloitsjoe

Pourquoi ne vous moquez-vous pas de la méthode sous-jacente qui effectue l'appel api à la place?

Par exemple, si vous récupérez des données avec fetch(), vous vous moquez de cela à la place. De cette façon, vous pouvez définir une réponse personnalisée pour cet appel, ce qui facilitera le test du hook lui-même.

1
Clarity

Avec le crochet moqueur lui-même, vous ne savez jamais si un vrai fonctionne parfaitement avec votre composant.

Avec le passage du crochet comme accessoire, il serait très difficile de faire communiquer les crochets les uns avec les autres. Par exemple. lorsque vous avez besoin de votre hook personnalisé pour appeler setter à partir du même composant useState. Vous auriez besoin d'étendre le hook personnalisé avec de plus en plus de paramètres.

  1. Vous pouvez vous moquer d'un appel d'API externe - je veux dire se moquer de fetch ou XHR. Il a encore besoin de connaître certains détails d'implémentation - le fait que vous exécutez une requête HTTP - mais il y a moins de choses que votre test devrait savoir.
0
skyboyer