user9847788
user9847788

Reputation: 2445

How to compare an array against a list of UI elements in Cypress?

In my Cypress tests, I am trying to compare an array of objects (names) returned to me from a SQL query against a list of elements on my UI (the same names).

Here is my initial attempt at comparing the values:

import searchResultsPage from "../page_objects/searchResults.page"

cy.task('queryDb', `SELECT * FROM myTable where name like '%${queryInput}%';`).then(result => {
    for(var i=0;i<result.length;i++) {
        searchResultsPage.name(i+1).should('have.text', `${result[i].name}`)
    }
})

Here is my page object file - searchResults.page.js:

class searchResultsPage {

    name(index) { return cy.get(`#mat-option-${index+1} > .mat-option-text`) }

}

module.exports = new searchResultsPage()

The problem with the above code is that the lists contain the exact same values, however they are not in the same order.

The database can store the names like Adam, Bill, Charlie, but the UI may display them like Charlie, Adam Bill.

The test should pass if the same records are in both lists, regardless of their order.

I attempted to re-order both arrays alphabetically below, & compare the values. The array from the SQL query (result) is sorting as expected. However, the array of HTML elements (myArray) is not sorting alphabetically:

cy.task('queryDb', `SELECT * FROM myTable where name like '%${queryInput}%';`).then(result => {

        let myArray;

        cy.get('mat-option').then(elements => {

            myArray = Array.from(elements, element => element.innerText);
            
            cy.log(myArray)

            myArray.sort((a, b) => {
                if (a.name < b.name) {
                    return -1;
                }
                if (a.name > b.name) {
                    return 1;
                }
                return 0;
            });

            cy.log('HTML array:')

            for (var i = 0; i < myArray.length; i++) {
                cy.log(myArray[i])
            }

            cy.log('*********')

            result.sort((a, b) => {
                if (a.name < b.name) {
                    return -1;
                }
                if (a.name > b.name) {
                    return 1;
                }
                return 0;
            });

            cy.log('SQL array:')

            for (var i = 0; i < result.length; i++) {
                cy.log(result[i].name)
            }

            cy.log('*********')

        }).then(() => {

            for (var i = 0; i < result.length; i++) {
                cy.log(result[i].name)
                cy.log(myArray[i])
                expect(result[i].name).to.deep.eq(myArray[i])
            }

        })
    })

Can someone please explain why the result array isn't sorting alphabetically above?

Upvotes: -1

Views: 849

Answers (2)

TesterDick
TesterDick

Reputation: 10555

Rather than trying to sort it yourself, you can use set membership

cy.task('queryDb', `SELECT * FROM myTable...`).then(result => {
  cy.get('mat-option')
    .should(elements => {
      const elementNames = Array.from(elements, element => element.innerText))
      const resultNames = result.map(r => r.name)

      expect(resultNames).to.have.members(elementNames)  

    })
})

Using .should() will allow Cypress to retry to the assertion (in case the elements are still loading).

Ref: Testing Arrays and Objects with Chai.js

Upvotes: 1

Daniel
Daniel

Reputation: 35684

One way to do it is to split sort and join both the sql and the html texts


  it("does some checking", () => {
    // this would come from the sql task
    const myExpectation = "Charlie, Adam, Bill";

    // split, trim, sort, and join the string
    const cleanSql = str => str.split(/[\,]/gi).map(s => s.trim()).sort().join(",");
    
    // function uses `then` to get texts and sort and join it
    const getNames = (index) => {
      return cy
        .get(`#mat-option-${index + 1} > .mat-option-text`)
        .then((chainer) => {
          const values = [...chainer.map((el) => chainer[el].innerText)];
          return values.sort().join(",");
        });
    };

    // uses `equal` because the returned value is a string (have.text wouldn't work on it)
    getNames(1).should("equal", cleanSql(myExpectation));
  });

This assumes your html looks like this

<div id="mat-option-2">
  <div class="mat-option-text">Bill</div>
  <div class="mat-option-text">Adam</div>
  <div class="mat-option-text">Charlie</div>
</div>

I'm using static myExpectation for local testability. You would, obviously, have to adapt that to your setup.

Upvotes: 0

Related Questions