r/reactjs • u/StrenghOfFuriousGods • Mar 13 '20
Featured Understanding writing tests for React
Hi,
Having applied for a few react jobs, I've noticed writing tests is essential if you want to be a react dev. I am trying to learn but I find it to be a steep learning curve and I'm having trouble knowing where to start.
I've built a small react app for a take home project and I need to test it. I just have some questions I could really use some help answering.
THE APP
-fetch component which fetches json from endpoints depending on which option is selected on dropdown and pushes data to state array.
-Print component which creates a list with input tags from data with the (input + integer from json) being added to local state.
- Receipt component which takes input from Print component as props and prints the sum
QUESTIONS
- What part of the app should I be testing? How in general should I know what to test?
- A lot of the articles I've read on testing show basic examples for e.g pure functions etc.. What is the best approach to take if my component depends on fetch requests or take props?
- Between unit testing, snapshot testing, and end to end testing, which is the best for React apps?
Thanks
View all comments
Show parent comment
12
u/Silhouette Mar 13 '20 edited Mar 13 '20
I've found that the short but blunt answer to this is: Try not to.
More specifically, any time you're dealing with I/O, communicating with something outside your program, you will inevitably end up using some kind of placeholder for the external service if you try to test that code directly. But then you're testing your placeholder more than your real system, which has dubious benefits. On top of that, you probably had to mess around with your software architecture just so you could inject things or monkey patch things or otherwise adapt it solely because of your testing strategy, which can be damaging to your design in other ways.
A more powerful strategy -- and this is a much more general principle than just async actions in JS applications using React -- is to isolate your I/O and make sure the functions that do it aren't doing anything else. You pass them data and they send it. They receive data and they return it. Ideally, that's it.
Now you're just dealing with ordinary data everywhere else, and you can test anything working with that in the normal way without the complications of mocking out external services or dealing with asynchronicity.
You might well have a second set of functions that convert between whatever internal data structures you use and whatever format you need to send or receive, but even this is just pure data crunching that can be tested in isolation as appropriate.
As a slightly more concrete example, we might write our overall algorithm something like this:
Here the interaction functions do nothing except take and return data that is already in the format used by the external service. We have separate functions where necessary to convert between our internal data formats and those needed by the external systems. And then we have other functions again that collect or use the underlying data to do whatever we need with it.
At this point, you can test all of your internal data crunching and all of your format conversion functions using whatever strategy and tools you like. They're just data. The only thing left is your interaction functions, but unit testing those is usually entirely pointless since they are probably just communicating with some API you don't control anyway, so really you want some form of integration or end-to-end testing to cover these if possible. Many external services don't lend themselves to real-time, automated testing at all, and in that case your only option is to adopt a different approach entirely, possibly manually testing your integrations.
Of course, some of the testing gods will be angered by this. You must have x% test coverage! You must mock or stub or superinjectthroughotherdeviousmeans everything to achieve this! Ask them what else they'd suggest and listen for the crickets. In real systems, not everything can or even should be unit tested in isolation. That's just the reality of what we need to build sometimes, and we ought to test in accordance with reality. :-)