Draft-js: Advice on snapshot testing with Jest

Created on 6 Oct 2016  路  17Comments  路  Source: facebook/draft-js

Do you want to request a _feature_ or report a _bug_?

I suppose this could be considered a feature request to make data-editor and data-offset-key attribute values deterministic via some seed.

What is the current behavior?

When testing a component which wraps an Editor using the snapshots feature in Jest, the test always fails because certain attributes appear to be randomly generated and unique per instance.

This is a sample of the output from the test failure:

-             data-editor="4or1r"
-             data-offset-key="9r3en-0-0">
+             data-editor="cbctb"
+             data-offset-key="3jgg4-0-0">
              <div
                className="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"                                                                                    
-               data-offset-key="9r3en-0-0">
+               data-offset-key="3jgg4-0-0">
                <span
-                 data-offset-key="9r3en-0-0"
+                 data-offset-key="3jgg4-0-0"

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem.

The test is very simple:

import React from 'react';
import renderer from 'react-test-renderer';
import { MyEditor } from '../src';

jest.mock('react-dom');

describe('MyEditor', () => {
  it('renders as expected', () => {
    const component = renderer.create(<MyEditor />);
    const tree = component.toJSON();
    expect(tree).toMatchSnapshot();
  });
});

Where MyEditor wraps Editor and provides a default value for editorState.

What is the expected behavior?

I would hope to somehow still be able to use snapshot testing.

Which versions of Draft.js, and which browser / OS are affected by this issue? Did this work in previous versions of Draft.js?

I'm using Draft 0.9.1 and Jest 15.1.1

Most helpful comment

I'm not sure if this is the same problem other people are having, but I had an issue where EditorState was being passed into my editor component and within it contained a random key that would be different on every jest run.

Mocking this function solved it for me:

jest.mock('draft-js/lib/generateRandomKey', () => () => '123');

All 17 comments

+1

@cpojer - would you mind chiming in here on whether consumers will need to ignore specific properties or if Draft itself should communicate that some properties should be ignored during snapshot testing

there isn't any way right now to ignore this. The right solution is usually to mock out whatever creates randomness, like Date.now = jest.fn(() => 42) for example. What provides these random IDs and can we mock them?

Perhaps I'm misunderstanding how react-test-renderer and/or snapshots work, but I thought the test renderer did a shallow render.

In that case, I don't know why I'm seeing internals of the Editor component. Ideally, I wouldn't care about the implementation details of Editor and only how _my_ component was being rendered, which I thought was the point of shallow rendering.

(This is a obviously a separate question to the original issue)

No, it's not shallow, it's a normal render.

However, you can mock out lower level components like jest.mock('path/to/Editor', () => 'Editor').

What was the final solution to this problem?

Was there any solution to this?

Edit: Using what @cpojer recommended, I was able to stub out the component that was rendering DraftJS to render just the component name.

@kawikadkekahuna can you show your test code please ?

I'm not sure if this is the same problem other people are having, but I had an issue where EditorState was being passed into my editor component and within it contained a random key that would be different on every jest run.

Mocking this function solved it for me:

jest.mock('draft-js/lib/generateRandomKey', () => () => '123');

There are two issues happening here for snapshots:

  • Not mocking the draftjs Editor (which has random keys in data attributes)
  • Using EditorState.createWithContent() in props, which has random key values in the object

Fortunately, both of these issues are solved with @neurosnap's solution of mocking generateRandomKey inside draftjs.

This is what @cpojer's meant by:

The right solution is usually to mock out whatever creates randomness

Just to make this crystal clear, both issues will affect the example component below (which is fixed with the solution above):

import { Editor, EditorState } from 'draft-js';


class MyEditor extends React.PureComponent {
  constructor(props) {
    super(props);

    const initialState = EditorState.createEmpty();  // object contains random keys

    this.state = {
      initialState,
    };
  }

  render() {
    return <Editor editorState={this.state.initialState} />;   // Editor contains random data attributes
  }
}

export default Editor;

Hey guys, because this issue is still open I'm just going to write my proposal here. So I am doing integration tests with jest. I want to test our sign up endpoint which will return a json result that looks something like this:

{
ok: true,
token: randomTokenHere,
user_id: randomUserId
}

My test is something like this:

test('sign up new user', () => {
  return rpap.post({
    url: '/users.signup',
    body: {
      email: '[email protected]',
      password: 'jestit',
      first_name: 'Jest',
      last_name: 'Jesting',
    },
  })
    .then((result) => {
      expect(result).toMatchSnapshot();
    });
});

It would be cool if I can do that:

      expect(result).ignore({
        token,
        user_id,
      }).toMatchSnapshot();

Or because this can lead to mistakes it's going to be better if we can validate that it is at least there but with don't care what the value is because it's random.

What I have to do now is delete the values from the result before testing it. That's fine but if jest can do this for me in a nice syntax and even validate it in a non strict manner it's going to be epic.

Essentially the snapshot files will have only the deterministic values inside.

What are your thoughts about this?

I like that! Seems like a great use case for a custom matcher

Is the problem solved?

I also had to do this (entity map was still filled with uuids):

jest.mock("draft-js/lib/uuid", () => {
    let idUUID = 0;
    return () => (++idUUID).toString();
});

In Jest 23 we added a snapshot property matcher for this use case:

it('will check the matchers and pass', () => {
  const user = {
    createdAt: new Date(),
    id: Math.floor(Math.random() * 20),
    name: 'LeBron James',
  };

  expect(user).toMatchSnapshot({
    createdAt: expect.any(Date),
    id: expect.any(Number),
  });
});

// Snapshot
exports[`will check the matchers and pass 1`] = `
Object {
  "createdAt": Any<Date>,
  "id": Any<Number>,
  "name": "LeBron James",
}
`;

This is better than replacing or ignoring the value because you can assert that it matches some structure (like a string).

I'm not sure if this has been extended to support snapshot testing of components, but there's no reason it could be.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

abeq picture abeq  路  3Comments

vierno picture vierno  路  3Comments

B-Reif picture B-Reif  路  3Comments

roundrobin picture roundrobin  路  3Comments

ufo22940268 picture ufo22940268  路  3Comments