How to use Cypress Commands

We are starting to make excellent progress thus far, but we have even more exciting things to learn. Within this lesson, we are going to learn about Cypress commands. Cypress commands are custom commands that we can write ourselves to make portions of our test code re-usable.

Cypress commands are incredibly useful. As your test suite grows, you will find yourself reaching for them more and more to help simplify and re-use portions of your test code.

For our specific use case, let's write a custom Cypress command that will create some default todos for us. This way, we will have a single line of code that will generate some todos in our app each time we use it.

Open the cypress/support/commands.js file and write the following.

Cypress.Commands.add("createDefaultTodos", () => {})

Let's first copy the variables from our test file into this new command.

Cypress.Commands.add("createDefaultTodos", () => {
  const TODO_ITEM_ONE = "Buy Milk"
  const TODO_ITEM_TWO = "Pay Rent"
  const TODO_ITEM_THREE = "Pickup Dry Cleaning"
})

Now let's add the ability to create our todos.

Cypress.Commands.add("createDefaultTodos", () => {
  const TODO_ITEM_ONE = "Buy Milk"
  const TODO_ITEM_TWO = "Pay Rent"
  const TODO_ITEM_THREE = "Pickup Dry Cleaning"

  cy.get(".new-todo")
    .type(`${TODO_ITEM_ONE}{enter}`)
    .type(`${TODO_ITEM_TWO}{enter}`)
    .type(`${TODO_ITEM_THREE}{enter}`)
})

Now let's update our second test to use this new command.

// ...
it("adds three todos", () => {
  cy.createDefaultTodos()
  cy.get(".todo-list li").should("have.length", 3)
})

Great, our tests are still passing and our new command is working perfectly.

Testing the order in which todos are added

Now let's write a simple test to ensure each todo is added in the correct order, which means that each new todo is appended to the bottom of the list.

First we will create a new it() block.

it("should append new items to the bottom of the list", () => {})

Next we can use our new createDefaultTodos() to add some todo's to the app.

it("should append new items to the bottom of the list", () => {
  cy.createDefaultTodos()
})

Now let's make some assertions to make sure each todo is in the correct order.

it("should append new items to the bottom of the list", () => {
  cy.createDefaultTodos()

  // Todo 1
  cy.get(".todo-list li").eq(0).find("label").should("contain", TODO_ITEM_ONE)

  // Todo 2
  cy.get(".todo-list li").eq(1).find("label").should("contain", TODO_ITEM_TWO)

  // Todo 3
  cy.get(".todo-list li").eq(2).find("label").should("contain", TODO_ITEM_THREE)
})

All tests are still passing.

While we are at it, we can also assert that three todos have been added. However, let's do it differently than before.

In our previous tests we are asserting the number of todo's like so:

cy.get(".todo-list li").should("have.length", 3)

This is entirely valid, but there is also another way.

Within the bottom left-hand corner of our app is some text that says "x items left," where x is the current number of todos left to be completed.

Let's assert that this text is displaying the correct message and number of todos.

After finding the element with our dev tools, we can write the assertion like so:

cy.get(".todo-count").contains("3 items left")

So our entire test now looks like this:

it("should append new items to the bottom of the list", () => {
  cy.createDefaultTodos()

  // Todo 1
  cy.get(".todo-list li").eq(0).find("label").should("contain", TODO_ITEM_ONE)

  // Todo 2
  cy.get(".todo-list li").eq(1).find("label").should("contain", TODO_ITEM_TWO)

  // Todo 3
  cy.get(".todo-list li").eq(2).find("label").should("contain", TODO_ITEM_THREE)

  cy.get(".todo-count").contains("3 items left")
})

You will notice that our .todo-count is a <span> with multiple elements nested inside of it. The number is wrapped in a <strong> tag, and the words are wrapped in <span> tags. The cy.contains() method will find the appropriate text even though it may be nested in several different tags.

In the above example, we use both cy.should(), and cy.contains().