React lifecycle methods are a pain to test. How do you know if your component mounted twice? How do you test for that? Why should you, since it's part of React's internal behaviour? Here's how we've started testing React hooks ... by not testing them at all!
Say I have my component written and it updates some messages from my API using a useEffect hook like this:
useEffect(() => {
if (data) {
const messagesToUpdate = getAllMessagesToUpdate(data);
messagesToUpdate &&
messagesToUpdate.forEach(edge => {
updateMessage({
variables: {
UpdateMessageInput: {
id: edge.node.id,
read: true,
},
},
});
});
}
}, [data, updateMessage]);
How do I test each permutation of this call? I would need to mock the render cycle so that I can ensure that each time useEffect is called, this message does as it's expected.
Here's an alternative. Abstract the useEffect call into its own hook, and abstract the functionality into a separate function.
// in my main component
useUpdateMessages(data, updateMessage);
// in my hook
export function useUpdateMessages(data, updateMessage) {
useEffect(() => {
updateMessages(data, updateMessage);
}, [data, updateMessage]);
}
// in my standalone function
export function updateMessages(data, updateMessage) {
if (data) {
const messagesToUpdate = getAllMessagesToUpdate(data);
messagesToUpdate &&
messagesToUpdate.forEach(edge => {
updateMessage({
variables: {
UpdateMessageInput: {
id: edge.node.id,
read: true,
},
},
});
});
}
}
Now I don't need to worry about React lifecycle methods. I can test my hook if I want to, but it hardly seems worth it here. If I would, it would be easier to do so using react-hooks-testing-library
Additionally, I only need to worry about testing my standalone function, and that can be done much more easily now it's separated away from React's internal mechanism.
I like this approach a lot. Separate your code from the framework you're using. Even though there are more moving parts, it can facilitate much easier testing and a lot cleaner code.
Thanks to my colleague Stuart Nichols for this idea!
Top comments (0)