Creating and Implementing UI Tests with Cypress in Empress

Introduction

In Empress, we prioritize thorough testing to ensure a seamless user experience. One way we accomplish this is through User Interface (UI) testing. This guide delves into UI Testing with Cypress, a powerful NodeJS based full-stack testing framework.

Introduction

Cypress is a front-end testing tool built for modern web applications. It enables developers to write end-to-end tests, integration tests, and unit tests. Unlike Selenium-based tools, Cypress operates directly in the browser, resulting in faster, more reliable tests.

This guide will focus on writing integration tests with Cypress in Empress, including how to run Cypress locally, generate code coverage reports, and utilize Testing-Library queries.

Writing Integration Tests

To write integration tests using Cypress, create a .js file in the cypress/integration directory.

Here’s an example of an integration test to check the insertion of a ToDo:

context('ToDo', () => {
    before(() => {
        cy.login('Administrator', 'admin');
        cy.visit('/desk');
    });

    it('creates a new todo', () => {
        cy.visit('/app/todo/new-todo-1');
        cy.fill_field('description', 'this is a test todo', 'Text Editor').blur();
        cy.get('.page-title').should('contain', 'Not Saved');
        cy.get('.primary-action').click();
        cy.visit('/desk#List/ToDo');
        cy.location('hash').should('eq', '/app/todo');
        cy.get('.list-row').should('contain', 'this is a test todo');
    });
});

Running Cypress Locally

Cypress uses any chromium-based browser installed on your system to run tests. To run the test for an app, use the following command from the frappe-bench directory:

bench --site [sitename] run-ui-tests [app]

This opens the Cypress Electron shell, where you can run any test manually or run all of the tests. You can also run tests in headless mode:

# run in headless mode
bench --site [sitename] run-ui-tests [app] --headless

To enable Cypress parallel testing, pass the --parallel flag:

# run tests parallelly
bench --site [sitename] run-ui-tests [app] --parallel

Code Coverage

Code coverage helps to identify which lines of the source code were executed during the tests. It requires the source code to be instrumented and integrated with our test runner to collect the coverage and generate a report.

In Empress, the .js files are instrumented using Istanbul, and the Cypress code-coverage plugin is used to merge coverage from each test and save the combined result.

Code Instrumentation

Instrumentation inserts additional counters into the code to compute which lines of the source code were executed. The coverage object is generated by incrementing these counters as the code is executed. The Cypress code-coverage plugin then handles the collected coverage and generates coverage reports.

Here’s an example of how code looks before and after instrumentation:

// Before instrumentation
function foo(a, b) {
    if (a < b)
        return b - a;
    else
        return a - b;
}

// After instrumentation
cov_1m1jljnmzu();
function foo(a, b) {
    cov_1m1jljnmzu().f[0]++;
    cov_1m1jljnmzu().s[0]++;

    if (a < b) {
        cov_1m1jljnmzu().b[0][0]++;
        cov_1m1jljnmzu().s[1]++;
        return b - a;
    } else {
        cov_1m1jljnmzu().b[0][1]++;
        cov_1m1jljnmzu().s[2]++;
        return a - b;
    }
}

Generating Code Coverage Report Locally

Follow these steps to generate a local code coverage report:

  1. Instrument the source code using istanbul/nyc:
npx nyc instrument -x 'frappe/public/dist/**' -x 'frappe/public/js/lib/**' -x '**/*.bundle.js' --compact=false --in-place frappe
  1. Run Cypress tests:
bench --site test_site run-ui-tests frappe --with-coverage
  1. Generate the report:
npx nyc report --reporter=text

Testing-Library Queries

You can also use Testing Library queries within your Cypress tests. Testing Library provides testing utilities that:

  • Make it easier to write UI tests that resemble the way users interact with the app.
  • Make it easier to find elements in the DOM without knowing all the implementation details.
  • Help keep the tests maintainable (so minor refactors don’t break tests).

Visit the Testing Library Docs for more details about usage.

Conclusion

Thorough UI testing is vital to maintain the quality of Empress. Cypress offers a powerful platform for writing and executing these tests. By leveraging its features and integrating them with the Testing Library, developers can ensure robust and reliable software solutions.