Cypress Workshop Part 4: Elements, Locators, Assertions
Tags: qa, testing, cypress, automation
Published: 2023-05-19 16:56:21

## DOM Elements

The Document Object Model (DOM) is an essential tool for web interaction, as it creates a virtual representation of a web page loaded in a browser. It serves as a programming interface for HTML and XML documents, allowing web programs to modify the structure, style, and content of the document. The DOM consists of nodes and objects that form the document, enabling programming languages to function on browser pages. Typically, the DOM resides within a browser, while JavaScript serves as the client-scripting language that establishes the necessary connection. JavaScript is responsible for manipulating the DOM in various website operations, such as creating slideshows, validating form submissions, and toggling navigation menus.

To put it simply, any web page you come across is considered a document. Whether you view it as an HTML source or in a browser window, it's essentially a different representation of the same content. The Document Object Model (DOM) allows the webpage to be represented as objects, making it possible to manipulate. By utilizing a scripting language like JavaScript, the document can be modified by targeting these objects.

When examining HTML code, it is crucial to distinguish between various elements, such as tags, attribute names, attribute values, and so on. For instance, let's take the HTML input element structure as an example:


![Example HTML input field element structure and its properties](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ra5fnrg4iyg7qunam9o.png)

The most helpful tool we will be using to find elements is developer tools, elements inspector in the browser. This is an example HTML DOM structure & element inspection tool (in developer tools of the browser, in this case Chrome).


![Chrome developer tools element inspector](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i36d2ozzdpnhl2i5i75c.png)

:information_source: Elements above the key web element are parent elements. 
:information_source: Elements inside the key web element are child elements. 
:information_source: Elements placed at the same level, side by side, are sibling elements to each other.

## Cypress Locators

**What are Cypress Locators?**

A Selector or Locator is an object that finds and returns web page items/elements on a page based on the query. In Automation, to perform any operation on the web elements first, you need to locate an element and perform an action on that element. The Locator or Selector helps to locate an element in the webpage. There are different types of locators, such as id, CSS, XPath, tag-based selectors, etc.

:information_source: Cypress supports various locators such as tags, id, class, attributes, text, etc. Cypress also supports XPath Selectors; however, it needs installation of the third-party plugin cypress-xpath. Xpath has not been supported out of the box in the Cypress framework.

To fetch the HTML element in Cypress using different types of locators `cy.get()` method is used.

**Why do we need Locators?**

We need Locators in order to manipulate elements on the page, to interact with them as a user would manually do. For example: in order to click on a certain element, or type a text, you have to first locate exactly which element that is on the page. 

Giving what we know so far, let’s put this into action. 

1: Create another test file under `/e2e/intro` folder and call it for example `locators.cy.js`. Write the following code in that file. 

```javascript
/// <reference types="Cypress" />

describe('Locators: Get elements by different locator strategies', () => {
  beforeEach('Navigate to test page', () => {
    cy.visit('/automation-practice-form');
  });

  it('Check different locators strategies', () => {
    // By id
    cy.get('#firstName');

    // By tag name
    cy.get('input');

    // By attribute name
    cy.get('[placeholder]');

    // By attribute name and value
    cy.get('[placeholder="First Name"]');

    // By class name
    cy.get('.col-md-3');

    // By class value
    cy.get('[class="mr-sm-2 form-control"]');

    // By tag name and attribute with value
    cy.get('input[placeholder="First Name"]');

    // By different attributes
    cy.get('[placeholder="First Name"][id="firstName"]');

    // By tag name, attribute with value, ID and class name
    cy.get('input[placeholder="First Name"]#firstName.form-control');

    // // Recommended way - unique attribute + value
    // cy.get('[data-test="first_name"]');
  });

  it('Check finding elements by travelling through DOM', () => {
    // Travel through DOM to find Submit button
    cy.get('#firstName').parents('form').find('button').should('contain', 'Submit');
  });
});

```


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wou3bbbubpwqncv21b3l.png)

Code explanation: 

Before each test we will navigate to the page that we want to test, in this case our practice form [link](https://demoqa.com/automation-practice-form). We opened web element inspector in developer tools, as explained in DOM elements section and we tried to locate different elements of our interest.

- In the first test, you can see that we are trying to get elements using different locator strategies using cypress function `get()`. For some of them, elements found will be unique and for some of them you will see that the cypress has found multiple elements by the locator that we have specified. 

It is always the best practice to use UNIQUE locator strategies, such as having a unique attribute for testing (`data-test` for example), or if that doesn’t exist in the app, you can use `id` as the second best locator. Often it happens that elements also don’t have IDs, so then you would try to find attributes with unique values or combination of those. Avoid using classes and tags only, as those elements are not unique. 

- In the second test, you can see one example of how you can travel through DOM to find elements in case that your element doesn’t have any unique value. What we did here is: 

We wanted to find **Submit** button in the form. Let’s pretend that that button doesn’t have any unique element. Next thing we did is - we found one element in the form on the page, that has unique value. We have found its parent - the form, at then inside the form we have found all buttons. Since we need one specific button, we added the assertion that that button should contain text **Submit**. Note that the text displayed on the page and text that is actually in the DOM can be different, and often is, due to CSS formatting. Always use text that you can see in the DOM, exactly how it is written in the DOM. 

2: Let’s run this test in Cypress CLI and see what we will get: 


![first test logs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1xpzw9z3t751f1om0q7m.png)

You can see that some elements are unique and others are not. By selecting them, you can see which are those elements exactly inside the app on the right.


![second test logs](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rdjozyobm50xtsz4cmzv.png)

You can see that we have found the unique submit button by travelling through the DOM.

:star2: Tips: 

You can use element locator inside Cypress CLI tool to find element values. Just click on element selector in the header and pick the element. You can see its value in the header.


![Cypress CLI element selection tool](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zbwcievi9ei7h5w0czet.png)

You can also use developer tools inside Cypress CLI (element selection, app console logs, network logs etc) :

![Development tools inside Cypress CLI](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l0vqec61j5n6ig4ud9cn.png)

:information_source: More about locators: 
[get](https://docs.cypress.io/api/commands/get#Syntax)
[best practices](https://docs.cypress.io/guides/references/best-practices)
[finding html elements](https://www.browserstack.com/guide/find-html-element-using-cypress-locators)
[locators](https://www.toolsqa.com/cypress/cypress-locators/)

## Assertions

Assertions play a crucial role in automated test cases by verifying the success or failure of specific steps. They serve to validate the desired state of elements, objects, or the application being tested. For example, assertions allow you to confirm whether an element is visible, possesses a specific attribute, CSS class, or state. It is highly recommended that all automated test cases include assertion steps. Without them, it becomes impractical to validate whether the application has achieved the expected state. Cypress incorporates assertions from Chai, Sinon, and jQuery libraries, providing a bundled set of assertion capabilities.

**Which are different types of 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_

When the assertion applies to the object provided by the parent chained command, it's 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. 

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.

_Explicit Assertions_

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. 

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 after applying custom logic.

The most commonly used assertions are **Should** and **Expect**. **Assert** is not commonly used in e2e test, but rather in unit testing or component testing. Let’s try to write some code and compare two types that are often used in e2e tests: 

Add new test to `locators.cy.js` file and run the test: 

```javascript
  it('Check different types of assetions', () => {
    // Should assertion
    cy.get('[for="gender-radio-2"]')
      .should('contain', 'Female')
      .and('have.class', 'custom-control-label');

    // Expect assertion
    cy.get('[for="gender-radio-2"]').then((element) => {
      expect(element).to.have.text('Female');
      expect(element).to.have.class('custom-control-label');
    });
  });
```

Code explanation: 

These two assertions are testing the same thing - first they will assert that there is an option to choose gender “Female” (it will search for text) in the form and then they will check if that element has class `custom-control-label`. These are just samples of assertion methods, we will see more of them throughout this workshop. Unless you are dealing with complex JQuery elements and manipulations over them, or API assertions, it is recommended to stick to `.should` syntax.

:information_source: More about cypress assertions: 

[chai](https://docs.cypress.io/guides/references/assertions#Chai)
[cypress assertions in general](https://www.toolsqa.com/cypress/cypress-assertions/)

## HOMEWORK

Write more tests that will try to locate elements on [demoqa](https://demoqa.com/automation-practice-form) page and perform different assertions over those elements (that element is visible, element is not visible, text is visible or not, element contains certain class, check number of found elements on the page (length), etc. 

Don’t forget to push everything you did today on Github :wink: Remember git commands?

`git add .`

`git commit -am "add: locators and assertions tests"
`
`git push`

<img width="100%" style="width:100%" src="https://media.tenor.com/qKeQ5DBbhq0AAAAC/as-i-expect-expected.gif">

YOU’RE DOING AMAZING, SEE YOU IN LESSON 5!

[Completed code for this lesson](https://github.com/ViktorijaFilipov/cypress-workshop/tree/main/LESSON_4)

If you have learned something new, feel free to support my work by buying me a coffee :coffee:

[![Buy Me A Coffee][2]][1]

[1]: https://www.buymeacoffee.com/viktorija3141
[2]: https://cdn.buymeacoffee.com/buttons/default-black.png