question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

can't trigger 'onChange' for an input type='range' rendered by React

See original GitHub issue

Current behavior:

...
return (
...
<div className="search-bar__form-range">
  <input type="range" min={10} max={900} step={10} value={500} onChange={(event)=>alert(`slider changed
  to:${event.target.value}`)}
  />
...
cy.get('.search-bar__form-range > input[type=range]').as('range').invoke('val', 700)
  .trigger('change');

Changes the slider value. Doesn’t trigger the onChange handler.

Desired behavior:

should trigger the onChange handler

Steps to reproduce:

Set up a React app with an input type=‘range’ and an onChange handler Try to trigger the onChange event from cypress.

Versions

“cypress”: “^2.1.0” “react”: “^15.4.2”

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:9
  • Comments:31 (1 by maintainers)

github_iconTop GitHub Comments

80reactions
davemyersworldcommented, Jan 14, 2019

I have put together a workaround for this issue that does not require switching to the input event.

There are two parts:

  1. Set the value of the underlying DOM node (avoiding React’s override)
  2. Fire a change event on it such that React picks up the change.

That works like this:

// React overrides the DOM node's setter, so get the original, as per the linked Stack Overflow
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
describe('Range', () => {
  it('Updates the value and UI when changing a range input', () => {
    cy.get('input[type="range"]').then(($range) => {
      // get the DOM node
      const range = $range[0];
      // set the value manually
      nativeInputValueSetter.call(range, 15);
      // now dispatch the event
      range.dispatchEvent(new Event('change', { value: 15, bubbles: true }));
    });
  });
});

I’m fairly new to the cypress ecosystem, so perhaps someone can do this in a more cypress-y way, but this solves the problem.

11reactions
RobertoPegorarocommented, Aug 2, 2021

Has anyone managed to program the workaround with Typescript? I’m getting always a Type Error - Illegal invocation for this:

const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
  window.HTMLInputElement.prototype,
  'value'
)?.set

const changeRangeInputValue = ($range: JQuery<HTMLElement>) => (value: number) => {
  nativeInputValueSetter?.call($range[0], value)

  $range[0].dispatchEvent(new Event('change', { value, bubbles: true }))
}

@cjoecker, @JonathanAbdon this works with typescript -> #1570 (comment)

It doesn’t work for TypeScript. I received the error: Argument of type '{ value: number; bubbles: true; }' is not assignable to parameter of type 'EventInit'. Object literal may only specify known properties, and 'value' does not exist in type 'EventInit'

So I’ve solved my problem with this issue for TypeScript using the following code: In commands:

Cypress.Commands.add('setSliderValue', { prevSubject: 'element' },
    (subject, value) => {
        const element = subject[0]

        const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
            window.HTMLInputElement.prototype,
            'value'
        )?.set
        
        nativeInputValueSetter?.call(element, value)
        element.dispatchEvent(new Event('input', { bubbles: true }))
    }
)

declare namespace Cypress {
    interface Chainable {
        setSliderValue(value: number): Chainable<void>
    }
}

And use it in the test:

cy.get('input[name="sliderComponentInput"]').setSliderValue(25)
Read more comments on GitHub >

github_iconTop Results From Across the Web

Trigger change event for React rendered input (type=range)
Ok, so I've found sort of a workaround. it looks like the onInput event can be triggered just fine. In the case of...
Read more >
How to trigger onchange event on input type=range while ...
Onchange : Onchange executes a JavaScript when a user changes the state of a select element. This attribute occurs only when the element...
Read more >
FAQs | React Hook Form - Simple React forms validation
React Hook Form relies on uncontrolled form, which is the reason why the register function capture ref and controlled component has its re-rendering...
Read more >
Value Bubbles for Range Inputs | CSS-Tricks
Range inputs in HTML are like this: <input type="range" name="quantity" min="1" max="10">. In browsers that support them, they look like ...
Read more >
Uncontrolled Components - React
In the React rendering lifecycle, the value attribute on form elements will override the value in the DOM. With an uncontrolled component, you...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found