Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing Select element in a react application

Tags:

reactjs

jestjs

I want to write a test that will check when I change the value of a select element in my react application.

import React, { Component } from 'react';

const TimeList =(props) =>{



return(
    <div>
    <label>
      Time
      <br/>
      <select name="lessonTime" value={props.defaultTime} onChange={props.handleChange}>
        <option value="8:00">8:00</option>
        <option value="8:30">8:30</option>
        <option value="9:00">9:00</option>
        <option value="10:00">10:00</option>
        <option value="12:00">12:00</option>
        <option value="13:30">13:30</option>
        <option value="19:00">19:00</option>
        <option value="19:30">19:30</option>
      </select>
    </label>
    </div>
  );

};

export default TimeList;

My Test code:

it('should select correct time',() =>{
    const mockFunc = jest.fn();
    const wrapper = mount(<TimeList value='10:00'
    onChange={mockFunc}/>)
    console.log(wrapper.props());
    wrapper.find('select').simulate('change',{target:{value:'8:00'}});
    expect(wrapper.find('select').props().value).toBe('8:00');
  });

The error Im getting is:

 Expected value to be (using ===):
      "8:00"
    Received:
      undefined
    
    Difference:
    
      Comparing two different types of values. Expected string but received undefined.

It seems I haven't understood how to test the select element.

Any ideas on how to create this kind of test?

like image 492
mogoli Avatar asked Apr 10 '18 21:04

mogoli


Video Answer


1 Answers

You have two problems here:

  1. You have a controlled component controlled by the defaultTime property. Will never change in your test as the value passed in the props is always the same.
  2. The prop should not be called defaultTime but value (it feels odds to me but that's how it works)

If in your component you change the name of the property as follows:

export const TimeList =(props) =>{
  return(
    <div>
      <label>
        Time
        <br/>
        <select name="lessonTime" value={props.value} onChange={props.handleChange}>
          <option value="8:00">8:00</option>
          <option value="8:30">8:30</option>
          <option value="9:00">9:00</option>
          <option value="10:00">10:00</option>
          <option value="12:00">12:00</option>
          <option value="13:30">13:30</option>
          <option value="19:00">19:00</option>
          <option value="19:30">19:30</option>
        </select>
      </label>
    </div>
  )
}

Then at least you can test that, when the component is firstly displayed, the selected value is correct:

it('should select correct time',() =>{
  const wrapper = mount(<TimeList value='10:00' onChange={jest.fn()}/>)

  expect(wrapper.find('select').props().value).toBe('10:00')
})



In order to test the change of the time you will need to test one level higher (where your state and onChange function is defined). Look at TimeListWrapper in the example below:

export const TimeList =(props) =>{
  return(
    <div>
      <label>
        Time
        <br/>
        <select name="lessonTime" value={props.value} onChange={props.handleChange}>
          <option value="8:00">8:00</option>
          <option value="8:30">8:30</option>
          <option value="9:00">9:00</option>
          <option value="10:00">10:00</option>
          <option value="12:00">12:00</option>
          <option value="13:30">13:30</option>
          <option value="19:00">19:00</option>
          <option value="19:30">19:30</option>
        </select>
      </label>
    </div>
  )
}

export class TimeListWrapper extends React.Component {
  constructor (props, context) {
    super(props, context)
    this.state = {
      timeListValue: '8:00'
    }
    this.handleChange = this.handleChange.bind(this)
  }

  handleChange(event) {
    this.setState({
      timeListValue: event.target.value
    })
  }

  render() {
    return (
      <div>
        <TimeList value={this.state.timeListValue} handleChange={this.handleChange} />
      </div>
    )
  }
}

And this is the test for TimeListWrapper:

it('should select correct time on change',() =>{
  // When component is mounted
  const wrapper = mount(<TimeListWrapper/>)

  // Then its default value is 8:00
  expect(wrapper.find('select').props().value).toBe('8:00')

  // When 10:00 is selected
  wrapper.find('select').simulate('change', {target: {value: '10:00'}})

  // Then its value changes to 10:00
  expect(wrapper.find('select').props().value).toBe('10:00')
})
like image 88
daemon_nio Avatar answered Nov 09 '22 11:11

daemon_nio