1. Cypress

Cypress Assertions

Assertions are the validation steps that determine whether the specified step of the automated test case succeeded or not. In actual, Assertions validates the desired state of your elements, objects, or application under testEg. Assertions enable you to validate scenarios such as whether an element is visible or has a particular attribute, CSS class, or state. It is always a recommended practice that all the automated test cases should have assertion steps. Otherwise, it will not be feasible to validate whether the application reached the expected state or not. Cypress itself bundles assertions provided by ChaiSinon, and jQuery libraries. We will cover a few of these assertions and their practical usage under below topics in this article:

  • What are Cypress Assertions?
    • What are Implicit assertions in Cypress?
    • Similarly, what is an Explicit assertion in Cypress?
  • When not to assert in Cypress?
  • What are Common Cypress Assertions?

What are Cypress Assertions?

Cypress integrates multiple assertions from various JS assertion libraries such as Chai, jQuery, etc. We can broadly classify all of these assertions into two segments based on the subject on which we can invoke them:

  • Implicit Assertions
  • Explicit Assertions

Let’s understand the details of both of these in the following sections:

What are Implicit Assertions in Cypress?

When the assertion applies to the object provided by the parent chained command, its called an Implicit assertion. Additionally, this category of assertions generally includes commands such as “.should()” and “.and()“. As these commands don’t stand independently and always depends on the previously chained parent command, they automatically inherit and acts on the object yielded by the previous command.

E.g., Consider the below code snippet:

cy.get('#loginButton')
  .should('have.class', 'active')
  .and('have.attr', 'href', '/login')

As .should('have.class') does not change the subject, .and('have.attr') is executed against the same element, it is handy to use these Implicit assertions when you need to assert multiple things against a single subject quickly.

Generally, we use Implicit assertions when we want to:

  • Assert multiple validations about the same subject.
  • Alter the subject before making the assertions on the subject.

Let’s understand the usage of “Implicit assertions” with the help of following code snippet:

/// <reference types="Cypress" />
 
describe('Implicit Assertions', () => {
  it('.should() - make an assertion about the current subject', () => {
    cy.visit('https://demoqa.com/automation-practice-table/')
    
    cy.get('.tsc_table_s13')
      .find('tbody tr:last')
      .should('have.class', 'odd')
      .find('td')
      .first()
      
      // checking the text of the <td> element in various ways
      .should('have.text', 'China')
      .should('contain', 'China')
      .should('have.html', 'China')
      .should('match', 'td')
      
      // Checking whether the text matches the regular expression
      // Here, first we have invoked the jQuery method text()
      // and then validated it using the regular expression
      .invoke('text')
      .should('match', /China/i)
  })

  it('.and() - chain multiple assertions together', () => {
    
    cy.get('#sidebar')
      .should('have.class', 'widget-area')
      .and('have.attr', 'role')
      .and('include', 'complementary')
  })
})

When we run the above test, it will show the output as shown below:

As we can see, in the above code snippet, it has two “it” blocks, which show the usage of “.should()” and “.and()“.

  • In the first test, we are checking the table and performing various assertions using the “should” command. Here assertions are being done using the text, contain, match, and other properties of the table present in DOM. Also, we can see that the subject was being changed from “assertion-table” to first “td” before performing further assertions.
  • In the second test, it is displaying how multiple assertions can be chained together using and command.

What are Explicit Assertions in Cypress?

When there is a need to pass an explicit subject for the assertion, it falls under the category of Explicit assertion. This category of assertions contains the commands such as “expect()” and “assert()“, which allow you to pass an explicit subject/object.

E.g., See the below code snippet for “expect():

expect(true).to.be.true
// The the explicit subject the boolean: true
const obj = { foo: 'bar' }
expect(obj).to.equal(obj)
expect(obj).to.deep.equal({ foo: 'bar' })
// The explicit subject here is the object obj.

Similarly, explicit subjects can be validated using the “assert()” method.

E.g., In the code snippet below, the “assert()” method is used for assertions where the employee object passes explicitly.

const employee = 
{ name: 'Lakshay', age: 34, }

assert.isObject(employee, 'value is object')

Generally, You will be using “Explicit assertions” when you want to:

  • Perform some custom logic before making the assertions on the given subject.
  • Perform multiple assertions against the same subject.

Let’s understand the usage of Explicit assertions using the following code snippet:

/// <reference types="Cypress" />
 
describe('Explicit Assertions', () => {
    
  it('expect - Validation using explicit assertion on a specified subject', () => {
    
    //Chai's BDD style assertions for using expect
    expect(true).to.be.true
    const obj = { tools: 'qa' }
    expect(obj).to.equal(obj)
    expect(obj).to.deep.equal({ tools: 'qa' })
  })

  it('expect - matches text of two elements', () => {
    cy.visit("https://demoqa.com/category/widgets/");
    
    const normalizeText = (inputString) => inputString.replace(/s/g, '').toLowerCase()

    let firstText
    let secondText

    cy.get(':nth-child(2) > ul > :nth-child(1)')
      .find('a')
      .then(($first) => {
        firstText = normalizeText($first.text())
      })

      cy.get('.demo-frame > ul > :nth-child(1)')
      .find('a')
      .then(($second) => {
         secondText = normalizeText($second.text())

         expect(secondText, 'second text').to.equal(firstText)
      })
      
      
      
  })

  it('assert - given value is an object', () => {
    const employee = {
      name: 'Lakshay',
      age: 34,
    }

    assert.isObject(employee, 'value is object')
  })
})

When we run the above test, it will show the output as shown below:

In the above code snippet, we have 3 “it” blocks to understand the explicit assertions.

  • In the first test case, we are checking different options on how the “expect” command can work.
  • Secondly, we are visiting “DemoQA“, and are fetching two texts and normalizing it, and we are comparing both the text values to be equal to each other.
  • In the third test case, we are asserting the type of object. So, in this case, we are using the “assert” command to verify whether its an object or not.

When not to assert in Cypress?

Even though Cypress provides multiple assertions, there will be multiple scenarios when the user doesn’t have to invoke any of the implicit or explicit assertions explicitly. The reason for the same is that many of the Cypress commands have in-built assertions or say many of the Cypress commands have requirements that may cause it to fail without needing an explicit assertion. Cypress community names them as “Default Assertions“. Few of the examples of such commands detailed in Cypress documentation are:

  • cy.visit() – expects the page to send text/html content with a 200 status code.
  • cy.request() – expects the remote server to exist and provide a response.
  • cy.contains() – expects the element with content to eventually exist in the DOM.
  • cy.get() – expects the element to exist in the DOM eventually.
  • .find() – also expects the element to exist in the DOM eventually.
  • .type() – expects the element to eventually be in a typeable state.
  • .click() – expects the element to eventually be in an actionable state.
  • .its() – expects to eventually find a property on the current subject.

E.g., If we consider the workflow of the “search articles on the DemoQA website,” many of the actions can be performed even without any assertions, as shown below:

// type definitions for Cypress object "cy"
/// <reference types="cypress" />

describe('My First Cypress Test', function() {
    it('Visits the ToolsQA Demo Page and check the menu items', function() {
    //Visit the Demo QA Website
    cy.visit("https://demoqa.com/");
    
   // Clicking on Widget Menu Item
    
   cy.get('#menu-top > li:nth-child(3) > a').click(); 
})
})

The visit() and get() commands fail automatically if the concerned elements are not found in the DOM, so no explicit invocation of assertion methods is needed.

What are Common Cypress Assertions?

Cypress provides a wide range of assertions which can be very handy during UI automation. Some of the most widely used Cypress assertions are:

  • Length: Validate the number of elements returned by the previously chained command. E.g.:
// Number of articles tiles should be 10
cy.get('.demo-frame > ul > li').should('have.length',19);
  • Class: Validating whether the element does have or doesn’t have the mentioned class. E.g.:
cy.get('form').find('input').should('have.class', 'enabled')
cy.get('form').find('input').should('not.have.class', 'disabled')
  • Value Validate element contains a specific value. E.g.:
cy.get('textarea').should('have.value', 'ToolsQA')
  • Text Content: Validating element to have a specified text. E.g.:
cy.get('a').parent('span').should('contain', 'ToolsQA')
cy.get('a').parent('span').should('not.contain', 'ToolsQA')
  • Visibility: Validating whether the element is visible or not. E.g.:
cy.get('button').should('be.visible')
  • Existence: Validating whether the element exists in the DOM. E.g.:
cy.get('#loader').should('not.exist')
  • State: Validate state for radio or checkboxes. E.g.:
cy.get(':radio').should('be.checked')
  • CSS: Validate CSS characteristics of the element. E.g.:
cy.get('.loader').should('have.css', 'text-highlight')
cy.get('#accordion').should('not.have.css', 'display', 'none')

Key Takeaways

  • Cypress integrates various assertions libraries that can cater to multiple needs of automation test developers.
  • Depending on the specific scenarios, a developer can take a call whether only built-in assertions are sufficient for the test or they need to use the subject-based Implicit or Explicit assertions.

So, we accomplished the task of having a good overview of assertions that Cypress uses. In the next article, we will learn about How Cypress interacts with DOM elements.