Jest: Snapshot test for component with uuid

Created on 28 Nov 2016  路  13Comments  路  Source: facebook/jest

I have an interesting test issue. I've got custom components that use the uuid node package to generate unique IDs which I can map to labels for accessibility purposes. Here is a sample Checkbox component, for instance:

import React, {PropTypes} from 'react';
import classNames from 'classnames';
import {v4} from 'uuid';
import Label from './Label';
import Icon from './Icon';

const Checkbox = ({
    label,
    className,
    name,
    defaultChecked,
    disabled,
    toggle,
    onChange
}) => {
    const classes = classNames(
        'Checkbox',
        {'Checkbox-toggle': toggle},
        'FormElement',
        'FormElement-optional',
        className
    );
    const id = `Checkbox-${v4()}`;

    return (
        <div className={classes}>
            <input
                className="FormElement-item"
                id={id}
                type="checkbox"
                name={name}
                onChange={onChange}
                defaultChecked={defaultChecked}
                title={label}
                aria-label={label}
                disabled={disabled}
            />
            <Icon id="check" />
            <Label htmlFor={id}>{!toggle && label}</Label>
        </div>
    );
};

Checkbox.propTypes = {
    className: PropTypes.string,
    name: PropTypes.string,
    label: PropTypes.string.isRequired,
    defaultChecked: PropTypes.bool,
    onChange: PropTypes.func,
    disabled: PropTypes.bool,
    toggle: PropTypes.bool
};

Checkbox.defaultProps = {
    defaultChecked: false
};

export default Checkbox;

This works fantastic in my app and keeps accessibility happy. Now, I'm adding Jest snapshot testing to my setup and testing this component. The issue obviously happens when v4() runs because it creates a unique ID every single test run so the snapshots never match up.

What is the suggested way to deal with this? I can't imagine I'm the only one in the world doing something like this but you never know :)

Most helpful comment

Disregard, just mocked it as such:

jest.mock('uuid', () => {
    return {
        v4: jest.fn(() => 1)
    };
});

Wrote this up too quickly :)

All 13 comments

Disregard, just mocked it as such:

jest.mock('uuid', () => {
    return {
        v4: jest.fn(() => 1)
    };
});

Wrote this up too quickly :)

This was really helpful to me. Just gonna add some context in case other people find this.

I used the jest.mock() function posted above in my test files and made sure to import uuid/v4 as 'import { v4 } from 'uuid'' in the corresponding component files.

Thanks for this post and for posting your solution - was really helpful!

I am having a really weird problem.

I have the exact same scenario, only mocks that were working fine, no longer work. I can't see why.

my components import thusly;
import uuid from 'uuid';

my mock looks like this;

jest.mock('uuid', () => {
    let value = 1;
    return () => (value++)
});

this used to generate snapshots with 1,2,3,4 etc through the components. Now, the mock is being completely ignored and I'm getting UUIDs there. I haven't changed any of my tests so I can only assume it's something environmental? Any ideas?

Hey @Bappy1988 I'm not sure why your mock has stopped working.

An alternative way to test this is with the new Snapshot Property Matcher released in Jest@23. See here

You should be able to write your test like this instead:

it('renders component with any uuid number', () => {
  // create component 
  expect(component).toMatchSnapshot({
    propSetToUuid: expect.any(Number),
  });
});

// Snapshot
exports[`renders component with any uuid number 1`] = `
Object {
  "propSetToUuid": Any<Number>,
  "other": "props",
}
`;

Where propSetToUuid is the prop that uses the generated ID.

I hope this helps :smile: if not feel free to ask for help over in our discord channel in Reactiflux

Hi @mattphillips

Thanks for the quick response!

I've got to the bottom of the mock failing - it appears to be an issue with 22.4.4 - downgrading to 22.4.3 and ensuring all its dependencies/related packages are also on 22.4.3 has fixed the mocking.

Should I raise a separate bug for that?

I'll switch over to Snapshot Property Matcher in future tests.

Thanks :)

Ben

that's definitely a bug, 22.4.4 should only contain 1ea05fbe4147b8e3f22cedd36ad2e37f088cf7ea and bed949b4c31f01fc0ebdb8c95934a3fa7fbf53ca on top of 22.4.3

@SimenB

Thanks, I'll put together a separate bug report. I suspect the issue may be more to do with how yarn is installing related packages but I'll include everything I have found out thus far.

Thanks

The solutions suggested here don't seem to work with the recommended way to import uuid.

import uuidv4 from 'uuid/v4';

I've tried several different ways to mock uuid/v4, but none seem to work. Any ideas?

@icd2k3, it sounds like subfolders aren't supported (not likely to be anytime soon, per #226). But! This should still be doable via jest.mock in the offending test(s):

jest.mock('uuid/v4', () => () => '00000000-0000-0000-0000-000000000000');

thanks @rjz

also note setting this in jest.setup.js will mock it for the entire test suite.

Just for completeness sake, if you need different UUIDs but with deterministic values for testing, this is how you would do it:

jest.mock("uuid/v4", () => {
  let value = 0;
  return () => value++;
});

I have found this works really nice.

At the top of test file:

// your regular imports here

jest.mock('uuid', () => ({ v4: () => '00000000-0000-0000-0000-000000000000' }));

// describe('test suite here', () => {

in the actual code:

import { v4 as uuidv4 } from 'uuid';

Just for completeness sake, if you need different UUIDs but with deterministic values for testing, this is how you would do it:

jest.mock("uuid/v4", () => {
  let value = 0;
  return () => value++;
});

This does not appear to work across multiple tests. The counter resets.

Was this page helpful?
0 / 5 - 0 ratings