Get multiple fields

This recipe answers the question #15762open in new window:

How would I read multiple input fields at once/

Imagine a form with multiple input fields, we want to place all their values into a single object.

Explicit test

First, let's write the explicit test

<form>
  <label for="fname">First name:</label><br />
  <input type="text" id="fname" name="fname" value="Joe" /><br />
  <label for="lname">Last name:</label><br />
  <input type="text" id="lname" name="lname" value="Smith" />
</form>
// this object will collect the values from every field
const values = {}
cy.get('#fname')
  .invoke('attr', 'value')
  .then((s) => {
    values.firstName = s
  })
cy.get('#lname')
  .invoke('attr', 'value')
  .then((s) => {
    values.lastName = s
  })
// use cy.wrap to work with an object "values"
// the assertion "deep.equal" will execute AFTER
// every field value is placed into the wrapped object
cy.wrap(values).should('deep.equal', {
  firstName: 'Joe',
  lastName: 'Smith',
})

Reusable function

Let's write a reusable function that returns a Cypress chain that yields the wrapped object

<form>
  <label for="fname">First name:</label><br />
  <input type="text" id="fname" name="fname" value="Joe" /><br />
  <label for="lname">Last name:</label><br />
  <input type="text" id="lname" name="lname" value="Smith" />
</form>
function getMultipleFields(selectors) {
  // this object will collect the values from every field
  const values = {}
  // return the "cy" command chain
  return cy
    .wrap(selectors)
    .each((selector) => {
      cy.get(selector)
        .invoke('attr', 'value')
        .then((s) => {
          values[selector] = s
        })
    })
    .then(() => {
      // by now all input elements were queried
      // return the wrapped "values" object
      return cy.wrap(values)
    })
}

// the "getMultipleFields" yields the object
// with input field values stores by selector
getMultipleFields(['#fname', '#lname']).should('deep.equal', {
  '#fname': 'Joe',
  '#lname': 'Smith',
})

Custom command

We can also write a custom Cypress commandopen in new window:

<form>
  <label for="fname">First name:</label><br />
  <input type="text" id="fname" name="fname" value="Joe" /><br />
  <label for="lname">Last name:</label><br />
  <input type="text" id="lname" name="lname" value="Smith" />
</form>
Cypress.Commands.add('getMultipleFields', (selectors) => {
  const values = {}
  selectors.forEach((selector) => {
    cy.get(selector)
      .invoke('attr', 'value')
      .then((s) => {
        values[selector] = s
      })
  })

  // the custom command should yield the values of values
  cy.wrap(values)
})

// call the custom command and assert the yielded object
cy.getMultipleFields(['#fname', '#lname']).should('deep.equal', {
  '#fname': 'Joe',
  '#lname': 'Smith',
})

Reusable function with aliases

If we need to get text / values from multiple page elements, we can write separate Cypress chains, saving each value under an alias. Then we can get the multiple values from the test context properties using the function () { ... } callback syntax.

<form>
  <label for="fname">First name:</label><br />
  <input type="text" id="fname" name="fname" value="Joe" /><br />
  <label for="lname">Last name:</label><br />
  <input type="text" id="lname" name="lname" value="Smith" />
</form>
function getFormValues() {
  return (
    cy
      .get('form')
      .within(() => {
        cy.get('#fname').invoke('val').as('fname')
        cy.get('#lname').invoke('val').as('lname')
      })
      // by using "function (){...}" callback
      // we bind the "this" reference to the test context object
      // where every alias created using "cy.as(<name>)" command
      // is stored automatically as a property <name>
      .then(function () {
        // We can return an object with the values
        // Tip: use Lodash _.pick function
        // to pick list of properties from a larger object
        return Cypress._.pick(this, ['fname', 'lname'])
      })
  )
}

getFormValues().should('deep.equal', {
  fname: 'Joe',
  lname: 'Smith',
})
// change the input values and confirm
cy.get('#fname').clear().type('Anna')
cy.get('#lname').clear().type('Vine')
getFormValues().should('deep.equal', {
  fname: 'Anna',
  lname: 'Vine',
})

Watch the video Get Multiple Values From The Page Via Aliases And Test Context Propertiesopen in new window.

See the recipe Get form input using label