UI Testing
Frappe Framework supports end-to-end (UI) testing using Cypress, a modern JavaScript testing framework that runs directly in the browser without relying on Selenium. Cypress allows you to automate user interactions, verify application behavior, and test complete workflows from the user’s perspective.
Overview
UI tests are written in JavaScript and executed against a running Frappe application. They can simulate real user actions such as logging in, navigating pages, filling forms, clicking buttons, and verifying results.
Writing UI Tests
Create your Cypress test files inside the following directory of your application:
cypress/integration
Each test file should contain one or more Cypress test cases that verify your application’s user interface.
Example Test
The following example logs into the application, creates a new ToDo record, and verifies that it appears in the list view.
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 Tests
Cypress uses any Chromium-based browser installed on your machine. Run UI tests from the frappe-bench directory.
| Command | Description |
|---|---|
bench --site [sitename] run-ui-tests [app] |
Launches the Cypress interface for interactive testing. |
--headless |
Runs all tests without opening the Cypress interface. |
--parallel |
Executes tests in parallel to reduce execution time. |
Headless Mode
bench --site [sitename] run-ui-tests [app] --headless
Parallel Execution
bench --site [sitename] run-ui-tests [app] --parallel
Running tests in parallel is especially useful in Continuous Integration (CI) environments where multiple machines can execute tests simultaneously.
Code Coverage
Code coverage measures how much of your application’s source code is executed while running tests. Frappe uses Istanbul (nyc) together with the Cypress Code Coverage plugin to generate coverage reports.
How Code Coverage Works
Before running tests, JavaScript source files are instrumented. Instrumentation inserts counters into the code that record which statements, functions, and branches are executed during testing.
After the tests finish, these counters are combined to generate a coverage report showing which parts of the application were exercised.
Generate Coverage Reports
Step 1: Instrument the source code
npx nyc instrument \
-x 'frappe/public/dist/**' \
-x 'frappe/public/js/lib/**' \
-x '**/*.bundle.js' \
--compact=false \
--in-place frappe
Step 2: Run Cypress tests with coverage enabled
bench --site test_site run-ui-tests frappe --with-coverage
Step 3: Generate the coverage report
npx nyc report --reporter=text
You can generate reports in multiple formats depending on your reporting requirements.
Testing Library Queries
Cypress can also be used together with Testing Library, which encourages writing tests that closely resemble real user interactions.
Benefits include:
- More user-focused UI tests.
- Less dependency on implementation details.
- Better long-term maintainability.
- More reliable selectors during UI refactoring.
Common Testing Library Queries
| Query | Purpose |
|---|---|
findByRole() |
Find elements by their accessibility role such as buttons, textboxes, or checkboxes. |
findByLabelText() |
Locate form controls using their visible labels. |
findByPlaceholderText() |
Find input fields using placeholder text. |
findByText() |
Locate elements based on their displayed text. |
findByDisplayValue() |
Find form controls by their current value. |
findByTitle() |
Locate elements using the HTML title attribute. |
findByAltText() |
Find images using their alternative text. |
findByTestId() |
Locate elements using a dedicated testing identifier. |
Best Practice
Write UI tests that simulate real user behavior rather than relying on implementation-specific selectors. Prefer Testing Library queries whenever possible, execute tests in headless mode for CI pipelines, and generate code coverage reports regularly to identify untested areas of your application.