In this lesson, weâll learn how to access elements in the page, and interact with them.
Finally, time for our first real test. What shall we test?
Hmm⊠Letâs see. Basic functionality. Letâs test that adding a todo actually adds it to the list.
Letâs see how we build our test, incrementally, Cypress style.
But first, I want to turn off the âwatchâ functionality, to ensure that our tests run only when we ask them to.
Weâll open the file âcypress.jsonâ.
The cypress.json
file is a configuration file that you can use to configure Cypress. Let's add the turning off the watch functionality.
{
âwatchForFileChangesâ: false
}
Okay, we added the configuration to turn off the watch
functionality, now letâs get back to the test.
Letâs get back to the test.
First step: change the test name! Very important.
Weâll change the test name to âshould add a new todo to the listâ.
Second step: we need to âget atâ the element.
Weâll see how we can use the interactive capabilities of Cypress to write the test a whole lot faster.
We need to get at the ânew todoâ element, so we need a selector for that element. And while we can figure it out manually, we can use Cypressâ help.
Letâs run Cypress, as usual:
npx cypress open
Now weâll run the test to completion, and then add what we need.
[Run the test, click on the âselector locatorâ and click on the ânew todoâ]
If we click on this little widget here (I call it the "interactive element locator"), we can point to the element on the screen that we want to get the selector for.
When we click on it, we get not only the selector, but also the command in Cypress that is used to âgetâ the element.
[Click on the âcopy to clipboardâ, and then paste it to the test.]
We pasted the command:
cy.get('.new-todo')
Now letâs run the test.
The test passes!
Notice how we now have two commands on the left of the screen, and even more interesting: hovering over the âGETâ command will show exactly which element that GET [.get
] located. Sweet!
Now, letâs add that todo by typing into the ânew todoâ element.
So, I add a .type()
command immediately after the .get
.
This is called âcommand chainingâ.
cy.get('.new-todo').type('Clean room{enter}')
It chains the type command to the get
command, so that type
will type whatever we want into the element thatget
got.
Note the âcurly braces enterâ [{enter}
] in the String that indicates that Cypress should type an âenterâ, so that the todo will actually be added.
Letâs run the test..
Yup, it runs! And finally, the test is useful.
What we should be doing now is validating that the action we did (creating a todo), actually worked. But weâll leave that to the next lesson, which will be all about validation. In this lesson, weâll concentrate on the actions we can do on the page.
But letâs change the selector a bit â letâs make it fail to see some more Cypress magic.
Letâs change the selector to â.old-todoâ and run the test to see it fail.
We changed the selector to a non-existent selector and ran the test. As we expected, it failed.
But notice that Cypress waited a bit before failing the test.
Why is that? Because Cypress will wait for the element to appear for a bit until it fails. This is part of the reason Cypress is branded as a ânon-flaky test toolâ.
Letâs revert to a working test but add a small delay to the time it takes for the ânew todoâ element appears.
The way we do that is I have this little functionality in the app â ?delay-new-todo=#
â which if I add this parameter to the URL, it will delay the new todo by whatever I want.
Letâs make it 3 seconds (3000 milliseconds), so that itâs within the timeout Cypress has before it fails. (which is, by the way, 4 seconds): ?delay-new-todo=3000
Let's run.
As you can see, the new todo doesn't yet appear until after 3 seconds and boom, the test passes, which makes sense.
Now let's change it to 5000 milliseconds, which is 5 seconds, which is above the Cypress default 4 second time out.
cy.visit('http://todomvc-app-for-testing.surge.sh?delay-new-todo=5000')
Let's run.
As you can see, the test failed in this case, but the test failed because it's above 4 seconds.
But in some cases, this is a true scenario: things take time to appear.
Can we change the timeout?
We can.
Let's go to the .get
and add an option timeout
â you can see that there's documentation on that â cy.get
has a second parameter with options.
cy.get('.new-todo', {timeout: 6000}).type('Clean room{enter}')
This is a regular pattern in the JavaScript world. Some APIs have a last parameter, which is an âoptionsâ parameter, where you pass various options as a JavaScript object. In this case, we pass a timeout of 6 seconds.
Let's run a test and even though there's a delay of 5 seconds, which is above the default of 4 seconds.
The test passes because of the option we added. Yay.
So, cool, we've learned how to get at an element on the page, and we've learned about timeouts and how Cypress waits for elements, let's add some more stuff onto the test.
But first, let's not forget to remove that delay here in the app, we don't really need it anymore. We can keep the timeout, it doesn't bother anything. It's okay.
Let's click on the todo to mark it as completed.
Let's use the selector finder again.
Click on the selector finder and click on this [the completed radio button]. There we have the cy.get
command.
In a real-world test, this selector .toggle
would be a bit naive, but for now, it's good enough.
I pasted the .get command
.
Now let's click on that element. Easy as adding .click
.
cy.get('.toggle').click()
Now let's run the test.
Et voila, it works. The button was clicked and the todo was marked as completed.
Notice in the UI, something remarkable.
Clicking on each command shows us how the page was at the time of the command. It's a history of all the actions and their effect on the page. Wonderfully good for troubleshooting.
So, we've learned how to execute commands on elements and most of the time, you will be using click
, get
, and type
.
We'll see a few more later, but I want to concentrate on another way to access an element, cy.contains
.
Let's add something to the test. Something that clears all todos using âclear completedâ.
Let's run the test again to see that clear completed.
What we want is to click on this element here, âClear completedâ.
So, I go here and I say, instead of cy.get
, I say, cy.contains('Clear completed')
, and I'll click on it.
/// <reference types="cypress" />
it('should add a new todo to the list', () => {
cy.visit('http://todomvc-app-for-testing.surge.sh/')
cy.get('.new-todo', {timeout: 6000}).type('Clean room{enter}')
cy.get('.toggle').click()
cy.contains('Clear completed').click()
})
Let's run the test. There we go.
The test ran and it worked.
We can also, instead of writing clear completed, just write âclearâ
cy.contains('Clear').click()
Let's run the test. There we go, and it worked â cy.contains
doesn't need the whole text. As its name applies, we can give a partial String and it will find it anyway.
That's about it.
We've learned how to access elements using cy.get
and cy.contains
. And we've learned how to interact with those elements using .click
and .type.
But Cypress has a whole slew of functionality around accessing elements and interacting with them and the documentation around them is wonderfully good.
So, before we continue onto the next lesson, which is all about validation, let's tour the documentation a bit and see how we can find out more commands that access elements and interact with them.
Let's go to the documentation. It's Cypress.io and we click here on the right side of the top navigation on âDocsâ.
The docs tab on the Cypress IO website is your entry point. Let's look at ways to interact with elements.
We'll go to âCore conceptsâ and click on Interacting with Elements.
As you can see, we can see all the commands and actionability that interact with elements.
Let's click on .click()
.
As you can see, what we've learned on .click
is only the tip of the iceberg in terms of capabilities.
Feel free to browse and learn about its advanced capabilities later.
Unfortunately, a guide on all the commands that can be used to access elements does not exist in Cypress, but we can go to the full list of commands, clicking on API, and then clicking on âCommandsâ will give us a list of all commands.
So, for example, we can click on get
and see all the things we can do with .get
.
As you can see, just like .click
, what we've learned is just the tip of the iceberg. But don't worry, you don't have to learn it all to start using Cypress.
Start simple and learn your way towards advanced use.
In the next lesson, we'll finally start validating those actions, creating a whole real test that this time actually tests something.