Tutorials Hut

  • Cypress tutorials




  • Custom Commands in Cypress

    Custom commands in Cypress help by providing an easy interface for various repetitive tasks .It allows you to define reusable functionality that can be used across multiple tests.

    They are useful for encapsulating common actions or assertions that you perform frequently in your tests, and can help to reduce code duplication and improve test maintainability.
    Additionally, custom commands can add as Parent, Child, and Dual commands.

    In This article we will cover below topics:

    Custom commands in cypress

    What is custom command in cypress and its syntax

    • Cypress has API’s to create commands based on our requirements and overwrite existing commands. 
    • Cypress custom command is similar to the default commands that cypress provides, except it is user-defined. Cypress custom commands are useful in automating any workflow if you require reusing them over and over in the tests.
    • A great place to define or overwrite commands is in the cypress/support/commands.js file, since it is loaded before any test files are evaluated .

    Syntax for creating a new custom command in Cypress:

    This is to be written in the cypress/support/commands.js file.

    Cypress.Commands.add('login', (username, password) => {
    cy.visit('/login')
    cy.get('#username').type(username)
    cy.get('#password').type(password)
    cy.get('button[type="submit"]').click()
    })
    Cypress.Commands.add(name, callbackFn)
    Cypress.Commands.add(name, options, callbackFn)
    Cypress.Commands.overwrite(name, callbackFn)

    where the arguments are as follows

      • name(String) – The name of the command in string that we want to add or overwrite
      • callbackFn(Function) – This function takes an argument passed to the command
      • options – Pass any options object to define the behavior of the command

    Note: options is only supported for use in Cypress.Commands.add() and not supported for use in Cypress.Commands.overwrite()

    Option Accepts Default Description
    prevSubject Boolean, String or Array false how to handle the previously yielded subject.

    The options that prevSubject accepts are as follows

      • false – ignore previous subjects (parent command)
      • true – accept the previous subjects (child command)
      • optional – pass in whether you want to start a new chain or use an existing chain (dual command)
    command.js_Custom commands in cypress

    Parent custom commands in Cypress

      • Parent commands are commands which  will always begin a new chain of commands.
      • They  ignore previously yielded subjects.
      • Commands such as visit(), get(), request(), etc. are examples of parent commands.

    Example of parent command –

    Cypress.Commands.add('clickLink', (label) = & gt; {
    
    	cy.get('a').contains(label).click()
    
    })
    //clicking the "Book Ticket" link
    cy.clickLink('Book Ticket')
    

    In the above example, ‘clickLink‘ is the name of our custom command. It will search for the label. In line 2, the command gets ‘a‘, and searches for the link which contains the label and clicks the element. cy.clickLink() will execute the action in the test file and click the “Book Ticket” link.

      • If we don’t pass any value for the optional “prevSubject“, the new command will automatically be considered as “Parent command” and can be invoked directly on the “cy” object.
      • These commands can be directly invoked on the cy object.

    Child custom commands in Cypress

    • Child commands are commands which  are always chained off of a parent command, or another child command.
    • These commands are dependent on the subject yielded by the previous command in the command chain
    • Commands such click(), find(), should(),, etc. are examples of child commands.

    Example of child command

        We will look into an example on how to chain a child custom command

    Cypress.Commands.add('forceClick', {
    	prevSubject: 'element'
    }, (subject, options) => {
    	// wrap the existing subject and do something with it
    	cy.wrap(subject).click({
    		force: true
    	})
    })
    
    //Using the forceClick function in the test file
    cy.get("#checkout").forceClick();
    
    Explanation:

      • Custom command name is ‘forceClick‘. 
      • We are passing the prevSubject argument to the element and wrapping the existing subject. 
      • With cy.wrap(), we are force clicking the subject.
      • In the test file, we are accessing the custom command, ‘forceClick‘ on a cy.get() command.

    Dual custom commands in Cypress

    • The dual commands are a kind of hybrid command which lie between the Parent and the Child commands.
    • These can either be called directly on the cy object or can chain with other commands.
    • Dual commands are helpful if we want our command to work in different ways with or without the existing subject.
    • Commands such cy.contains(),cy.screenshot(),cy.scrollTo(),cy.wait(), etc. are examples of child commands.

            Example of Dual command:
    Cypress.Commands.add('getButton', {
    	prevSubject: 'optional'
    }, (subject) => {
    	if (subject) {
    		cy.get(subject).get('btn').its('button');
    	} else {
    		cy.get('btn').its('button');
    	}
    })
    

    Since the prevSubject is optional, we can either pass the subject as an argument or invoke the command without the subject in the test file as below

    cy.getButton() // without the subject
    cy.get('#loginBtn').getButton() // with the subject

    Cypress Custom Commands Example

    • In this example create a custom command and use it in the spec file :
    • Custom commands are added to commands.js file. 
    • In that file, let us add a custom command for a login function
    Cypress.Commands.add("login", (username, password) => {
    	//adding a new command named "login", and arguments passed are username and password
    	cy.get('[id=Uname]').clear();
    	cy.get('[id=Uname]').type(username);
    	cy.get('[id=Pwd]').clear();
    	cy.get('[id=Pwd]').type(password);
    	cy.get('[type=submit]').click();
    });
    
    • Here the custom command name is “login”.
    • It accepts two arguments : username and password. 
    • Steps of clearing the username and password field and entering value in the textfield and then submitting it. 

       In the spec file which has our test case in it block this method can be called using cy.

    describe("Custom Commands Demo", () => {
    	it("Login to the application", () => {
    		cy.visit("https://demo.com");
    		cy.login("demoUser", "Demo@pass");
    		cy.url().should('be.equal', 'https://demo.com')
    	});
    });
    

    Overwriting Existing Cypress Commands

    • We can overwrite the already existing Cypress commands and modify the behavior.
    • It helps avoiding creating another command that will try to use the original command at the end.
    • Some of the original Cypress command that can be overwritten are cy.visit(), cy.type(), cy.screenshot(), cy.contains()

         Example of overwriting the existing Cypress command.

    Cypress.Commands.overwrite('contains',
    	(originalFn, subject, filter, text, options = {}) => {
    		// determine if a filter argument was passed
    		if (typeof text === 'object') {
    			options = text
    			text = filter
    			filter = undefined
    		}
    
    		options.matchCase = false
    
    		return originalFn(subject, filter, text, options)
    	}
    )
    

    As we saw above, we are using the Cypress.Commands.overwrite to modify the existing Cypress command.

    We are naming our custom command as contains and we are passing arguments to determine whether the filter argument has passed.

    Custom commands in Cypress are a powerful tool for improving test organization and maintainability, and can help to make your tests more readable and easier to understand. They can be used to encapsulate any common actions or assertions that you perform frequently in your tests, and can be defined either inline or in external modules.


















  • Leave a Reply

    Your email address will not be published. Required fields are marked *