Mendix Test Automation with Cypress

Vinicius Strugata Ambrosio
6 min readOct 8, 2023

--

In my last two posts here on Medium, I described the procedure for running automated tests on a Mendix Android mobile app with Appium. This time, the focus is on how to achieve the same goal with a web application using Cypress.

Cypress and the Path for Quality — Photo by Kevin Martin Jose on Unsplash

Cypress is a very powerfull and well known E2E — End-to-End — testing automation platform. It works fine with Mendix generated applications, despite the fact some adjustments are needed. Here I describe the procedure I usually follow when doing E2E tests.

Scenario

Once again our scenario is identical to the previous article: a simple application that takes two numbers and calculates their sum. Our mission is to code an E2E testing using Cypress for this humble Mendix project. However, you’ll notice that it is not that easy …

Use case: the correct sum of two numbers

Procedure

  • [1] Create a folder called test inside your Mendix project. Open a Terminal in this folder and type the command below to initialize a node project (where the Cypress code will be)
npm init -y
  • [2] Now install the Cypress dependencies
npm install cypress --save-dev
  • [3] Then, run the Cypress UI
npx cypress open

this will show the Cypress Welcome Screen

Cypress Welcome screen
  • [4] Click E2E Testing. Accept defaults and click Continue
Cypress Configuration
  • [5] Choose the browser of your preference by selecting one of the options and then click on the green button
Cypress browsing selector
  • [6] Click Create new spec and define a filename
Cypress auto generated spec script

For this particular procedure, the spec name is calc.cy.js. Click Create spec.

Defining the spec filename
  • [7] Click Okay, run the spec.
Demo spec contents

This will run the default test case and, if everything work as expected, the results will be:

Cypress launching the test spec
Cypress test result

this proves that Cypress is working properly!

  • [8] Now open a text editor and change the contents of the calc.cy.js to be like below:
describe('Calculator', () => {
it('Should calculate correctly the sum of the given numbers', () => {
// Arrange
cy.visit('http://localhost:8080/')

// Act
cy.get('.mx-name-textBoxValue1').clear().type('5');
cy.get('.mx-name-textBoxValue2').clear().type('2');

cy.get('.mx-name-actionButtonSum').click();

// Assert
cy.get('.mx-name-textResult').should('have.text', 'Result: 7');
})
})

basically the code instructs cypress to navigate to your local application, type some numbers in the text boxes and then get the result by clicking on a button.

  • [9] However, notice the cy.get parameters. These are the Cypress selectors. We must pass the correct selector as parameter. It’s possible to use IDs, Tags and Classes as selectors. From my experience, using Classes as selector is the way to go, since IDs are not fixed and cannot be defined by the developer. More details in this link. For example, for a widget name textBoxValue1 the class selector will start with prefix .mx-name- , resulting in .mx-name-textBoxValue1.
Naming the widget. This name will be used as part of the class definition
Searching for the widget using the class name

In addition to get the textBox element using get, we also clear the previous contests and finally type the number:

cy.get('.mx-name-textBoxValue1').clear().type('5');
cy.get('.mx-name-textBoxValue2').clear().type('2');
  • [10] For the button, we do the same: get the element and click on it programmatically
cy.get('.mx-name-actionButtonSum').click();
  • [11] Finally the assertion is done using a similar approach: get the text element and check its value.
cy.get('.mx-name-textResult').should('have.text', 'Result: 7');
  • [12] When you edit the code, the Cypress test will be executed automatically if you save the changes. So, complete all the changes and then save. You can also click on the hit the R key to run the tests again. The results will be like:
Successful test execution!
  • Everything seems to be perfect. However, let’s suppose you are testing some changes in the Cypress code or even in the Mendix code, and for that you needed to run several times the testing code. At some point, your test will fail with the following message:
ERROR: The current license does not allow more users to sign in.
  • This error occurs when you are running the project locally and using a trial license. In this project, for every test executed, a new anonymous session is automatically created and, when reaches the maximum number allowed (5 sessions).
  • To overcome this limitation we have to options:
    (a) Instead of using an anonymous session, we can login and logout a testing user for every test case. This ensure that only one named session will be used at time.
    (b) Continue to allow anonymous login, but find a way to clear all the previous created sessions before running the test. I decided to use this approach.
  • [13] But how to clear all the previous sessions? A possible way is to create a Microflow that retrieves the sessions delete all of them except the current:
Microflow that deletes the sessions, except the current
  • Another problem: how can we instruct Cypress to run this Microflow? One option is to create a button in the UI that can be clicked by the testing script. Obviously, this option is bad, since adds a new undesired widget in the UI only for this purpose. Better than that is to expose this Microflow as a REST service:
Microflow exposed as a service

ATTENTION! For sake of simplicity, I’ve disabled the authentication. In a real scenario, we can define a special testing user able to call this service.

Swagger showing the exposed service
  • [14] The final missing piece in this solution is instruct the Cypress code to call this service at the beginning of the test case:
cy.request('DELETE', 'http://localhost:8080/rest/appservice/v1/clearSessions');
  • The complete code is as below, for your reference:
describe('Calculator', () => {
it('Should calculate correctly the sum of the given numbers', () => {
// Arrange
cy.visit('http://localhost:8080/')
cy.request('DELETE', 'http://localhost:8080/rest/appservice/v1/clearSessions');

// Act
cy.get('.mx-name-textBoxValue1').clear().type('5');
cy.get('.mx-name-textBoxValue2').clear().type('2');

cy.get('.mx-name-actionButtonSum').click();

// Assert
cy.get('.mx-name-textResult').should('have.text', 'Result: 7');
})
})
  • [15] The finish line of this procedure brings us to result below:
This animation shows the Cypress code executing successfully a use case in a Mendix application

Conclusions

Cypress is an amazing tool for pursuing E2E testing! This article only scratches the surface of possibilities this tool offers. As mentioned in my previous articles, the ultimate goal is to integrate with a CI/CD tool, running all tests at night, so that in the next morning the QA guy can get the testing report and proceed with manual tests if necessary.

Another advantage of a scripting testing tool: it can be used by the developer to quickly reach at a given point of the user flow and continue with some adjustment, such as validations, styling, …

Some of you can argue that E2E tests are expensive. It’s a matter of opinion: for me, there’s no other way to go. Coding expecting that everything will works as expected is naive. It’s by far more expensive to join all developers, QAs, DEVOPs in a war room trying to find like crazy a solution for a problem in the production environment that could potentially be prevented by E2E tests.

--

--