Refs are null in Jest snapshot tests with react-test-renderer

Asked
Active3 hr before
Viewed126 times

8 Answers

testsreact
90%

Since test renderer is not coupled to React DOM, it doesn't know anything about what refs are supposed to look like. React 15.4.0 adds the ability to mock refs for test renderer but you should provide those mocks yourself. React 15.4.0 release notes include an example of doing so.,Connect and share knowledge within a single location that is structured and easy to search.,Find centralized, trusted content and collaborate around the technologies you use most., 4 Snapshot testing with test renderer is not meant for DOM-reliant parts. If you need to test DOM itself rather than React components, please consider using Enzyme's mount() in jsdom environment. – Dan Abramov Nov 28 '16 at 22:35

Since test renderer is not coupled to React DOM, it doesn't know anything about what refs are supposed to look like. React 15.4.0 adds the ability to mock refs for test renderer but you should provide those mocks yourself. React 15.4.0 release notes include an example of doing so.

import React from 'react';
import App from './App';
import renderer from 'react-test-renderer';

function createNodeMock(element) {
  if (element.type === 'p') {
    // This is your fake DOM node for <p>.
    // Feel free to add any stub methods, e.g. focus() or any
    // other methods necessary to prevent crashes in your components.
    return {};
  }
  // You can return any object from this method for any type of DOM component.
  // React will use it as a ref instead of a DOM node when snapshot testing.
  return null;
}

it('renders correctly', () => {
  const options = {createNodeMock};
  // Don't forget to pass the options object!
  const tree = renderer.create(<App />, options);
  expect(tree).toMatchSnapshot();
});
load more v
88%

What is the current behavior? It's not possible to test component that use ref with the react-test-renderer utilitiesTesting: the refs are always null.,A warning could be added if we use react-test-renderer it on a component that need refs.,Just stumbled upon this, my solution for this was to not use react-test-renderer, but render from @testing-library/react,I will try to have another look on that... if some is starting with it, most simple test that we want to resolve is below ( add it at end of suit ReactTestRenderer )

/* @flow */

import React from 'react';

export default class Foo extends React.Component {    
    /* the future refs */
    bar; 

    componentDidMount() {
        console.log(this.bar); // this.bar is null

        this.bar.doThings() // So this fail
    }

    render() {
        return (
            <div ref={(c) => { console.log('ref cb', c); this.bar = c; }}> {/* The callback is call but, `c` is null*/}
                <p>Hello World</p>
            </div>
        );
    }
}
load more v
72%

Currently I am manually initializing Quill editor on componentDidMount and jest tests fail for me. Looks like ref value that I am getting is null in jsdom. There is and issue here: https://github.com/facebook/react/issues/7371 but looks like refs should work. Any ideas what I should check?,Note that it only works with React 15.4.0 and higher.,Since test renderer is not coupled to React DOM, it doesn't know anything about what refs are supposed to look like. React 15.4.0 adds the ability to mock refs for test renderer but you should provide those mocks yourself. React 15.4.0 release notes include an example of doing so.,As a result, console.log outputs null. But I would expect P tag

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {

  componentDidMount() {
    console.log(this._p)
  }
  
  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h2>Welcome to React</h2>
        </div>
        <p className="App-intro" ref={(c) => { this._p = c }}>
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}
load more v
65%

You can use Jest’s snapshot testing feature to automatically save a copy of the JSON tree to a file and check in your tests that it hasn’t changed: Learn more about it.,Returns the root “test instance” object that is useful for making assertions about specific nodes in the tree. You can use it to find other “test instances” deeper below.,Create a TestRenderer instance with the passed React element. It doesn’t use the real DOM, but it still fully renders the component tree into memory so you can make assertions about it. Returns a TestRenderer instance.,Essentially, this package makes it easy to grab a snapshot of the platform view hierarchy (similar to a DOM tree) rendered by a React DOM or React Native component without using a browser or jsdom.

load more v
75%

This allows us to successfully generate a snapshot for testing, as well as assert that focusOnTarget has indeed been called (through Jest's toHaveBeenCalled() assertion API.,Recently, I ran into some problems while attempting to snapshot test my React code.,I’m not absolutely certain of the cause of the error, but I suspect that renderer doesn't play well with React refs, and thus this.focusTarget.current is undefined.,The error originated from one of my component methods, which calls the HTMLElement.focus() method to set focus on a particular input field. For reference, I've reproduced the code below (the project is generated using create-react-app).

The error originated from one of my component methods, which calls the HTMLElement.focus() method to set focus on a particular input field. For reference, I've reproduced the code below (the project is generated using create-react-app).

// App.jsimport React, { Component } from 'react';import InputComponent from './InputComponent';import logo from './logo.svg';import './App.css';class App extends Component {  render() {    return (      <InputComponent />    );  }}export default App;// InputComponent.jsimport React, { Component } from 'react';export default class Input extends Component {  constructor(props) {    super(props);this.focusTarget = React.createRef();    this.focusOnTarget = this.focusOnTarget.bind(this);  }focusOnTarget() {    this.focusTarget.current.focus();  }componentDidMount() {    this.focusOnTarget();  }render() {    return (      <input        ref={this.focusTarget}        type="text"      />    );  }}// App.test.jsimport React from 'react';import App from './App';import InputComponent from './InputComponent';import renderer from 'react-test-renderer';var focusOnTargetSpy = jest.fn();jest  .spyOn(InputComponent.prototype, 'focusOnTarget')  .mockImplementation(focusOnTargetSpy);it('should match snapshot', () => {  var tree = renderer    .create(<App />)    .toJSON();  expect(tree).toMatchSnapshot();  expect(focusOnTargetSpy).toHaveBeenCalled();});
40%

If you open up src/containers/__tests__/__snapshots__/App.test.js.snap you should find a snapshot version of the component that shows the component’s render output.,We will begin by writing tests for the App component. A good starting point is adding a snapshot test to ensure that the component renders the expected output, given the required props.,To use the snapshot technique, we need to install the enzyme-to-json package to convert our React components to a snapshot during testing:,We will use snapshot testing to track changes to components. Using this technique, we take snapshots of our components. When the component’s rendered output changes, we can easily detect the changes made. The snapshots are also readable, so it is an easier way of verifying that components render the expected output.

Before adding the tests, we need to find out what the app does. The best way to do this is to clone the app and run it locally. To clone the application and install its dependencies run:

git clone https: //github.com/reactjs/redux.git
   cd redux / examples / async
git checkout db5f8d1
npm install
npm start
load more v
22%

Snapshot tests are a very useful tool whenever you want to make sure your UI does not change unexpectedly.,Often there are fields in the object you want to snapshot which are generated (like IDs and Dates). If you try to snapshot these objects, they will force the snapshot to fail on every run:,From here you can choose to update that snapshot or skip to the next:,That's all there is to it! You can even update the snapshots with --updateSnapshot or using the u key in --watch mode.

The snapshot artifact should be committed alongside code changes, and reviewed as part of your code review process. Jest uses pretty-format to make snapshots human-readable during code review. On subsequent test runs, Jest will compare the rendered output with the previous snapshot. If they match, the test will pass. If they don't match, either the test runner found a bug in your code (in the <Link> component in this case) that should be fixed, or the implementation has changed and the snapshot needs to be updated.

<Link>
load more v
60%

StoryShots adds automatic Jest Snapshot Testing for Storybook.,To use StoryShots, you must use your existing Storybook stories as the input for Jest Snapshot Testing.,StoryShots addon for React is dependent on react-test-renderer, but doesn't install it, so you need to install it separately.,Then, init Storyshots for async component in the file: StoryShots.test.js

npm install @storybook / addon - storyshots

Other "tests-react" queries related to "Refs are null in Jest snapshot tests with react-test-renderer"