Discussion

Pegasystems Inc.
PL
Last activity: 20 May 2025 4:26 EDT
Writing e2e and feature tests with Playwright and Cucumber
This article is part of Testing Pega applications series.
Introduction
In previous articles we highlighted the setup of the project, and we demonstrated how to run tests. Below following this article make sure you are familiar with the previous article available here: https://support.pega.com/discussion/running-e2e-and-feature-tests-playwright-and-cucumber. In this article we explore how C11N Testing Starter Pack works in detail and how you can take advantage of it to build your own testing solution.
Understanding how it works
Having our tests up and running; it is now time to understand how it works so that we can tailor it to our needs. The goal for this code was to make it modularized and reusable so it can be easily used in other projects. Code is split into several logical modules and modules on top reusing logic from bottom layers.
- Code inside Library components layer serves as the foundation. It is the reusable code that is utilized by code in upper layers. Test Data layer is logic handling seed data so we can run tests with different sets of data.
- Configuration layer sets the scene for tools we use, Playwright and Cucumber. It consists also .env file that sets our environment variables.
- Test definition layer is where logic for our test is defined. This layer reuse logic from layers below implementing DRY rule (do not repeat yourself).
One potential extension to be implemented is to create some way to execute those tests. Currently tests can only be run by a developer who has the setup done on a local machine. Potential improvement is:
- Create CLI tool the simplifies test running
- Spinning up web server so it is possible to trigger test via REST call.
Both the solutions would enhance the ability to interact with tests by users as well it would give ability to include those tests on CI/CD pipelines.
Test structure
Modular approach is also employed in way how tests are written. As I reminder we use Playwright for e2e UI testing and Cucumber for feature testing. Those tests require:
- low level API functions, so we do not repeat ourselves. Example: fill Input
Note: snippet above find element on screen using data-testid attribute that you need to set for each control in a View configuration.
Those functions are defined in https://github.com/kamiljaneczek/c11n-testing/blob/main/lib/playwright/controls.ts and are fully reusable in all Constellation based projects.
- Fixtures – code that supports test execution, specific to Constellation, that hide some complexity: https://github.com/kamiljaneczek/c11n-testing/blob/main/lib/playwright/fixtures.ts
- Test data to be prepared.
When running e2e we always start from the beginning of the process, data that we will use in testing the business process is defined in JSON file. Here is an example for testing Incident type
In our case we don’t require much data prepared upfront, files consist of data that simulates user input.
The situation is different with feature testing with Cucumber. Feature testing with cucumber works differently than Playwright. The features we aim to test may be available only at a particular stage of the case. Hence before starting test a case should be prepared. We have two options:
- Use e2e testing to prepare such data – but this solution is slow.
- Use DX API – this is what we use. While Playwright is not a tool for API testing, we can use it to test REST API. This method is preferred and used in this example.
You can find specific functions to submit each assignment on Incident case in this file - https://github.com/kamiljaneczek/c11n-testing/blob/main/lib/playwright/api/incident.ts .
Also, in e2e folder: https://github.com/kamiljaneczek/c11n-testing/blob/main/e2e/api/prod-inc-api.spec.ts there is full e2e test of Incident case via DX API.
API testing
Small disclaimer about API testing. While we can test API using Playwright to test DX API here are couple of important notes:
- We should not be testing DX APIs as these are managed by Pega engineering team.
- We can test case processing via API to test some parts of backend logic, but this is different from e2e UI testing. E2E UI testing concentrates on what users see and how they interact with system which is different to invoking DX API endpoints directly.
- We might use DX API and API testing to perform a kind of Unit test for Views. Payload returned as DX API response consist of full UI metadata (what elements get displayed on screen). We might write test to check if field is set as mandatory, disabled etc.
Additionally, one more benefit of having API tests in places is the ability to quickly create test data at scale so we can use it for other purposes:
- manual testing
- Load and performance testing
Recording e2e tests
Playwright comes with the ability to generate tests out of the box and is a great way to quickly get started with testing. It will open two windows, a browser window where you interact with the website you wish to test and the Playwright Inspector window where you can record your tests, copy the tests, clear your tests as well as change the language of your tests.
Use the codegen command to run the test generator followed by the URL of the website you want to generate tests for.
pnpm playwright codegen <application_url>
Writing feature tests with Cucumber
Defining a Feature File
Cucumber feature files describe test scenarios in plain English. Create a new file under features/:
Implementing Step Definitions
Map each step in /step-definitions/incident.ts file:
Understanding the Playwright Test Code
This test simulates a user logging into an application, creating an incident, and verifying that the incident was successfully created.
Code Structure Breakdown
import { Given, When, Then } from '@cucumber/cucumber'; import { test, expect } from '@playwright/test';
Imports Explanation:
- The first line imports Cucumber's BDD syntax components (Given, When, Then) which provide a human-readable structure for your tests
- The second line imports Playwright's test and expect functions, which provide browser automation and assertion capabilities
Step 1: User Authentication
Given('I am logged in as a case worker', async () => { await page.goto('https://your-app-url'); await page.fill('#username', 'caseworker'); await page.fill('#password', 'password123'); await page.click('#login'); });
What's Happening:
- The Given step establishes the precondition - a logged-in case worker
- page.goto() navigates to the application URL
- page.fill() uses CSS selectors to locate the username and password fields and enters credentials
- page.click() submits the login form by clicking the login button
- The async/await pattern ensures each action completes before moving to the next one
Locator Details:
- The code uses CSS ID selectors (#username, #password, #login) to identify elements
- According to Playwright best practices, these could be improved by using more resilient locators like getByRole() or getByLabel() for better maintainability
Step 2: Creating an Incident
When('I create a new incident', async () => { await page.click('#create-incident'); await page.fill('#incident-title', 'Test Incident'); await page.click('#submit'); });
What's Happening:
- The When step describes the main action being tested - creating a new incident
- page.click('#create-incident') clicks on the button to initiate incident creation
- page.fill('#incident-title', 'Test Incident') enters a title for the incident
- page.click('#submit') submits the incident creation form
Automation Flow:
- Playwright automatically waits for elements to be available before interacting with them
- Each action is performed sequentially, mimicking a real user's behavior
Step 3: Verification
Then('the incident should be successfully created', async () => { const confirmationMessage = await page.textContent('#confirmation'); expect(confirmationMessage).toContain('Incident Created'); });
What's Happening:
- The Then step verifies the expected outcome - successful incident creation
- page.textContent('#confirmation') retrieves the text from the confirmation message element
- expect(confirmationMessage).toContain('Incident Created') asserts that the message contains the expected text
Conclusion
This guide provides a foundation for testing Constellation applications using Playwright and Cucumber. By following best practices and leveraging the provided starter pack, teams can ensure robust test coverage and maintain high-quality applications. Future articles will explore Selenium-based testing and advanced strategies for testing SDK-based applications and CI/CD integration.