3

I have a time indicator that travels over a timescale, the indicator's style attribute value keeps on changing for every x milliseconds and I need to get, store and compare that the previously captured value is greater than the latest value.

Initial value: enter image description here

Latest value: enter image description here

The logic is, from one point (left 10), every second it moves to the left (left -0, -1, -2, -3 ...)

I tried few ways and one of them is to capture in the same 'cy.then', but in that case, the element will not have the recent value. So far, I tried this. it fetches the value and with some help of regex, I got a 'comparable' value but how I can store/compare those values? Additionally, what is the best way if we need to compare more than 2 values?

const BTN_CONTROL_TIMEINDICATOR = '#currentTimeIndicator'
  static verifyTimeLapse() {
        //wip
        var initialVal, nextVal
        initialVal = this.getAnyValueOfAnElement(BTN_CONTROL_TIMEINDICATOR)
        cy.wait(500)
        nextVal = this.getAnyValueOfAnElement(BTN_CONTROL_TIMEINDICATOR)
        cy.log(initialVal > nextVal) 
    }

  static getAnyValueOfAnElement(element) {
        //wip
        cy.get(element)
           .then(($ele) => {
               const val=$ele.attr('style').replace(/[^\d.-]/g, '')
               cy.log(val)
               // return does not work 
            })
    }

cy.log:

enter image description here

Dhamo
  • 1,171
  • 3
  • 19
  • 41

2 Answers2

4

Page objects don't work very well with the Cypress command queue, here's what you might do with custom commands.

/* Get the numeric value of CSS left in px */
Cypress.Commands.add('getTimescaleValue', () => {
  cy.get('#currentTimeIndicator')
    .then($el => +$el[0].style.left.replace('px',''))
})

/* Get a sequence of time scale values */
Cypress.Commands.add('getTimescaleValues', ({numValues, waitBetween}) => {
  const values = [];
  Cypress._.times(numValues, () => {          // repeat inner commands n times
    cy.getTimescaleValue()
      .then(value => values.push(value))      // save value
      .wait(waitBetween)
  })
  return cy.wrap(values);
})

/* Assert a sequence of values are in descending order */
Cypress.Commands.add('valuesAreDescending', { prevSubject: true }, (values) => {
  values.reduce((prev, current) => {
    if (prev) {                       // skip first (no prev to compare)
      expect(prev).to.be.gt(current)  // assert pairs of values 
    }
    return current
  });
})


it('check the timeline', () => {
  cy.getTimescaleValues({ numValues: 10, waitBetween: 100 })
    .valuesAreDescending()
})

Log

assert expected 63 to be above 58
assert expected 58 to be above 48
assert expected 48 to be above 43
assert expected 43 to be above 33
assert expected 33 to be above 23
assert expected 23 to be above 18
assert expected 18 to be above 13
assert expected 13 to be above 3
assert expected 3 to be above -2

Tested with

<div id="currentTimeIndicator" style="left:63px">Target</div>
<script>
  const timer = setInterval(() => {
    const div = document.querySelector('#currentTimeIndicator')
    const left = +div.style.left.replace('px', '');
    if (left < 0) {
      clearInterval(timer)
      return
    }
    const next = (left - 5) + 'px';
    div.style.left = next;
  }, 100)
</script>

If your app uses setInterval() for timing, you should be able to use cy.clock() and cy.tick() instead of .wait(waitBetween) to get more precise sampling and faster test execution.

1

I don't know where the initial value comes from. But before it changes, maybe on page load, maybe as first job on click, etc you can do something like this:

let item = document.querySelector("#currentTimeIndicator");
item.dataset.left = parseFloat(item.style.left);

console.log(item);
<div id="currentTimeIndicator" style="left:-20px"></div>
Bulent
  • 3,307
  • 1
  • 14
  • 22