Recently I have decided to solve the Test.Bash 2022 UI Automation challenge . I need to test a small web application running at https://automationintesting.online/ ; it is a message form. A user can submit the form, and then the admin can log in and read the message. The total time to solve it is twenty minutes, so let's go.
Video You can watch the video I submitted to the challenge below
Create a repo and a local project I have created a repository for my tests bahmutov/test-bash-2022-ui . Locally I have created a new folder with Git and NPM package
1 2 3 4 5 6 # "md" is my alias for creating folders# a combination of "mkdir" and "cd" ~/git $ md test-bash-2022-ui ~/git/test-bash-2022-ui $ git init ~/git/test-bash-2022-ui $ git remote add origin [email protected] :bahmutov/test-bash-2022-ui.git ~/git/test-bash-2022-ui $ npm init -y
Let's install Cypress and Prettier, cause I love automatic code formatting .
1 2 3 4 5 # all commands are in the "test-bash-2022-ui" folder $ node -v v16.14.0 $ npm i -D cypress prettier # I copied .prettierrc.json from another project
Open Cypress and scaffold E2E tests
We are going to be testing the application running at "https://automationintesting.online/ ". Let's put this as baseUrl
in our cypress.config.js
file.
cypress.config.js 1 2 3 4 5 6 7 const { defineConfig } = require ('cypress' )module .exports = defineConfig ({ e2e : { baseUrl : 'https://automationintesting.online/' , }, })
Time to write a test
Sending a message If you have never seen a Cypress test, take a look at the Cypress introduction . We visit the base URL, find the message form, and then enter some text into the fields. To make sure we can find our message, I use the Lodash library (bundled with Cypress) to generate a random id to include in the message subject.
cypress/e2e/send.cy.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 it ('sends a message successfully' , () => { const name = 'Test Cy User' const email = '[email protected] ' const phone = '123-456-7890' const subject = `Test Cy message ${Cypress._.random(1e5 )} ` const body = Cypress ._ .repeat ('message body ' , 5 ) cy.visit ('/' ) cy.get ('.row.contact form' ).within (() => { cy.get ('[data-testid="ContactName"]' ).type (name) cy.get ('[data-testid="ContactEmail"]' ).type (email) cy.get ('[data-testid="ContactPhone"]' ).type (phone) cy.get ('[data-testid="ContactSubject"]' ).type (subject) cy.get ('[data-testid="ContactDescription"]' ).type (body) cy.get ('#submitContact' ).click () }) cy.log ('**checking messages**' ) cy.on ('uncaught:exception' , () => false ) cy.visit ('/#/admin' ) cy.get ('[data-testid="username"]' ).type (Cypress .env ('username' )) cy.get ('[data-testid="password"]' ).type (Cypress .env ('password' ), { log : false , }) cy.get ('[data-testid="submit"]' ).click () cy.contains ('.navbar' , 'B&B Booking Management' ) .should ('be.visible' ) .find ('a[href="#/admin/messages"]' ) .click () cy.location ('hash' ).should ('equal' , '#/admin/messages' ) cy.get ('.row.detail' ) .should ('have.length.greaterThan' , 0 ) .contains ('.row' , subject) .should ('have.class' , 'read-false' ) .click () cy.contains ('.message-modal' , subject) .should ('be.visible' ) .and ('include.text' , name) .and ('include.text' , phone) .and ('include.text' , email) .and ('include.text' , subject) .and ('include.text' , body) .contains ('button' , 'Close' ) .click () cy.contains ('.message-modal' , subject).should ('not.exist' ) cy.contains ('.row.detail' , subject) .should ('have.class' , 'read-true' ) .and ('not.have.class' , 'read-false' ) })
The test runs pretty quickly, as you can see in this video
Of course, it is not a problem - we can always hover over the test steps to see how the application's DOM looked at that particular moment.
Tip: the demo application resets itself every 10 minutes. Thus it could potentially reset during the test run, causing the test to fail. To mitigate this, we can turn on Cypress test retries .
1 2 3 it ('sends a message successfully' , { retries : 2 }, () => { ... })
If the test fails, Cypress will mark it "flaky" and retry it up to 2 more times.
In the next blog posts, I will explain how to improve this first test to understand any potential test failures better.
See also