website/blog/2016-07-27-jest-14.md
One of Jest's philosophies is to provide an integrated “zero-configuration” experience. We want to make it as frictionless as possible to write good tests that are useful. We observed that when engineers are provided with ready-to-use tools, they end up writing more tests, which in turn results in stable and healthy code bases.
One of the big open questions was how to write React tests efficiently. There are plenty of tools such as ReactTestUtils and enzyme. Both of these tools are great and are actively being used. However engineers frequently told us that they spend more time writing a test than the component itself. As a result many people stopped writing tests altogether which eventually led to instabilities. Engineers told us all they wanted was to make sure their components don't change unexpectedly.
<!--truncate-->Together with the React team we created a new test renderer for React and added snapshot testing to Jest. Consider this example test for a simple Link component:
import renderer from 'react-test-renderer';
test('Link renders correctly', () => {
const tree = renderer
.create(<Link page="http://www.facebook.com">Facebook</Link>)
.toJSON();
expect(tree).toMatchSnapshot();
});
The first time this test is run, Jest creates a snapshot file that looks like this:
exports[`Link renders correctly 1`] = `
<a
className="normal"
href="http://www.facebook.com"
onMouseEnter={[Function bound _onMouseEnter]}
onMouseLeave={[Function bound _onMouseLeave]}>
Facebook
</a>
`;
The snapshot artifact should be committed alongside code changes. We use pretty-format to make snapshots human-readable during code review. On subsequent test runs Jest will simply compare the rendered output with the previous snapshot. If they match, the test will pass. If they don't match, either the implementation has changed and the snapshot needs to be updated with jest -u, or the test runner found a bug in your code that should be fixed.
If we change the address the Link component in our example is pointing to, Jest will print this output:
Now you know that you either need to accept the changes with jest -u, or fix the component if the changes were unintentional. To try out this functionality, please clone the snapshot example, modify the Link component and run Jest. We updated the React Tutorial with a new guide for snapshot testing.
This feature was built by Ben Alpert and Cristian Carlesso.
By building a test renderer that targets no specific platform we are finally able to support a full, unmocked version of React Native. We are excited to launch experimental React Native support for Jest through the jest-react-native package.
You can start using Jest with react-native by running yarn add --dev jest-react-native and by adding the preset to your Jest configuration:
"jest": {
"preset": "jest-react-native"
}
:::info
The preset currently only implements the minimal set of configuration necessary to get started with React Native testing. We are hoping for community contributions to improve this project. Please try it and file issues or send pull requests!
:::
For Facebook's native apps we use a system called “snapshot testing”: a snapshot test system that renders UI components, takes a screenshot and subsequently compares a recorded screenshot with changes made by an engineer. If the screenshots don't match, there are two possibilities: either the change is unexpected or the screenshot can be updated to the new version of the UI component.
While this was the solution we wanted for the web, we also found many problems with such end-to-end tests that snapshot integration tests solve:
Because we believe snapshot testing can be useful beyond Jest we split the feature into a jest-snapshot package. We are happy to work with the community to make it more generic so it can be integrated with other test runners and share concepts and infrastructure with each other.
Finally, here is a quote of a Facebook engineer describing how snapshot testing changed his unit testing experience:
“One of the most challenging aspects of my project was keeping the input and output files for each test case in sync. Each little change in functionality could cause all the output files to change. With snapshot testing I do not need the output files, the snapshots are generated for free by Jest! I can simply inspect how Jest updates the snapshots rather than making the changes manually.” – Kyle Davis working on fjs.
Recently Aaron Abramov has joined the Jest team full time to improve our unit and integration test infrastructure for Facebook's ads products. For the next few months the Jest team is planning major improvements in these areas:
As always, if you have questions or if you are excited to help out, please reach out to us!