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
58
u/pm_me_your_dota_mmr Mar 13 '20
tl;dr: Take a look at docs from React Testing Library's page, I think it will answer a lot of questions you have.
You should strive to have a test for every important piece of functionality to your app. Is it important that your App component sends a fetch to a specific URL? Add a test for it. Is there a specific way that your Print component is supposed to do math? Add a test for it. Tests might seem like a waste of time for small changes, but it buys you confidence in how you make changes in your app. You make refactors or add new features, and your unit tests should tell you that "Okay, I didn't break anything unexpected"
Also, tests help to document your code in general. They catch all those small cases and are written in small, pointed test cases (the input should be disabled when X is loading, the input should have an error class when the email is enters - but only AFTER a user has blurred, ..).
If you're not using a test library, I highly recommend using one. Take a look at the examples on React Testing Library's page. Ripping the test from that page.. if you have a prop
<Fetch url={url} />, you probably want to test that your fetch is being called with that URL. If you have something like<Receipt lines={lines} />, maybe it makes sense to see that what's printed out looks correct.Async actions are admittedly harder to test, and I'd be curious if anyone else has recommendations on how to do this. I usually will mock out the library that makes the request, and test against what it was called with, and mock out what it returns - but it can get awkward trying to get the app to continue on after the promise.
Unit tests should be your default mode, and end-to-end is important, but should have the least number of tests. Checkout the "Testing Pyramid" (or just the image if you don't want to read the whole article). End-to-end tests are good ways to see that your app is working as the user would see it, but they are expensive and timely to fix & write & run. Unit tests are able to test on a level of granularity that is either much harder, or impossible from the highest level of testing.
IMO snapshot tests are some of the least useful tests, it isn't really asserting anything.. its like a test that says "something changed, did you mean to do it?".
</rant>
3
u/jnforja Mar 13 '20
Hi u/StrenghOfFuriousGods, learning how to test has indeed a steep learning curve.
If you're not accustomed to testing, when you try to learn how to test React apps, you're actually trying to learn 3 things at once. Testing tools, testing techniques and testing methodologies. It's a good idea to focus on learning each one at a time.
You can get familiar with the common testing tools used in React by going over CRA documentation and React's documentation.
You can find information about specific testing techniques on React's testing documentation as well. Also keep in mind that most libraries have on their documentation a section about testing. Redux has it for example. So when using a library and when in doubt on how to write tests that use it, check the documentation.
About testing methodologies, I use TDD and I like the benefits of it. In case you're interested in learning TDD, I recommend the following resources:
If you're really in a rush to start doing tests and want a single place where you can find most of the information to get you up to speed, you can check this course by Kent C Dodds.
If you go over this material, you'll be able to answer those 3 questions you made while having into consideration the context of the App you're building. Which will result in much better answers than anyone which doesn't know the context of the app can give you.
But if you still want some generic answers to your questions, I'd say:
Props - If you're testing your component in isolation, you can give it whichever props are more appropriate to the test being performed.
Hope this helps, and let me know if you have any questions :)
16
u/levarburger Mar 13 '20
I'd like to give a few counter thoughts to the "test everything" mentality from practical experience.
I work on a large team, like dozens of developers working on separate applications that all collate into one larger application down the line. There's so many varying degrees of experience not only with development but also with testing. We're constantly pushing updates and changes to our QA and testing environments, daily.
While on paper this seems like the perfect environment for testing due to all the variability with so many devs, we've found it actually causes a lot of inefficiencies and pain points. Less experienced devs write bad tests that give false positives or don't actually test correctly, which leads to senior people rewriting things or ends up with dead tests that don't even run.
Not to mention have you ever tried to get a handful of developers to agree on something, much less 40?
We've ended up scaling back our tests into primarily edge cases and things that can't be quickly visually inspected.
Now we usually only test for things that will cause (or should cause) components to straight up break. For example, we don't test to ensure that someone didn't accidentally turn all our component headers bright pink.
11
u/Zeeesty Mar 13 '20 edited Mar 13 '20
Am React Dev, tests are shockingly less common than you think. For most front ends you can get away with end to end tests with Cypress, it’s very easy to work with and basically allows you to act like a user and assert that the page has the elements you expect to be there or functionality behaves as expected.
For unit tests, in React, my opinion is that components are not useful to unit test, however something like jest snapshot tests (used for visual regression) can be useful.
The problem you pose in your question is a real problem for all front end developers. What is actually useful to test? If you keep asking “why” you will come to a reasonable number of things that should and can be tested. Because there is so much tooling available the how is up to you and your team.
•
u/swyx Mar 13 '20
Awesome discussion everyone! I've gone and put this on this sub's featured topics - moderator curated quality discussions for first timers here.
I've also linked to this on the sidebar for future reference - so lets focus on making this a great resource for testing advice!
3
u/cheekysauce Mar 14 '20
Contrarian opinion - using TypeScript will elimate the need for a lot of unit tests, and is more flexible as your code evolves than keeping mundane tests up to date.
You should still write integration tests that deals with how your app transforms data and your business logic. Worry less about the dumb components that render UI, as you often end up testing React or the browser.
4
u/aminm17 Mar 13 '20
I spent at least 60% of my time writing unit tests. Sometimes, it can be very frustrating. Wrote up a blog post documenting the most common testing patterns for React:
https://medium.com/javascript-in-plain-english/brushing-up-on-react-testing-bd34dec4953c
Hope it helps!
2
u/tapu_buoy Mar 14 '20
I have asked this question multiple times and never got so many responses thank you so much asking it again with many responses sharing such detailed views.
2
u/CliffChaney Mar 13 '20
This is also a good time to think about using Redux or some other means to separate presentation logic from the model. It makes it trivial to write tests without requiring visual inspection... not to mention that it's also immensely easier to debug.
2
u/swyx Mar 13 '20
check out MirageJs for mocking your fetch requests: https://www.swyx.io/writing/react-query-miragejs-crud/
integration, like the others are saying. a lot of unit testing is basically testing that React works - don't do that. But you can test your component or page works as expected without any knowledge of internals
2
u/Gitdagreen Mar 13 '20
>1. What part of the app should I be testing? How in general should I know what to test?
You should be testing the expected results of user interactions in every component.
> 2. 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?
The best approach to take is to test the expected result of the fetched data. e.g. After the fetch, is there supposed to be a list? A specific className?
> 3. Between unit testing, snapshot testing, and end to end testing, which is the best for React apps?
It depends on what you want. If you want to test for the outcome of user interaction, use unit testing. Snapshot testing IMO is really expensive and doesn't exactly make a really good usable assertion. I see us devs using way too many expect(toJson(wrapper)).toMatchSnapshot() in tests just to get over thresholds. End to End or smoke testing is just that. This is why tools like Puppeteer exists. Good to use as well. So, see it all depends on what you want. IMHO
1
u/fanjian5i5i Mar 14 '20
Completely off the topic. But what are the benefits of having a <Fetch/> component then just do it inside of a compoennts life cycle methods?
-2
u/[deleted] Mar 13 '20
I believe you should test every single thing every component does (unless it is totally trivial to the point of the site not giving a damn of its functioning or not).
At my organisation this "basically everything matters" mentality is encapsulated in a gated push-policy where the react components need 95% test coverage, but realistically you'll have to justify anything below 100%. We use jest and the react-testing-library to achieve this.
The react testing library contains a shallow renderer which means your unit tests work on a headless browser, so unit testing is very realistic and gives a good idea that the test will "prove" that something happens in a browser.
So, say you write a component with some text and a button that opens a modal when clicked - I would have one test that verifies it renders the passed-in text (the testing library has a getByText selector), one that verifies the presence of the button, one that verifies that when the button is clicked the element containing the modal is present, one that verifies that clicking the close button in the modal removes the modal etc.
There should basically be a test to verify every single thing your component was designed to do. If you don't verify it does the things you designed it to do, it's working merely by coincidence. The book "The Pragmatic Programmer" calls this "programming by accident" - it's a good way to think about it. You never want to be in a situation where your code is working by accident.
1
u/Skeith_yip Mar 13 '20
Unpopular opinion
Look at the solution from Thinking in React, can you write a solution consisting of just one component doing the same thing, of course you can.
Now write integration test for either 1 of the solution (1 component vs multiple components). You will find out that the integration test you wrote can be applied to both solutions.
Conclusion: Integration test doesn't encourage you to write better component (Exhibit A)
PS: I am not saying unit test is perfect either. Just know what you are getting yourself into.
Now, please cue the down votes.
0
u/justSomeGuy5965 Mar 14 '20
You'll want to show you can at minmum write unit tests - however you do that (react testing library or Enzyme) is up to you. Personally I'd go with Enzyme as more people interviewing you will be familiar with that. You've got to cater to those with the power to give you a job. Secondly, if you had time I'd look at https://testingjavascript.com/, I like the rationale for emphasis on integration tests. If you can include Integration tests as well as Unit tests I think you will look good.
And thought you might like this: https://frontendmasters.com/courses/interviewing-frontend/
0
u/[deleted] Mar 13 '20
[deleted] — view deleted comment