Introduction
Testing is a fundamental part of development. Testing a react application is no different. Once an application grows to a certain size it becomes one of the only ways you can have confidence that a change you make will not affect previous functionalities. The keyword here is confidence.
A test is only good if it can make sure that an interaction a user expects, remains the same
Me or something
A test’s main focus should be centered around what the end-user expects. This means any and all implementation details should remain irrelevant. A user does not care about the names of variables or functions, only that when they click a button it does the expected behavior.
Photo by David Travis on Unsplash
With that being said, this is the first article in a series where I’ll go over how to perform modern testing on a React application. I’ll first go over our terminology and tools, following articles will go over how to create E2E tests and unit tests taking into account the selected tools.
Terminology
Although everyone has a different definition of what different types of tests are and what they cover, I figured I would give my own personal definition for future reference:
What is a unit test?
A unit test is a testing method for an isolated and individual piece of code, a unit. In the context of React, this more than likely refers to testing our components in isolation and any associated functions.
What is an end-to-end (E2E) test?
Testing the functionality of an application under the most production-like circumstances. In our case, this means compiling, building, and running the app inside a browser-like environment and going through different user flows.
Testing a React app: The Tools
I put a heavy emphasis on end-to-end testing. This will most resemble how the user is interacting with the application and will, again, instill the most amount of confidence. My framework of choice here is Cypress.
Unit tests will be taken care of with Vitest(yes, not Jest).
And finally, since our concern isn’t with the backend or API but with the front-end and the respective user interactions then a mocking library will be vital. MSW has us covered here.
End-to-end Testing a React App: Cypress
Here is a video directly from their landing page giving a brief introduction:
Cypress is a tool I can’t speak more highly of. As weird as it sounds it makes testing fun. The visual test runner makes it so easy to develop the tests as it can select elements and help you create selectors as you go. It comes with amazing Typescript support out of the box. The website documentation is on point. I’ll stop gushing about it now. 😢
Unit Testing a React app: Vitest 🌽
The yin to our Cypress yang. Vitest will cover everything that isn’t feasible to do for end-to-end testing. Although integration testing is vital it does have the downside that it can be considerably slower than unit testing.
Although it’s become a bit of a meme to say something is blazing fast 🚀. In this case, it completely holds true.
Much like Cypress, this comes with out-of-the-box Typescript support, Chai built-in assertions, instant watch mode, and DOM mocking!
Not to mention it can be overkill if we want to test specific edge cases for functions or transformations that we have inside our codebase.
We will be using this to test our React components, hooks, and utility functions in isolation. This is to make sure we cover our edge cases in the process.
Mocking our tests: MSW 🎭
Although not directly related to our tests this is still a vital component. MSW will make our tests consistent and avoid coupling our tests to backend cleanup and APIs. These can be more important down the line with end-to-end testing or separate backend-only testing.
I prefer MSW in most cases because we can mock our edges cases in a more declarative manner.
Conclusion
Hope you enjoyed this brief introduction. If you’re interested to learn more about testing consider following me or bookmarking this article! This is just the first part of the series.
In future articles, I’ll go over everything from setup to building tests to implementing this process in your pipeline to getting accurate code coverage reports.
More content at Relatable Code
If you liked this feel free to connect with me on LinkedIn or Twitter
Check out my free developer roadmap and weekly tech industry news in my newsletter.
Top comments (4)
I think with vitest and testing lib you can achieve most (all?) of the testing you do with Cypress, but faster. Which scenario can you test only with Cypress ?
Vitest is best used for headless testing. Cypress has the benefit of having browser-based test runner using real browser APIs. There will be a lot of potential issues or bugs that Cypress can cover that vitest will not be able to.
For a full description on what the developers behind vitest consider that they don't cover in comparison to cypress check out this post from them:
vitest.dev/guide/comparisons.html#...
Not sure navigator object or Scroll position are really important in such tests but I'm interested to know if someone has needs that cannot be covered by testing lib
Outside of browser APIs, I would say it mostly depends on your overall goals. As said in the post Cypress offers more visual oriented test development at the cost of speed based on the real browser engine so its closest it can be possibly be to the user-environment. This is the biggest benefit. For me the confidence in knowing its the closest to the user-environment.
Vitest is crazy fast and headless and covers its own use cases. In the end it really depends on what use cases you need for your team/app.
I prefer to use both. Smoke testing and covering big features with cypress to take advantage of the browser-based running. I can split the tests to test in firefox, chrome and safari. while with vitest I can get more granular.