Use custom Cypress command for reusable assertions
We’re duplicating quite a few commands between the registration and login of our user for assertions. Let’s see how we can take these assertions and create a custom command to make the assertions.
We have the tests:
it('should register a new user', () => { cy.createUser().then(user => { cy.visit('/') .getByText(/login/i) .click() .getByLabelText(/username/i) .type(user.username) .getByLabelText(/password/i) .type(user.password) .getByText(/submit/i) .click() // verify the user in localStorage .url() .should('eq', `${Cypress.config().baseUrl}/`) .window() .its('localStorage.token') .should('be.a', 'string') .getByTestId('username-display', {timeout: 500}) .should('have.text', user.username) }) });
We can create some assertions commands to make it more reusable:
Cypress.Commands.add('assertHome', () => { cy.url().should('eq', `${Cypress.config().baseUrl}/`) }) Cypress.Commands.add('assertLoggedInAs', user => { cy .window() .its('localStorage.token') .should('be.a', 'string') .getByTestId('username-display', {timeout: 500}) .should('have.text', user.username) })
Then we can improve the test:
it('should register a new user', () => { cy.createUser().then(user => { cy.visit('/') .getByText(/login/i) .click() .getByLabelText(/username/i) .type(user.username) .getByLabelText(/password/i) .type(user.password) .getByText(/submit/i) .click() .assertHome() .assertLoggedInAs(user); }) });
Run tests as an authenticated user with Cypress
For most applications you’re going to need to be logged in as a user to interact with the application. Let’s see how we can register as a new user and login as that user to test using the application as a logged in user.
Sometime you want to check some DOM element is not present, you cna use queryByTestId()
it('displays the username', () => { cy.createUser().then(user => { cy.visit('/') .getByText(/login/i) .click() .getByLabelText(/username/i) .type(user.username) .getByLabelText(/password/i) .type(user.password) .getByText(/submit/i) .click() .assertLoggedInAs(user) .getByText(/logout/i) .click() .queryByTestId('username-display', {timeout: 300}) .should('not.exist') }) });
Combine custom Cypress commands into a single custom command
Almost every time we need to login, we’ll want to have a newly created user to login as. Let’s go ahead and combine the createNewUser
and login
commands to create a single loginAsNewUser
which we can use in any test that needs an authenticated user.
// support/commands.js Cypress.Commands.add('loginAsNewUser', () => { cy.createUser().then(user => { cy.login(user) }); }); Cypress.Commands.add('login', user => { cy.request({ url: 'http://localhost:3000/login', method: 'POST', body: user, }).then(({body}) => { window.localStorage.setItem('token', body.user.token); return body.user; }) })
// e2e/calcualtor.js describe('authenticated calculator', () => { it('displays the username', () => { cy.loginAsNewUser().then((user) => { cy.visit('/') .getByTestId('username-display') .should('have.text', user.username) .getByText(/logout/i) .click() .queryByTestId('username-display', {timeout: 300}) .should('not.exist') }) }); })
Install React DevTools with Cypress
Because Cypress runs in a real Chrome browser, we can install extensions, like React DevTools. The tricky bit will be to make our application hook up to the extension properly.
react-dev-tools.js
if (window.Cypress) { window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__ }
Import the script before we import the REACT
index.js
import './react-dev-tools' import './global.css' import React from 'react'