javascripttestingconditional-statementscypress

Search for one selector or another in a Cypress test


I need to test something like the following.

If div.table-row.table-row-hover exists, it must contain the specified text.

If div.table-row.table-row-hover does not exist, there must be another element which is selected by i[class="far fa-empty-set"].

My code doesn't work, it fails because doesn't find div.table-row.table-row-hover.

it.only("Test", () => {

  const query = "ExampleText"; 
  cy.get('div[class="ng-search-input"]').type(`${query}{enter}`);
  cy.get("div.table-row.table-row-hover").then(($elements) => {
    if ($elements.length > 0) {
      let textFound = false;
      $elements.each(($el) => {
        const text = Cypress.$($el).text().toLowerCase(); 
        if (text.includes(query.toLowerCase())) {
          textFound = true;
        }
      });
      expect(textFound).to.be.true;
    } else {
      cy.get('i[class="far fa-empty-set"]').should("exist");
    }
  });
});

Solution

  • To find out if you have one selector or another, the easiest way is to compose a "Multiple Selector".

    See this page https://api.jquery.com/multiple-selector/ for documentation.

    const tableRowSelector = 'div.table-row.table-row-hover'
    const emptySetSelector = 'i[class="far fa-empty-set"]'
    const multiSelector = `${tableRowSelector}, ${emptySetSelector}`
    
    cy.get(multiSelector).then($el => {
      if ($el.selector === tableRowSelector) {
        cy.contains(tableRowSelector, query, {matchCase:false})
      } else {
        cy.get('i[class="far fa-empty-set"]')
      }
    })
    

    Problem #1 - is "empty-set" the default?

    It won't work if the i[class="far fa-empty-set"] is the default before you search, because of the time lag involved in searching.

    In this case you need to intercept and wait for the API call

    cy.intercept(<search-url>).as('search')
    
    cy.get('div[class="ng-search-input"]').type(`${query}{enter}`)
    cy.wait('@search')
    
    const tableRowSelector = 'div.table-row.table-row-hover'
    const emptySetSelector = 'i[class="far fa-empty-set"]'
    const multiSelector = `${tableRowSelector}, ${emptySetSelector}`
    
    cy.get(multiSelector).then($el => {
      if ($el.selector === tableRowSelector) {
        cy.contains(tableRowSelector, query, {matchCase:false})
      } else {
        cy.get('i[class="far fa-empty-set"]')
      }
    })
    

    Problem #2 - it's only half a test

    Whichever condition is satisfied, you are only testing one of the conditions.
    If you want a professional test, you must handle both conditions.

    To do that add a fixture to the cy.intercept() in order to set up each condition.

    it('test when search query is found', () => {
      cy.intercept(<search-url>, 'query-found-results.json').as('search')
      cy.get('div[class="ng-search-input"]').type(`${query}{enter}`)
      cy.wait('@search')
      cy.contains('div.table-row.table-row-hover', query, {matchCase:false})
    })
    
    it('test when search query is not found', () => {
      cy.intercept(<search-url>, 'query-not-found.json').as('search')
      cy.get('div[class="ng-search-input"]').type(`${query}{enter}`)
      cy.wait('@search')
      cy.get('i[class="far fa-empty-set"]')
    })