0

I am new to unit testing and I ran into the this case. I am using JEST and Enzyme - REACT JS

I am familiar calling clicks and onChange events but not sure how to set up a test for the following:

updateUser = (e) => {
  var tempUser = this.state.user;

  switch(e.target.id){
     case "firstName":
           tempUser.FirstName = e.target.value;
           break;
     case "lastName":
           tempUser.LastName = e.target.value;
           break;
     case "email":
           tempUser.Email = e.target.value;
           break;
      case "userName":
           tempUser.Username = e.target.value;
           break;
      default:
           break;
    }

this.setState({
    user: tempUser,
   })
}

So I tried to apply the same set up I have been using to test updateUser - not sure if its the correct approach.

describe(' Test', () => {
let wrapper;

 beforeEach(() => wrapper = shallow(<Component {...baseProps} />));

it('UpdateUser method', () => {
 wrapper.instance().updateUser = jest.fn();
 wrapper.setState({
   user:{
         tempUser :{
            FirstName: "",
            LastName:"",
            Email:"",
            Username:"",
          },
      },
  }),
wrapper.update();
expect(wrapper.instance().updateUser).toBeDefined();
expect(wrapper.state().user).toEqual({}); 
})

Thanks for the help - hope to learn how to test switch cases and get this test to pass.

skyboyer
  • 22,209
  • 7
  • 57
  • 64
user 9191
  • 717
  • 4
  • 11
  • 31
  • @skyboyer any advice ? work something out based on my answer – user 9191 Feb 28 '19 at 14:43
  • in general my advice: calling `updateUser` through `props` and validate `render()` changed component accordingly. mutating state makes your component unstable while accessing state directly in tests makes tests harder to maintain. I'd not do that. to show some code I need at least understand how `updateUser` is bound to element and how your component is rendered. – skyboyer Feb 28 '19 at 15:50
  • Should i add the code and the test code inside of a codesandbox – user 9191 Feb 28 '19 at 16:02

2 Answers2

1

There is example how to simulate click on button with shallow rendering https://airbnb.io/enzyme/docs/api/shallow.html#shallow-rendering-api.

Also if you are using old state use callback function. Do not mutate state. Or you can make even simpler.

updateUser = (e) => {
  let key;
  switch(e.target.id){
       case "firstName":
             key = "FirstName";
             break;
       case "lastName":
            key = "LastName";
             break;
       case "email":
            key = "Email";
             break;
        case "userName":
              key = "Username";
             break;
        default:
             return null;
      }
  this.setState({[key]: e.target.value})
}
Talgat Saribayev
  • 1,898
  • 11
  • 19
  • Thanks , i will look at it - But i am familiar with click events - how could i test the switch and case based on my test – user 9191 Feb 28 '19 at 15:18
  • Oh ok there is actually solution for that from previous questions https://stackoverflow.com/questions/43426885/enzyme-simulate-an-onchange-event. I hope the rest is understandable. – Talgat Saribayev Mar 01 '19 at 08:33
  • I will look at it but i never used mocha before - using jest and enzyme for all of my tests – user 9191 Mar 01 '19 at 12:56
  • You do not need mocha. Look to a answer. It is the same things as jest assertions and enzyme wrappers. – Talgat Saribayev Mar 01 '19 at 20:51
1

it's tricky to speculate without actual code(I mean render() method).

Suppose it looks like(I've skipped switch/case to make it shorter)

updateState = ({target: { value, id }}) => {
    this.setState({
        [id]: value,
    });
}

render() {
    return (<>
      <input value={this.state.email} id="email" onChange={this.updateState} />
      <input value={this.state.firstName} id="firstName" onChange={this.updateState} />
      <input value={this.state.lastName} id="lastName" onChange={this.updateState} />
      <input value={this.state.age} id="age" onChange={this.updateState} />
      <div id="raw_output">{JSON.stringify(this.state)}</div>
    </>);
}

Then focusing on testing render()'s result does not need you to mock any functions:

function updateFieldById(wrapper, id, value) {
    wrapper.find(id).simulate('change', { target: { id, value } });
}

it('updates state after each field changed', () => {
    const wrapper = shallow(<Comp />);
    // checking start output with default input
    expect(wrapper.find('#raw_input').props().children).toMatchSnapshot();
    updateFieldById(wrapper, 'email', '_email_mock_');
    expect(wrapper.find('#raw_input').props().children).toMatchSnapshot();
    updateFieldById(wrapper, 'firstName', '_fn_mock_');
    expect(wrapper.find('#raw_input').props().children).toMatchSnapshot();
    updateFieldById(wrapper, 'lastName', '_ln_mock_');
    expect(wrapper.find('#raw_input').props().children).toMatchSnapshot();
    updateFieldById(wrapper, 'age', '999');
    expect(wrapper.find('#raw_input').props().children).toMatchSnapshot();
});

Sure instead of using toMatchSnapshot() you may check for any element's existence or verify particular text value like

    expect(wrapper.find('#fullName').props().children).toEqual('firstName lastName');

Also you may to split test case on by-field basis.

skyboyer
  • 22,209
  • 7
  • 57
  • 64