Return value from nested wrap

Viewed 531

I am starting out with cypress and I have a doubt about returning a value form a custom command.

I have multiple tables across my application, and in my tables I can click a row that will open a modal with more deailed information. So I want to build a command to extract the values of a specific row, so I can store them and then compare with the modal values.

I'm also trying to do this command in a way to reuse across the different tables. However I am having issues with my return value. This is my current command:

Cypress.Commands.add(
  'getRowInformation',
  (rowsSelector, compareValue, mainProperty, nestedSelector) => {
    let rowNumber = -1
    const propertiesObject = {}

    /** 
     * get all the field in the all the rows that might contain the compareValue
     */
    cy.get(`[data-testid="${mainProperty}"]`).then($elements => {
      cy.wrap($elements)
        .each(($elementField, index) => {
          /**
           * Find first match and get the row index
           */
          if (rowNumber === -1 && $elementField.text() === compareValue) {
            rowNumber = index + 1
          }
        })
        .then(() => {
          /**
           * Access needed row
           */
          rowsSelector()
            .eq(rowNumber)
            .within(() => {
              cy.get(nestedSelector).then($property => {
                cy.wrap($property)
                  .each($prop => {
                    Object.assign(propertiesObject, { [$prop.attr('data-testid')]: $prop.text() })
                  })
                  .then(() => {
                    /**
                     * Return key value map, where key in data-testid
                     * and value is the element's text
                     */
                    return cy.wrap(propertiesObject)
                  })
              })
            })
        })
    })
  },
)

And I am calling this command in my it() as:

cy.getRowInformation(myCustomSelector, 'Compare value', 'testid', 'span').then(properties => {
    console.log('properties', properties)
    expect(true).to.be.true
})

My custom selector:

myCustomSelector: () => cy.get('[data-testid="row"]'),

My problem is that what gets to my .then in my it() is the rowsSelector().eq(rowNumber) and what I needed is the created propertiesObject. From the docs I could not get an example as nested as this, so do you guys think this is doable?

2 Answers

Docs say .within() yields the same subject it was given from the previous command.

So it seems you have to move your cy.wrap(propertiesObject) out of the within callback and put it in the outer then

You can also sub in .find() which is syntactically equivalent to .within()

rowsSelector()
  .eq(rowNumber)
  .find(nestedSelector).each($prop => {
    Object.assign(propertiesObject, { [$prop.attr('data-testid')]: $prop.text() })
  })
  .then(() => cy.wrap(propertiesObject))  

You might also want to review this Cypress, get index of th element to use it later for it's td element for the section that finds the rowNumber.

I haven't tried it, but maybe

cy.contains(`[data-testid="${mainProperty}"]`, compareValue)  // only 1st match returned
  .invoke('index')
  .then((rowNumber) => {
    rowsSelector()
      .eq(rowNumber)
      .find(nestedSelector)
      .each($prop => {
        Object.assign(propertiesObject, { [$prop.attr('data-testid')]: $prop.text() })
      })
      .then(() => cy.wrap(propertiesObject))
  })
Related