Search code examples
javascriptpromisecypresspageobjects

How to extract text value and assign it to variable outside then scope in cypress


I want to somehow get some price values from the page I am on.
I would like to do with cypress the following:

  1. get the text from the page element,
  2. turn it to a number
  3. then save it on the price JS object
  4. return the price JS object

This is what I did so far:

  getCheckoutPricesBeforeApplyingVoucher() {
    let prices = {
      subtotalPrice: 0,
      totalPrice: 0,
      itemPriceOrderOverview: 0,
      totalPriceOrderOverview: 0,
      totalWithVATOrderOverview: 0
    }
      prices.subtotalPrice = this.getPrice('[data-cy=subtotalPrice]')
      prices.totalPrice = this.getPrice('[data-cy=totalPrice]')
      prices.itemPriceOrderOverview = this.getPrice('[data-cy=itemPriceOrderOverview]');
      prices.totalPriceOrderOverview = this.getPrice('[data-cy=totalPriceOrderOverview]');
      prices.totalWithVATOrderOverview = this.getPrice('[data-cy=totalWithVATOrderReview]');
      cy.log(prices.subtotalPrice);
      cy.log(prices.totalPrice);
      cy.log(prices.itemPriceOrderOverview);
      cy.log(prices.totalPriceOrderOverview);
      cy.log(prices.totalWithVATOrderOverview);
      return prices;
  }

   getPrice(selector) {
    return cy.get(selector)
      .invoke('text')
      .then((text) => {
        return Number(text);
      })
  }

But the values that my prices JS object has are all 0 when written in the console with for example cy.log(prices.subtotalPrice). They are not set to the corresponding values from UI elements.
Do you have an advise how to do this properly? Maybe my whole approach should go in different direction?
Thanks!

[EDIT] I tried this as well, but the result for some reason is still 0 for each value from JS object.

  getCheckoutPricesBeforeApplyingVoucher() {
    let prices = {
      subtotalPrice: 0,
      totalPrice: 0,
      itemPriceOrderOverview: 0,
      totalPriceOrderOverview: 0,
      totalWithVATOrderOverview: 0
    }

    cy.get('[data-cy=subtotalPrice]').invoke('text').as('subtotalPrice');
    cy.get('[data-cy=totalPrice]').invoke('text').as('totalPrice');
    cy.get('[data-cy=itemPriceOrderOverview]').invoke('text').as('itemPriceOrderOverview');
    cy.get('[data-cy=totalPriceOrderOverview]').invoke('text').as('totalPriceOrderOverview');
    cy.get('[data-cy=totalWithVATOrderReview]').invoke('text').as('totalWithVATOrderReview');

    prices.subtotalPrice = this.subtotalPrice;
    prices.subtotalPrice = this.totalPrice;
    prices.subtotalPrice = this.itemPriceOrderOverview;
    prices.subtotalPrice = this.totalPriceOrderOverview;
    prices.subtotalPrice = this.totalWithVATOrderReview;

    cy.log(prices.subtotalPrice);
    cy.log(prices.totalPrice);
    cy.log(prices.itemPriceOrderOverview);
    cy.log(prices.totalPriceOrderOverview);
    cy.log(prices.totalWithVATOrderOverview);
    return prices;
  }

Solution

  • Cypress commands like cy.get(...) are asynchronous in order to provide retry for asynchronous elements, for example if the data comes from an API.

    Mixing Cypress commands with Page Object methods is problematic, because the methods then have to become asynchronous as well.

    If you are absolutely sure that the data is present in the page, you can switch to the synchronous Cypress.$(...) which will directly set your object properties.

    getCheckoutPricesBeforeApplyingVoucher() {
      return {
        subtotalPrice: +Cypress.$('[data-cy=subtotalPrice]').text(),
        totalPrice: +Cypress.$('[data-cy=totalPrice]').text(),
        itemPriceOrderOverview: +Cypress.$('[data-cy=itemPriceOrderOverview]').text(),
        totalPriceOrderOverview: +Cypress.$('[data-cy=totalPriceOrderOverview]').text(),
        totalWithVATOrderOverview: +Cypress.$('[data-cy=totalWithVATOrderReview]').text()
      }
    }