Sorted Attributes

📺 Watch this recipe explained in the video Confirm Sorted Attributesopen in new window.

Let's take a dynamically populated list of items.

<ul id="purchases"></ul>
<script>
  const ul = document.getElementById('purchases')
  setTimeout(() => {
    ul.innerHTML += '<li data-sku="0044B">Chair</li>'
  }, 1000)
  setTimeout(() => {
    ul.innerHTML += '<li data-sku="00500A">Table</li>'
  }, 2000)
  setTimeout(() => {
    ul.innerHTML += '<li data-sku="00100C">Bed</li>'
  }, 2500)
  setTimeout(() => {
    ul.innerHTML += '<li data-sku="00991C">Frame</li>'
  }, 3000)
</script>

Each element in the list has data-sku attribute. Can we confirm the final list of attributes? We do not care about the order of the items, so we want to confirm the sorted list of attributes.

// the sorted expected SKU numbers
const skus = ['00991C', '00100C', '00500A', '0044B'].sort()

Let's use cypress-mapopen in new window to map all found DOM elements to their attribute data-sku and then sort the array of strings.

Tip: increase the Chai truncate threshold to see both arrays in the assertion

chai.config.truncateThreshold = 300
cy.get('#purchases li')
  // cy.mapInvoke from cypress-map
  .mapInvoke('getAttribute', 'data-sku')
  .invoke('sort')
  // cy.print from cypress-map
  .print()
  .should('deep.equal', skus)

Alternative solution: use cy.map from cypress-map to get the data-... attributes.

cy.log('**use cy.map**')
cy.get('#purchases li')
  // get the "data-sku" from each DOM element
  .map('dataset.sku')
  .invoke('sort')
  .should('deep.equal', skus)

If you cannot use cypress-map, you should write a single should(callback) to keep extracting the data attributes and compare them to the expected list.

cy.log('**use should(callback)**')
cy.get('#purchases li').should(($elements) => {
  // a single callback to process and assert the attributes
  const attrs = $elements
    .toArray()
    .map((li) => {
      return li.dataset.sku
    })
    .sort()
  expect(attrs).to.deep.equal(skus)
})