Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wrapper not updated after simulate('change'). #1999

Open
sharmapuneet opened this issue Feb 4, 2019 · 15 comments
Open

wrapper not updated after simulate('change'). #1999

sharmapuneet opened this issue Feb 4, 2019 · 15 comments
Projects

Comments

@sharmapuneet
Copy link

@sharmapuneet sharmapuneet commented Feb 4, 2019

Describe the bug
During the test case, I perform a full mount on a component. After finding the input element, I simulate a change event in which I know the callback function is triggered since the value of the variable being passed back is asserted to be true. However, the props of the element do not get updated.

Test

import TripType from '.'

/** @test {TripType} */
describe('<TripType/>', () => {
  /** @test {TripType#TripTypedisplays} */
  it('should render the TripType class', () => {
    const onChange = jest.fn()
    const wrapper = shallow(<TripType name="test" onChange={onChange} />)

    expect(wrapper).toMatchSnapshot()
  })

  /** @test {TripType#displays} */
  it('should trigger the onChange event', () => {
    const onChange = jest.fn()
    const wrapper = mount(<TripType name="test" onChange={onChange} />)

    wrapper.find('input[value="return"]').simulate('change', { target: { checked: true } })

    expect(onChange).toBeCalled()
  })

  /** @test {TripType#displays} */
  it('should change value', () => {
    const wrapper = mount(<TripType name="test" defaultSelected="return" />)

    expect(wrapper.find('input[value="return"]').prop('checked')).toBe(true)
    expect(wrapper.find('input[value="oneway"]').prop('checked')).toBe(false)

    wrapper.find('input[value="oneway"]').simulate('change', { target: { checked: true } })

    expect(wrapper.find('input[value="return"]').prop('checked')).toBe(false)
    expect(wrapper.find('input[value="oneway"]').prop('checked')).toBe(true)
  })
})

In the above test third test fails. I tried wrapper.update(), wrapper.forceUpdate() but no luck.

Expected behavior
Expected: false
Received: false

But getting -
Expected: false
Received: true

Screenshots
screen shot 2019-02-04 at 5 34 59 pm

Desktop (please complete the following information):

OS: MacOS High Sierra 10.13.6
React: "^16.0.0",

@ljharb

This comment has been minimized.

Copy link
Member

@ljharb ljharb commented Feb 4, 2019

You may need a wrapper.update(); in general, I'd advise against ever using simulate - it doesn't actually simulate anything. Instead, explicitly invoke the prop function you want.

@sharmapuneet

This comment has been minimized.

Copy link
Author

@sharmapuneet sharmapuneet commented Feb 4, 2019

@ljharb I tried the below with no luck -

it('should change value', () => {
    const wrapper = mount(<TripType name="test" defaultSelected="return" />)

    expect(wrapper.find('input[value="return"]').prop('checked')).toBe(true)
    expect(wrapper.find('input[value="oneway"]').prop('checked')).toBe(false)

    wrapper.find('input[value="oneway"]').simulate('change', { target: { checked: true } })
    wrapper.update()
    expect(wrapper.find('input[value="return"]').prop('checked')).toBe(false)
    expect(wrapper.find('input[value="oneway"]').prop('checked')).toBe(true)
  })
@ljharb

This comment has been minimized.

Copy link
Member

@ljharb ljharb commented Feb 4, 2019

Try wrapper.find('input[value="oneway"]').prop('onChange', { target: { checked: true } }) instead of simulate.

@sharmapuneet

This comment has been minimized.

Copy link
Author

@sharmapuneet sharmapuneet commented Feb 4, 2019

Same results.

@ljharb

This comment has been minimized.

Copy link
Member

@ljharb ljharb commented Feb 4, 2019

Can you share the actual code for your component?

@sharmapuneet

This comment has been minimized.

Copy link
Author

@sharmapuneet sharmapuneet commented Feb 4, 2019

import React from 'react'
import PropTypes from 'prop-types'
import FormControl from '@material-ui/core/FormControl'
import KeyboardArrowRightIcon from '@material-ui/icons/KeyboardArrowRight'
// import { RadioButton, RadioButtonGroup } from 'material-ui/RadioButton'
import Radio from '@material-ui/core/Radio'
import RadioGroup from '@material-ui/core/RadioGroup'
import FormControlLabel from '@material-ui/core/FormControlLabel'
import './_styles.scss'

/**
 * Trip Type component.
 *
 * This component handles the selection of whether a trip is one-way or return.
 *
 * @export
 * @version 1.0.1
 * @param {object} props Incoming config.
 * @return {React.Component} Return react component.
 */
const TripType = ({ name, defaultSelected, multiStopLink, multiStopLinkColour, onChange }) => (
  <FormControl component="fieldset">
    <RadioGroup name={name} onChange={onChange} value={defaultSelected} row>
      <FormControlLabel value="return" control={<Radio color="primary" />} label="Return" labelPlacement="end" />
      <FormControlLabel value="oneway" control={<Radio color="primary" />} label="One Way" labelPlacement="end" />
      {/* <Radio
        className="trip-type__return"
        value="return"
        label="Return"
        iconStyle={{ marginRight: '0.5rem' }}
        labelStyle={{ width: 'inherit' }}
      /> */}
      {/* <Radio
        className="trip-type__one-way"
        value="oneway"
        label="One Way"
        iconStyle={{ marginRight: '0.5rem' }}
        labelStyle={{ width: 'inherit' }}
      /> */}
      {multiStopLink && (
        <div className="trip-type__multi-stop">
          <a href={multiStopLink}>
            Multi-stop
            <span className="trip-type__link-icon">
              <KeyboardArrowRightIcon style={{ fill: multiStopLinkColour }} />
            </span>
          </a>
        </div>
      )}
    </RadioGroup>
  </FormControl>
)

TripType.propTypes = {
  multiStopLink: PropTypes.string,
  name: PropTypes.string.isRequired,
  defaultSelected: PropTypes.string.isRequired,
  multiStopLinkColour: PropTypes.string.isRequired,
  onChange: PropTypes.func.isRequired,
}

TripType.defaultProps = {
  multiStopLink: null,
}

export default TripType
@ljharb

This comment has been minimized.

Copy link
Member

@ljharb ljharb commented Feb 4, 2019

ok - and what about FormControlLabel? (note, it's pretty strange to be doing tests of TripType and coupling to implementation details of FormControlLabel - i'd suggest preferring shallow tests over mount tests whenever possible)

@sharmapuneet

This comment has been minimized.

Copy link
Author

@sharmapuneet sharmapuneet commented Feb 4, 2019

So you are saying it won't work with mount?

@sharmapuneet

This comment has been minimized.

Copy link
Author

@sharmapuneet sharmapuneet commented Feb 4, 2019

Can you help me how can I write the third test with shallow?

@ljharb

This comment has been minimized.

Copy link
Member

@ljharb ljharb commented Feb 4, 2019

It should certainly work with mount; but I'm saying you shouldn't be testing FormControlLabel except in the FormControlLabel tests.

@sharmapuneet

This comment has been minimized.

Copy link
Author

@sharmapuneet sharmapuneet commented Feb 4, 2019

oh ok.

@garncarz

This comment has been minimized.

Copy link

@garncarz garncarz commented May 12, 2019

@sharmapuneet This helped me with a similar problem: .simulate('change', {target: {name: 'name_of_input', value: 'value'}}) (or checked: true in your case). The thing is if the event function sets state dynamically like state.some_variable[event.target.name] = event.target.value;, the name is unfortunately undefined without specifying it (even if set in HTML).

@brockross

This comment has been minimized.

Copy link

@brockross brockross commented Jun 11, 2019

@garncarz thank you so much! I hadn't realized I needed to explicitly state the name attribute in the synthetic event; I was relying on my exiting JSX to handle that for me. This was so helpful!

@AbhishekPratap05

This comment has been minimized.

Copy link

@AbhishekPratap05 AbhishekPratap05 commented Jul 30, 2019

Try wrapper.find('input[value="oneway"]').prop('onChange', { target: { checked: true } }) instead of simulate.

After using this i am getting Expected 1 arguments, but got 2

@t-lock

This comment has been minimized.

Copy link

@t-lock t-lock commented Sep 28, 2019

@garncarz thank you so much!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
simulate
Awaiting triage
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.