How to test a UI Designer page using Cypress

dumitru.corini_1385394's picture
dumitru.corini_1385394
Blog Categories: 

How to test a UI Designer page using Cypress

It is not enough to make an UI Designer page - testing it is very important as well. For this reason, our team decided to move towards an e2e framework that is fast to set up and allows us to write tests efficiently. We decided to use Cypress, a open-source, JavaScript framework that lets you write Given-When-Then semi-structured tests.

In this article I will go over an UI Designer page that lets you create a user and two tests that were made for the page. You can find all of these in this GitHub repository. The two tests that I will talk about aren’t the only ones that you will find in the repository, so if you want to see more examples, you can clone the repository and check them out.

Diving into the page structure

Let’s start with the page. It has a form container with multiple fields that will ask for different information in order to create a new user. You can also see some messages that will be displayed in case of errors and success, as well as a loading message. There is also a hidden functionality that makes the success or error messages disappear after three seconds if the user takes any action on the page. We usually use this feature in order to mimic a toast and thus not clog the user's screen.

The test choices

Without further ado, let’s talk about tests. Cypress tests are made from two distinct parts. The first is about writing the test scenarios in one file and the second is about explaining with code what each line of the scenario will do. The cypress-cucumber-preprocessor library is used in order to write scenarios in the Given-When-Then style.

The two tests that I am going to talk about are:

  • A failure in the user creation because the passwords don’t match
  • The loader being displayed while the user is being created

I chose the first because it is a test that we have done and redone multiple times in our pages, but with a little subtlety. In most cases, we are checking that a correct API call is made, with the correct parameters and the correct response. In this case, none of that is necessary because the test for password equality is made client-side. Thus the additional thing that is checked is if no API call is made because none is needed. The second was chosen because it depicts a use-case that seemed pretty interesting to me, and also because the building blocks of the scenario might be useful in a variety of situations - for example, the test for checking if the message disappears after three seconds.

Test that user creation fails because passwords do not match

Let’s talk about the first test scenario.

Given The server is started
And API call response for "user creation should not be called" is mocked
When I visit the index page
And All inputs are filled
And I modify the password field
And I try to create the user
Then I see the message about "Passwords don't match."

The idea for this test is to both verify that there is no API call that is made towards the user API, and also that there is a message saying that passwords don't match. To verify that there is no API call that is made, we can make a route towards the user API without actually creating a response, but only by throwing an error.

cy.route({
    method: "POST",
    url: userAPI,
    onRequest: () => {
        throw new Error("This should have not been called");
    }
});

In order to verify that everything works according to plan, we visit the page.

cy.visit(url);

After that, we fill all inputs with information.

cy.get("input").eq(0).type("walter.bates");
cy.get("input").eq(1).type("bpm");
cy.get("input").eq(2).type("bpm");
cy.get("input").eq(3).type("Walter");
cy.get("input").eq(4).type("Bates");

Followed by modifying the password so it does not match the "confirm password" value.

cy.get("input").eq(1).type("incorrect");

And the last action on the page is to create the user.

cy.contains("button", "Create").click();

After we have setup this specific situation, we want to test that the "passwords don't match" message is present on the page.

cy.contains("p", message).should("be.visible");

After launching the test runner, we can see that the test is executed and is successful.

Test that the loader is displayed while the user is being created

The scenario for this test is based on the display of a loader and checking that it disappears after five seconds.

Given The server is started
And API call response for "user created after delay" is mocked
When I visit the index page
And All inputs are filled
And I try to create the user
Then The loader is shown
When I wait for 5000 delay
Then I see the message about "User successfully created."
And The loader is not shown

As you can see, some parts of this test are the same as in the first test. The main things that are different are the definition of the API mock, checking that the loader is shown, waiting for 5 seconds and checking the end-state of the page. Mocking the API response after 5 seconds gives a moment during which the response has not arrived from the user API, and thus the loading should be shown. The response is the same as the one that you would get from the Portal, which is very close to reality.

cy.fixture("json/userCreatedResponse.json").as("userCreated");
cy.route({
    method: "POST",
    url: userAPI,
    delay: 5000,
    response: "@userCreated"
}).as("userCreatedRoute");

While the user is created, we verify that the loader is shown.

cy.get(".glyphicon.glyphicon-cog.gly-spin").should("be.visible");
cy.contains("p", "Creating user.").should("be.visible");

After which we wait for 5 seconds.

cy.wait(time);

And after 5 seconds, when the response arrives, we check that the message disappears.

cy.get(".glyphicon.glyphicon-cog.gly-spin").should("not.be.visible");
cy.contains("p", "Creating user.").should("not.be.visible");


As you can see, these tests are quick to write and can be very powerful. Awesome! Now you know how to test a UI Designer page with Cypress! You can also check our web-pages project containing pages that we are currently developing.

Comments

Submitted by Pierre-yves Monnet on Tue, 07/28/2020 - 20:05

Hello,
thank you for this post!
In the scenario, you use

cy.get("input").eq(0).type("walter.bates")

How do you know the file "0" is the username? Is that because this is the first input in the page (started top left)? Do you have a better way to identify the field? Because in a form, a new widget may show up before this input (a select box to select a domain for example), and I don't want to rebuild my test if the form change.

Is that possible to identify each field, in order to say "

cy.get("input").eq( USERNAME ).type("walter.bates")

I know there is no ID with the UI Designer, I'm thinking about using different properties, like the CSS properties maybe?

Thank you

Submitted by dumitru.corini_... on Wed, 07/29/2020 - 10:49

The "0" does stand for the first input field. For us, the structure of the page very rarely changes and that is why we decided to keep it generic and not use css classes.

But, you can always use the css classes defined in UI Designer for this if your page is more volatile. To do this, add a css class to the element in UI Designer (for example, add "username" class to first input), and then use the css class in the cy.get (with "username" as a class, it's cy.get(".username input").type("walter.bates")). The only thing to make sure is to select one element with the get if you want to do an action.

Notifications