Mendix Test Automation with Cypress
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 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 …
Procedure
- [1] Using Windows Explorer, create a folder called
test
inside your Mendix project folder structure. Open a command line terminal (Powershell) 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
- [4] Click E2E Testing. Accept defaults and click Continue
- [5] Choose the browser of your preference by selecting one of the options and then click on the green button
- [6] Click Create new spec and define a filename
For this particular procedure, the spec name is calc.cy.js
. Click Create spec.
- [7] Click Okay, run the spec.
This will run the default test case and, if everything work as expected, the results will be:
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 nametextBoxValue1
the class selector will start with prefix.mx-name-
, resulting in.mx-name-textBoxValue1
.
In addition to get the textBox element using get
, we also clear the previous contents 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:
- 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:
- 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:
- 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:
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.
- [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:
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.