Jest Snapshot Testing With Dates and Times
Snapshot testing is great for quickly creating unit tests for components by getting a ‘snapshot’ of what a component looks like when it’s rendered on the page given certain prop values. This removes the need to manually check the amount of specific elements being rendered on the component, or what individual pieces of text are based on the values of props.
Let’s say that the component that you want to test using Jest snapshots has props that contain dates and times that are based on the current date/time. This can make snapshot testing a bit annoying as you’d have to update your snapshot test(s) every minute, and no one wants to do that! Another problem that you may run into is that if you use a service like CircleCI to run your tests, the date/time will be based on the timezone of the CircleCI server.
By leveraging the wonderful moment-timezone library, we can easily get around these issues in order to benefit from the easy creation of unit tests and ease of maintainability that Jest snapshots gives us.
Let’s take a look at a component that uses dates and times:
import React, { Component } from 'react';
import moment from 'moment';
import './App.css';
import PropTypes from 'prop-types';
class App extends Component {
static propTypes = {
currentDay: PropTypes.string.isRequired,
};
static defaultProps = {
currentDay: moment().format("MMM Do YYYY h:mm:ss a")
};
render() {
const { currentDay } = this.props;
return (
<div className="App">
Hello world!
<p>The day and time is currently {currentDay}</p>
</div>
);
}
}
export default App;
Which renders the following on your browser:
After writing a small snapshot test and creating the initial snapshot, this is what you’ll see once you wait a few minutes, and run your snapshot tests again in your local environment:
And this is what happens on a continuous deployment/integration service (in this example we’re using Gitlab’s integrated CI services):
Based on the time in the above image, we know that the servers are using UTC, whereas we are using EST.
So how do we go about creating the conditions in our unit test so that we can run our snapshots locally and on a CI service?
First, let’s update our unit test to pass a hard coded date to our component that’s created using the moment library.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import renderer from 'react-test-renderer';
import moment from 'moment';
it('renders without crashing', () => {
let props = {
currentDay: moment("2017-09-15 09:30:00").format("MMM Do YYYY h:mm:ss a")
};
const tree = renderer.create(<App {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});
Let’s run our tests now that we’ve made that change….
Perfect! Now our snapshot test won’t be failing due to the clock continuing to tick.
But what about the CI service? Our change doesn’t fix the problem that we saw earlier with the difference in timezones.
Rather than using the standard ‘moment’ library like we did earlier, we can use the ‘moment-timezone’ library to enforce a particular timezone in our tests. Our test file should now look like the following:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import renderer from 'react-test-renderer';
import moment from 'moment-timezone';
it('renders without crashing', () => {
moment.tz.setDefault('EST');
let props = {
currentDay: moment("2017-09-15 09:30:00").format("MMM Do YYYY h:mm:ss a")
};
const tree = renderer.create(<App {...props} />).toJSON();
expect(tree).toMatchSnapshot();
});
After committing our changes and pushing them to our repository on Gitlab…
We now have a snapshot unit test that allows us to assert that our component renders the date and the time without needing to constantly update it or worry about the test’s behaviour when it’s running on servers that use a different timezone than we are.
Like what you've read?
Subscribe to receive the latest updates in your inbox.