Type checking with prop-types in Jest
Hi, and welcome to Shark Bytes, the OMS tech blog. We’ll be posting the cool bits about technology and programming in this space every month.
This blog is about improving the React prop-types’ type checking in your Jest test suite. I’m not going to talk too much about the basics of prop-types in this blog, many other people have covered this already. I will also assume you are familiar with Jest, but that is not required.
The problem
We’ve all been there: We use prop-types to assert that the props we pass to our components are sane, but then no one notices that a recent change has made a prop-type check fail. This usually happens because prop-types are basically a form of runtime type checking, where the library will print warnings to the console whenever a mismatch is detected. Detecting this when building is hard because of the runtime behavior of the prop-types library.
“But why don’t you use Flow or TypeScript?” some say. This is a fair point, as static type checking helps detect this kind of bug. They would also give us good error messages when an error is detected and prevent buggy code from compiling. However, not everyone has the liberty to rewrite their entire app to be statically typed, and some people don’t want to introduce another complicating factor to an already complex code base. These are also fair points, so this blog will therefore focus on improving the prop-types experience in Jest.
The above is the output Jest prints when it encounters a prop-type mismatch. As you can see, the prop-type warning is printed to the test output, but the test still passes. This is because Jest does not know what to do with the console.error because it is not an Error, and therefore passes the test since it did not throw.
This leads to a sub-par experience where it is possible to miss bugs because the test suite will pass when run in the CI platform.
The solution
There is a simple way to fix this in Jest, where we turn prop-type failures result into test failures. Let’s write a short Jest setup file:
In the above file we are overriding the default implementation of console.error to check if the text includes a prop-type failure. If it does, we throw is as an Error, which will cause the corresponding Jest test to fail.
Download and save this file into a directory in your project. We like using a directory called scripts for this type of file.
Finally, don’t forget to tell Jest to load the script file by updating your package.json with the setupFiles config. If you forget this, the script will not run.
If you’re using create-react-app, you can use setupTestFrameworkScriptFile instead, as it is not possible to use setupFiles there.
When we try to run our test again, we can see that the test fails with a nice error message from prop-types. The message tells us exactly where it error occurred, in my case in the test file. This new behavior gives us a better sense of confidence that no incompatible prop-changes have been implemented, as they would be picked up by the test suite.
What I think is really powerful about this is that if you run your tests when you build your project, this essentially turns prop-types from runtime type checking to compile-time type checking!
Also, if you combine this with the eslint prop-types validation, you get a really powerful test suite for free, where eslint tells you when you are missing prop-type declarations, and Jest tells you when you mess up passing the correct props.
The library
The solution proposed above is pretty easy, but if you want an even simpler solution I created a tiny library that you can npm install instead.
Check out the library at https://github.com/esphen/jest-prop-type-error
Wrapping up
I want to give some recognition to Stian Didriksen for the idea to write this blog and the jest-prop-type-error library. Your talk on Jest testing was excellent!
Thanks for reading our first company blog. We have more to share, and me and my colleagues will be posting more in the coming months. I hope you enjoyed reading this short “quick-tip”, and have an excellent day!