2
votes

I am still learning ReactJS with Enzyme and Material-ui.

I have a component with Material-ui's TextField and I would like to unit test the following situation.

  1. When user enters a string '123' on TextField on screen, the TextField should set 'error' to 'true' and display message 'Wrong Name format.'

Component

import React, { useState } from "react";
import TextField from "@material-ui/core/TextField";
import Grid from "@material-ui/core/Grid";

export const NameTextField = props => {
  const { onStateChange } = props;
  const [state, setState] = useState({
    errors: [],
    onChange: false,
    pristine: false,
    touched: false,
    inProgress: false,
    value: {
      name: ""
    }
  });
  const handleOnBlur = async event => {
    const inputStringLC = String(event.target.value).toLowerCase();

    // First verify the email is in good format
    if (inputStringLC !== "123") {
      // If true, verify username is available
      const updatedState = {
        ...state,
        touched: true,
        pristine: true,
        value: {
          name: inputStringLC
        },
        inProgress: false,
        errors: []
      };
      setState(updatedState);
      onStateChange(updatedState);
    } else {
      const updatedState = {
        ...state,
        touched: true,
        pristine: false,
        value: {
          name: inputStringLC
        },
        errors: ["Wrong Name format."]
      };
      setState(updatedState);
      onStateChange(updatedState);
    }
  };

  return (
    <Grid container spacing={1}>
      <Grid item xs={12}>
        <TextField
          variant="outlined"
          required
          fullWidth
          id="name"
          label="Name"
          error={state.errors.length > 0}
          helperText={state.errors.length > 0 ? state.errors[0] : null}
          name="name"
          autoComplete="name"
          margin="dense"
          onBlur={handleOnBlur}
        />
      </Grid>
    </Grid>
  );
};

export default NameTextField;

Unit Test

import React from 'react';
import { configure, shallow, mount } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import NameTextField from './NameTextField';
import TextField from '@material-ui/core/TextField';
import { createShallow } from '@material-ui/core/test-utils';


configure({adapter: new Adapter()});

describe('<NameTextField />', ()=> {
  let shallow;

  beforeAll(() => {
    shallow = createShallow();
  });
  let wrapper;
  beforeEach(()=>{
    wrapper =  shallow(<NameTextField />);
  });

  it('should render one <TextField /> element.', ()=>{
    expect(wrapper.find(TextField)).toHaveLength(1);
  });


  it('should show error when entered', ()=>{
    wrapper.find('#name').simulate('change', {target: {value: '123'}});
    expect(wrapper.find("#name").props().error).toBe(
        true);
    expect(wrapper.find("#name").props().helperText).toBe(
        'Wrong Name format.');
  });


});

I get the following error. Error: expect(received).toBe(expected) // Object.is equality

Expected: true Received: false

Am I doing something wrong here?

1
check your shallow render output, see if you have all of the components you expect. or try to fully mount the field, if the test works after that then you know that you are testing something beyond the scope of the shallow render - Joe Lloyd
Personally, I always use mount rather than shallow. After your simulation, to be sure that it has re-rendered you can use .update() - Siege21x

1 Answers

4
votes

I solved this by this. Posting solution for those in same situation.

  1. I tried using mount but it gets very complicated as material-ui has a lot of nested style components init. So I used shallow instead.
import React from 'react';
import {configure} from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
import NameTextField from './NameTextField';
import TextField from '@material-ui/core/TextField';
import {createShallow} from '@material-ui/core/test-utils';
import {act} from 'react-dom/test-utils';

configure({adapter: new Adapter()});

describe('<NameTextField />', () => {
  let shallow;

  beforeAll(() => {
    shallow = createShallow();
  });
  let wrapper;
  beforeEach(() => {
    wrapper = shallow(<NameTextField onStateChange={handleStateChange}/>);
  });

  const handleStateChange = updatedState => {
  };

  it('should show no error when first entered', () => {
    expect(wrapper.find(TextField).at(0).props().error).toBe(
        false);
    expect(wrapper.find(TextField).at(0).props().helperText).toBe(
        null);
  });

  it('should show error when nothing entered', () => {
    act(() => {
      wrapper.find(TextField).at(0).simulate('blur', {target: {value: '123'}});
    });
    wrapper.update();
    expect(wrapper.find(TextField).at(0).props().error).toBe(
        true);
    expect(wrapper.find(TextField).at(0).props().helperText).toBe(
        "Wrong Name format.");
  });

  it('should show no error when correctly entered', () => {
    act(() => {
      wrapper.find(TextField).at(0).simulate('blur', {target: {value: 'James'}});
    });
    wrapper.update();
    expect(wrapper.find(TextField).at(0).props().error).toBe(
        false);
    expect(wrapper.find(TextField).at(0).props().helperText).toBe(
        null);
  });

});

Hope this helps. Thanks for all who had helped me in this.