Testers and developers often use page objects to interact with their web applications via DOM elements. Let's create a page object for our TodoMVC app:
1 | export const TodoMVC = { |
All tests that add a todo item and check them can use the addTodo
and getTodos
methods
1 | import { TodoMVC } from './todo' |
Note: the should read
assertion comes from my cypress-map plugin.
🎁 The source code for this blog post can be found in the repo bahmutov/todomvc-po-with-assertions.
Data validation
What about data validation? For example, our application stores todo items in the browser's local storage. Let's confirm it.
1 | it('stores todo in the local storage', () => { |
Note: the cy.step
command comes from the cypress-plugin-steps plugin, cy.apply
query is from my cypress-map plugin.
If we want to validate the id of the item, we need to grab the its value and use a regular expression
1 | cy.step('check local storage') |
cy-spok
Just like entering a todo item into the input field, checking the data is a very common operation in E2E tests. Thus it makes sense to create a page object utility method to easily check the data. I can use my cy-spok plugin in the page object to create a function to be used as cy.should(callback)
argument.
1 | // https://github.com/bahmutov/cy-spok |
The spok
is a higher order function, since calling spok({ ... })
returns another function. The property beTodoItem: spok({ ... })
is a method to be used inside cy.should(callback)
. Let's check our local storage
1 | it('adds a new todo (check the data)', () => { |
Checking the server response
Let's say our application receives the todo items from the backend. We could use the same callback property together with cy.intercept
command
1 | it('sends the todos on load', () => { |
Checking HTML structure
Custom data checks inside the page object - how about custom HTML checks inside the page object? Let's say we want to validate all important fields inside the page. We could use a combination of cy.get
and cy.within
and all other HTML assertions:
1 | it('adds a new todo and checks the DOM', () => { |
So we have the header inside the class="todoapp"
element. The header contains the h1
element with the text "todos" and the input element having some certain attributes. Can we check the structure, attributes, and text easier?
Sure - by using the custom HTML assertion should look
from the cypress-map plugin.
1 | export const TodoMVC = { |
The html
property simply lists the "important" elements and their important attributes. It is the small subset of the page, our page must have these HTML nodes. We can use this static string to check the page:
1 | it('checks the DOM using page object', () => { |
Nice!