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
.
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);
});
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");
});