Transcripted Summary

We now have code that does something useful in our application.

But we haven’t really tested that the actions we did really work. We haven’t validated that adding a todo really adds it, that marking it as complete really marks it, and that clearing the completed really does that.

So, this lesson is all about validations — how to check that what should have happened did.

Let’s start by looking at the test.

First, we’ll comment out the last 2 actions, so we can concentrate on validating the first action - adding a todo.

We need to validate that the first todo line includes the “Clean room”.

Let’s first access the element.

Side Note

We’ll use the Selector playground for that, as usual, but it’s going to e the last time I use that just to make things shorter (I know what the selectors are). But last time, for the fun of it. So, we run the test, use the selector playground to access the text. There we go. And copy the cy.get. It's cy.get('label') because it's the only “label” on the page, that should work.

Now that we’ve found the command for the first element, and pasted it, let’s validate that it contains the text “Clean room”:

To validate that it contains the proper text, we use .should().

Actually, all validations use should.

  • The first argument to the should is what to check. And in this case, it’s “have.text”

  • The second argument is the value of what to test. We call this the condition, which in this case is the text to check

And the nice thing about autocomplete in Visual Studio Code and maybe other IDEs, is you get the list, a long, long list of all the conditions available in Cypress. Cool.

If we Ctrl+Space on the String, we can see the list of should conditions, and clicking after and Ctrl+Space will show you documentation on the specific condition.

cy.get('label').should('have.text', 'Clean room')

Let's see it in action. Let's save the test and run it. There we go…

As you can see, it shows how nicely the validations show up — “expected <label> to have text Clean room”. It also shows what is the element here on the right.

Now let's make it fail.

We'll change the text here to “clean vroom”. Okay, let's make the test fail.

Let's run it.

As you can see, it got to the assertion, but it's waiting 4 seconds just in case something changed. Cypress will wait on validations, just like it waits on cy.get and cy.contains.

And look how nicely the error is.

It shows exactly what failed and how it failed in nice and concise English.

(Oh no, I'm starting to sound like a Cypress fan boy).

Anyway, let's return the test to its original working state.

Now we'll add one more validation.

Let's check that the toggle checkbox is initially unchecked.

The element we want is currently the only one with a class “toggle”, so we'll just add cy.get('.toggle').

Now to validate that it is not checked, I add a should as usual and I want it “not to be checked”. There we go.

Yep, not to be checked is exactly what we want.

cy.get('label').should('have.text', 'Clean room')

Let's run the test. There we go.

The assertion passed with flying colors.

Let's continue with some more validations — this time we are going to do it after toggling the mark.

Let's first check that toggling the to do will make it strike through. Here the power of Cypress and the fact that it runs in the browser is apparent.

So, we uncommented the toggling command, to make it toggle the todo. And we’ll access the text, which is in a “label” element. We use cy.get as we saw above.

Now we need to check that it is strike through. How do we do that? We need to check that the css property ‘text-decoration-line’ of the element is ‘line-through’.

cy.get('label').should('have.css', 'text-decoration-line', 'line-through')

As usual, we do it with should, where the condition is have-css.

Because Cypress and your test run in the browser, we have direct access to the CSS properties. We don’t need to run awkward JavaScript to get at it. We just ask whether the property is of the correct value.

Let's run the test and there we go.

It runs and it passes.

Now to the last validation where we check whether clearing all the completed todos will clear the to do list.

But first let's uncomment the clicking on the clear completed. There we go. We uncommented it.

Now let’s access the todo list, which has a class of “todo-list” [cy.get('.todo-list')].

What we want to do is to check whether this element, which is a “ul”, has any “li” elements, because each todo is an “li” element.

Again, because Cypress and our tests have access to the DOM, we can check that the ul has no descendant li-s, using “have.descendants” condition.

If it doesn’t have any, then no todos exist.

# todomvc.spec.js

/// <reference types="cypress" />

it('should add a new todo to the list', () => {
  cy.get('.new-todo', {timeout: 6000}).type('Clean room{enter}')
  cy.get('label').should('have.text', 'Clean room')
  cy.get('label').should('have.css', 'text-decoration-line', 'line-through')
  cy.contains('Clear completed').click()
  cy.get('.todo-list').should('not.have.descendants', 'li')

Let's run it. There we go.

It worked, and passes.

# So, what have we learned?

We learned that Cypress has an extensive list of validations, conditions, which go beyond checking whether something has a text or is checked, and can even check conditions on the DOM or on the CSS properties of an element.

Using those validations, we've created our first complete test, which includes a set of actions and a set of validations that validate those actions. In essence, you've learned all you need to write tests in Cypress. The rest is details and can be found in the documentation.

But we’re not done yet! In the next lesson, where we’ll learn a bit about mocha, which is the test runner that runs the tests.

In the next lesson, we'll learn a little bit about Mocha, which is the test runner that runs the tests.