David He
David He

Reputation: 394

The correct way to unit test react component

I am using jest and enzyme to test my react component which relies on antd - a 3rd react UI library. For illustrative purpose, I produce the minimal code that is fair enough to show my question.

See my test component as follow:

import React from 'react';
import { Button } from 'antd';

function Test({onSubmit}) {
  return (
          <div>
           <Button htmlType="submit" type="primary" />
          </div>
         );
}

export default Test;

Q1: I mock up the Button as below since unit test requires us to isolate the target and mock up any other dependencies. Is that correct?

__mocks__
  antd.js

antd.js

import mockComponent from '../mockComponent';

const list = [
  'Form',
  'Input',
  'Button',
  'Spin',
  'Icon'
];

const mockups = list.reduce((prev, next) => {
  prev[next] = mockComponent(next);
  return prev;
}, {});

mockups.Form.Item = mockComponent('Form.Item');

export const Form = mockups.Form;
export const Input = mockups.Input;
export const Button = mockups.Button;
export const Spin = mockups.Spin;
export const Icon = mockups.Icon;

mockComponent.js

import React from 'react';

export default function mockComponent (name) {
  return props => React.createElement(name, props, props.children);
}

Q2. I have got the following warning even if the test passes. How can I resolve that?

test.spec.js

import React from 'react';

import { shallow, mount } from 'enzyme';
import renderer from 'react-test-renderer';

import Test from '../components/question';

describe('mount test', () => {
  let wrapper;

  let props;
  let mountedLogin;

  const test = () => {
    if (!mountedLogin) {
      mountedLogin = mount(<Test {...props} />);
    }

    return mountedLogin;
  };

  beforeEach(() => {
    mountedLogin = null;
  });

  it('always render test as the root', () => {
    const divs = test().find('div');
    expect(divs.length).toBeGreaterThan(0);
  });
});

warning

 console.error node_modules/fbjs/lib/warning.js:36
 Warning: Unknown prop `htmlType` on <Button> tag. Remove this prop from the 
 element. For details, see
    in Button (created by Unknown)
    in Unknown (created by Test)
    in div (created by Test)
    in Test (created by WrapperComponent)
    in WrapperComponent

A side note, I haven't got any jest configs in my package.json.

Can anybody help me out with these.

Many thanks

Upvotes: 2

Views: 1628

Answers (1)

Tharaka Wijebandara
Tharaka Wijebandara

Reputation: 8065

Q1: I mock up the Button as below since unit test requires us to isolate the target and mock up any other dependencies. Is that correct?

Currently, the recommended approach for React unit testing is shallow rendering. It basically renders the given component one level deep. If we shallow render your Test component, it will call render method of Test component, but not the render method of Button component. Even though Button is 3rd party component and dependency, we don't need to mock it. Because we don't render it. But still, we will be able to see whether it's in the component tree and it has got the correct props. This is what essentially we will assert with the mocking approach also. However, shallow rendering has few limitations also, but usually, it works very well for most of the scenarios.

But you can obviously mock children and render the whole component also. But it's time-consuming and problematic, at least with my experience.

Q2: I have got the following warning even if the test passes. How can I resolve that?

Since you pass a string as name for React.createElement, React think you want to create a normal HTML element, and not a React component. But since there is a no HTML element call Button (case sensitive) and it doesn't know prop called htmlType, you get this unknown prop type warning. To prevent this warning, either you can stop passing props to React.createElement or pass a mock component to React.createElement instead of the name string.

import React from 'react';

function Mock(){
  retun (<div/>);
}

export default function mockComponent (name) {
  return props => {
    return React.createElement(Mock, {...props, name}, props.children);
  }
}

If you need to read more about react unit testing, I suggest you to go through this thread from react discuss forum.

Hope this helps!

Upvotes: 4

Related Questions