reactjstestingionic-frameworkrangecypress

Test IonRange in Cypress


It is interesting, that such standard behaviour in such a standard component is so hard to test.

Given an IonRange element in my Ionic React component:

<IonRange
  min={0}
  max={30}
  onIonInput={()=> console.log("changed")}
/>

When I manually test the IonRange, I get the console output as expected. However, when I have my cypress test like this (pretty much copied over from the docs):

cy.get("ion-range")
  .as('range')
  .invoke('val', 10)
  .trigger('change')

I expect to see the log statement in the output.

Actual behaviour: the range knob jumps to the expected position but the onIonInout callback is never invoked.

I also tried other triggers, such as

  .trigger('ion-change')
  .trigger('input')
  .trigger('ion-input')
  .trigger('range-change')
  .trigger('ionChange')
  .trigger('ionInput')

all leading to the same behaviour.

I also tried to workaround using arrow keys. That would be a very unsatisfying solution, because it does not generalise for cases with ranges of, say, 0 to 10,000. I tried it anyway:

cy.get("ion-range").type('{rightArrow}') // trows "this is a non-typable element"

The range knob jumps to the centre (weirdly).

The workaround that I ended up with is:

cy.get("ion-range").click() // clicks in the centre 

(also mentioned by @SuchAnIgnorantThingToDo-UKR) and then I expect the value 15. But due to differences in rendering resolutions (even with a set viewport), the result flakes between 15 and 16. Also, this solution is very unsatisfying given we might want to assert for specific values)

I reviewed the following:

Please let me know if you have any idea for this very trivial every-day problem.


Solution

  • @SuchAnIgnorantThingToDo-UKR already answered in great detail.

    I just want to add how to test the dragging. You can do this:

    describe('Components', () => {
      it('ion-range', () => {
        cy.visit('https://ionicframework.com/docs/usage/v7/range/basic/demo.html?ionic:mode=ios')
    
        cy.get('ion-range').as('slider')
    
        const waitTime = 200
    
        cy.get('@slider') //
          .trigger('mouseenter')
          .wait(waitTime)
          .trigger('mousedown', 100, 0)
          .wait(waitTime)
          .trigger('mousemove', 150, 1, { force: true })
          .wait(waitTime)
          .trigger('mousemove', 200, 1, { force: true })
          .wait(waitTime)
          .trigger('mousemove', 300, 1, { force: true })
          .wait(waitTime)
          .trigger('mouseup', 300, 1)
      })
    })