2

I'm new to React and testing in general so forgive the naivety of the question. I have a React form component which onChance on the inputs runs a function handleChange. Tried to test it with Jest but can't make it work.

Here's the Login component:

class Login extends React.Component {

  constructor() {
    super();
    this.state = {username: '', password: ''}
    this.disableSubmit = this.disableSubmit.bind(this);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.setState({
      [e.target.name]: e.target.value
    });
  }

  render() {

    return(
      <div className="login">
        <form>
          <h3 className="login__title">LOGIN</h3>
          <div className="input-group">
            <input onChange={this.handleChange} value={this.state.username} className="form-control login__input username" type="text" placeholder="user name" name={'username'} autoFocus/>
          </div>
          <div className="input-group">
            <input onChange={this.handleChange} value={this.state.password} className="form-control login__input password" type="password" placeholder="password" name={'password'}/>
          </div>
          <div>
            <button className="btn btn-primary btn-block login__button" type="submit">Login</button>
          </div>
        </form>
      </div>

    )
  }
}

export default Login;

Here's my test:

import React from 'react'
import { shallow, mount } from 'enzyme'
import { shallowToJson } from 'enzyme-to-json'


import {Login} from '../../../src/base/components/index'


describe('Given the Login component is rendered', () => {

  describe('Snapshots', () => {
    let component

    beforeEach(() => {
      component = shallow(<Login />)
    })

    it('should be as expected', () => {
      expect(shallowToJson(component)).toMatchSnapshot()
    })
  })

})


test('Submitting the form should call handleSubmit', () => {

  const startState = {username: ''};
  const handleChange = jest.fn();
  const login = mount(<Login />);
  const userInput = login.find('.username');

  userInput.simulate('change');

  expect(handleChange).toBeCalled();

})

The snapshot test passes fine, but in this last attempt my function test fails with:

TypeError: Cannot read property 'target' of undefined

Guess I need to pass something to the function? Bit confused!

Thanks in advance for your help.

UPDATE:

changed the test as follows but test fails with: expect(jest.fn()).toBeCalled() Expected mock function to have been called.

test updated:

test('Input should call handleChange on change event', () => {

  const login = mount(<Login />);
  const handleChange = jest.spyOn(login.instance(), 'handleChange');
  const userInput = login.find('.username');
  const event = {target: {name: "username", value: "usertest"}};

  userInput.simulate('change', event);

  expect(handleChange).toBeCalled();

})
1
  • handleChange isn't currently being mocked. Commented Sep 15, 2017 at 15:56

3 Answers 3

2

Yes, you'll need to pass an event object to you simulate function.

  const event = {target: {name: "special", value: "party"}};

  element.simulate('change', event);

EDIT: Oh, and you'll also need to do something like:

jest.spyOn(login.instance(), 'handleChange')

but that's unrelated to your error

Sign up to request clarification or add additional context in comments.

Comments

2

Found the solution in here: Enzyme simulate an onChange event

test('Input should call handleChange on change event', () => {

  const event = {target: {name: 'username', value: 'usertest'}};
  const login = mount(<Login />);
  const handleChange = jest.spyOn(login.instance(), 'handleChange');
  login.update(); // <--- Needs this to force re-render
  const userInput = login.find('.username');

  userInput.simulate('change', event);

  expect(handleChange).toBeCalled();

})

It needed this login.update(); in order to work!

Thank everyone for your help!

Comments

0

handleChange isn't currently being mocked. A couple of approaches:

Pass change event handler as prop to Login component.

<div className="input-group">
  <input 
    onChange={this.props.handleChange} 
    value={this.state.username}
    className="form-control login__input username" 
    type="text"
    placeholder="user name"
    name={'username'}
    autoFocus
    />
</div>

login.spec.js

...
const handleChange = jest.fn();
const login = mount(<Login handleChange={handleChange}/>);
...

Replace handleChange with the mock function.

...
const handleChange = jest.fn();
const login = mount(<Login />);
login['handleChange'] = handleChange // replace instance
...
expect(handleChange).toBeCalled();

Use jest spyOn to create a mock function that wraps the original function.

...
const handleChange = jest.spyOn(object, 'handleChange') // will call the original method
expect(handleChange).toBeCalled();

Replace handleChange on the Login component with a mock function. ... const handleChange = jest.spyOn(object, 'handleChange').mock // will call the original method expect(handleChange).toBeCalled();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.