Snapshot testing works by serializing the webpage and comparing it with latest value. But when it comes to dynamically generated values, it will fail. Like if you have a list which contains the primary key as shown below.

When you store the snapshot for first time, the keys will be 234, 456,789.

When you take the snapshot of it again, the keys is going to be different from the previous one.

How to solve for the above problem?

There are many solutions which can be employed to solve for the snapshot testing.

Mocking of non-derministic data

If we have a navbar which display the current date and time using Date.now() api. So the snapshot testing of the navbar will always result in failure because the time is changing. In this case, we can use mocking of Date.now() api so that the time is displayed same during testing.

Mocking of Date.now() api using jest

Date.now = jest.fn(() => 1482363367071);

Lets consider the sample react component with Date function

import React, { Component } from "react";

class SnapShotTests extends Component {
  render() {
    return (
      <div className="App">
        {Date.now()}
      </div>
    );
  }
}

export default SnapShotTests;

The snapshot test for the above component will be

import React from "react";
import renderer from "react-test-renderer";
import SnapShotTests from "../SnapShotTests";

it("renders correctly", () => {
  Date.now = jest.fn(()=>1234)
  const tree = renderer.create(<SnapShotTests />).toJSON();
  expect(tree).toMatchSnapshot();
});

Passing ids as props

If you are having elements with dynamic ids or uuids, then it is going to fail snapshot test every time as the generated id will be different. In that scenario, you can pass the ids as prop to the component. You can also set default prop for that id, so that you dont have to pass the prop.

We can modify the sample component above to accept the date as prop.

import React, { Component } from "react";
import PropTypes from 'prop-types';

class SnapShotTests extends Component {
  render() {
    const { date } = this.props.
    return (
      <div className="App">
        {date}
      </div>
    );
  }
}

SnapShotTests.proptypes = {
  date: PropTypes.string
}

export default SnapShotTests;
import React from "react";
import renderer from "react-test-renderer";
import SnapShotTests from "../SnapShotTests";

it("renders correctly", () => {
  const tree = renderer.create(<SnapShotTests data={1234}/>).toJSON();
  expect(tree).toMatchSnapshot();
});

Using Property Matchers

Property matchers are useful when you want to match the snapshot with the object.

We can not always be able to mock the functions. When you are taking the snapshot of charts or visualization, where we have random ids for the elements. It is difficult to mock the inner functions of the visualization library.

In order to use snapshot testing for the above, we need to pass the arguments to toMatchSnapshot function, and update the snapshot files. Jest will update/create the snapshot files accordingly.

Lets consider a simple react component as shown below

import React, { Component } from "react";

class SnapShotTests extends Component {
  render() {
    return (
      <div className="App">
        {Date.now()}
      </div>
    );
  }
}

export default SnapShotTests;

Write the snapshot test for the above component by passing the property matchers to the toMatchSnapshot file.

import React from "react";
import renderer from "react-test-renderer";
import SnapShotTests from "../SnapShotTests";

it("renders correctly", () => {
  const tree = renderer.create(<SnapShotTests />).toJSON();
  expect(tree).toMatchSnapshot({
  children: [ expect.any(String) ] });
});

The snapshot file will be generated as shown below.

// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`renders correctly 1`] = `
Object {
  "children": Array [
    Any<String>,
  ],
  "props": Object {
    "className": "App",
  },
  "type": "div",
}
`;

As you can see, the Date.now() is now replaced with Any<String>. So the snapshot test will always pass the test without the need to mock the Date.now() function.