Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Snapshot test for component with uuid #2172

Closed
reintroducing opened this issue Nov 27, 2016 · 15 comments
Closed

Snapshot test for component with uuid #2172

reintroducing opened this issue Nov 27, 2016 · 15 comments

Comments

@reintroducing
Copy link

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 :)

@reintroducing
Copy link
Author

Disregard, just mocked it as such:

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

Wrote this up too quickly :)

@loganshoemaker
Copy link

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!

@Bappy1988
Copy link

Bappy1988 commented May 29, 2018

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?

@mattphillips
Copy link
Contributor

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 😄 if not feel free to ask for help over in our discord channel in Reactiflux

@Bappy1988
Copy link

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

@SimenB
Copy link
Member

SimenB commented May 29, 2018

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

@Bappy1988
Copy link

@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

@icd2k3
Copy link

icd2k3 commented May 30, 2018

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?

@rjz
Copy link

rjz commented May 30, 2018

@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');

@icd2k3
Copy link

icd2k3 commented May 30, 2018

thanks @rjz

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

@renatoi
Copy link

renatoi commented Sep 17, 2018

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++;
});

@azizur
Copy link

azizur commented Apr 11, 2020

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';

@robross0606
Copy link

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.

@connorads
Copy link

For anyone thats wants to use mockImplementationOnce or other jest.fn() features you can do so like this.

jest.mock("uuid", () => ({
  v4: jest.fn(),
}));

beforeEach(() => {
  const mockUuid = require("uuid") as { v4: jest.Mock<string, []> }; // "as" is TypeScript you can ignore
  mockUuid.v4
    .mockImplementationOnce(() => "uuid-1")
    .mockImplementationOnce(() => "uuid-2");
});

afterEach(() => {
  jest.resetAllMocks();
});

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Please note this issue tracker is not a help forum. We recommend using StackOverflow or our discord channel for questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 11, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests