web-dev-qa-db-fra.com

Essence d'erreur lancée par un React composant à l'aide de tests-bibliothèque et de plaisanterie

Suivant le modèle de fournisseur de Kent C Dodds expliqué dans cet ensemble Blog Post , j'ai un composant de fournisseur de contexte avec un crochet à utiliser ce contexte.

Les gardes-crochets contre l'utilisation de celui-ci à l'extérieur du fournisseur,

export function useUser() {
  const { user } = useContext(UserContext) || {};
  const { switchUser } = useContext(SwitchUserContext) || {};
  if (!user || !switchUser) {
    throw new Error('Cannot use `useUser` outside of `UserProvider`');
  }
  return { user, switchUser };
}

Pour tester le scénario, je crée un TestComponent et utilisez le crochet useUser à l'intérieur.

function TestComponent() {
  const { user, switchUser } = useUser();
  return (
    <>
      <p>User: {user.name}</p>
      <button onClick={switchUser}>Switch user</button>
    </>
  );
}

Je le teste comme ça,

  test('should throw error when not wrapped inside `UserProvider`', () => {
    const err = console.error;
    console.error = jest.fn();
    let actualErrorMsg;
    try {
      render(<TestComponent />);
    } catch(e) {
      actualErrorMsg = e.message;
    }
    const expectedErrorMsg = 'Cannot use `useUser` outside of `UserProvider`';
    expect(actualErrorMsg).toEqual(expectedErrorMsg);

    console.error = err;
  });

Je dois actuellement se moquer de console.error Et plus tard, réglez-le à sa valeur d'origine à la fin du test. Ça marche. Mais j'aimerais rendre cela plus déclaratif et plus simple. Y a-t-il un bon modèle pour y parvenir? Quelque chose en utilisant . Tothrow () Peut-être?

J'ai un codesandbox Pour cela, le code ci-dessus peut être trouvé dans UserContext.js et UserContext.test.js.

Remarque: les tests peuvent être exécutés dans la codesandbox elle-même sous l'onglet Tests.

7
Bhargav Shah

Tu pourrais faire quelque chose comme ça

test('should throw error when not wrapped inside `UserProvider`', () => {
  component.useUser = jest.fn().mockRejectedValue(new Error('Cannot use `useUser` outside of `UserProvider`'));
  let actualErrorMsg;
  try {
    render(<TestComponent />);
  } catch(e) {
    actualErrorMsg = e.message;
  }
  const expectedErrorMsg = 'Cannot use `useUser` outside of `UserProvider`';
  expect(actualErrorMsg).toEqual(expectedErrorMsg);
});
1
Yadab

Ce n'est peut-être pas aussi propre d'une solution, mais c'est simple et facile à comprendre. Cet exemple utilise dossier mais fonctionne bien sans. Il est également assez facile de définir quelque chose comme ça et de la réutiliser ailleurs.

it("errs if provider is missing", () => {
  const HookWrapper = ({
    testId,
  }: {
    testId?: string;
  }) => {
    try {
      const data = useCustomHook();

      return <pre data-testid={testId}>{JSON.stringify({ data }, null, 2)}</pre>;
    } catch (err) {
      const error = err as Error;
      const errorPayload = { message: error.message, stack: error.stack };
      return (
        <pre data-testid={testId}>
          {JSON.stringify({ error: errorPayload }, null, 2)}
        </pre>
      );
    }
  };
  
  render(<HookWrapper testId="HookWrapper" />);

  const providedData = JSON.parse(
    screen.getByTestId("HookWrapper").innerHTML
  );
  const error = providedData.error as Error;

  expect(error).toBeDefined();
  expect(error.message).toEqual("SomeProvider Context not initialized");
});
0
David R.