Playwright + Cucumber unusual combination. Practical examples of writing automated tests

1. Introduction

Cucumber is not young anymore and probably not the most popular tool for development focused on BDDbut it still has some popularity because it focuses on defining and testing the expected behavior of the system from the users' perspective.

I decided to use a combination of these two tools based on the fact that BDD tests are simple text, in human language, written in the form of a story (scenario) describing some behavior, which means Cucumber is easy to understand for both a novice specialist with little testing experience and for a technically unsavvy person. At the same time, the powerful playwright core provides great opportunities for writing auto tests. The gradation of the framework into parts will allow an experienced specialist to create the basic part of the functions (in this example, on Playwright + TypeScript), and a novice specialist to cover the application with tests using a ready-made base and knowledge (Cucumber, X-path). P.S. perhaps this will become clearer at the end of the article.

Frameworks/tools used:

  • Playwright

  • Cucumber

  • Typescript

  • NodeJS

2. Preparatory work

For practice we will need a simple web application / site. For example, this will be testing the UI part of some signup/registration form.
The optimal option is to run this web application locally.
You can either create a similar page yourself or use the example I created. It is advisable to avoid overloading the article with files, the necessary set of files has been added to the git repository – https://github.com/QaitkenQ/test_signup_form/tree/start_files

Steps to install/configure a web application

  1. Install Node JS.

  2. Create a folder/directory, for example test_server.

  3. Unzip the downloaded files into the created directory or upload the files via console using git.
    The root directory with the web application will look like this: (*readme.md file is optional)

    Web application

    Web application

  4. Open a command prompt and navigate to your working directory, or open the directory with a code editor (such as VSC).

  5. Run the following commands through the terminal.

  6. Start the server with the command

  7. Make sure the server is working by opening the page http://localhost:3000 in the browser.

The site is ready for testing.

3. Installing/Configuring Playwright and Cucumber

  1. Create a root directory for the framework with the following structure (for example Cucuwright):

    Framework structure

    Framework structure

    Folder feature – contains the Cucumber script file.
    Folder src – contains 3 folders with files:
    1. step_definitions – here are files with a detailed description of cucumber steps.
    2. page_objects – here are files describing page elements and actions performed with them.
    3. utils – here is the BaseFunctions file containing basic operations/actions that can be applied to any page.
    File cucumber.js – contains some settings for the Cucumber framework.
    File tsconfig.json – contains TypeScript settings.

    The starter set of files is also available in the repository on another branch https://github.com/QaitkenQ/test_signup_form/tree/cucuwright
    They already have pre-created data to start testing the page with the singup form, which is already running on http://localhost:3000 (For example, the steps file already contains BeforeAll and AfterAll hooks for correctly opening and closing the browser page, the necessary dependencies between the files are already described).

  2. Open a command prompt and navigate to your working directory, or open the directory with a code editor (such as VSC).

  3. Install the Playwright framework by running the command npm init playwright@latest and selecting the necessary options (typescript language, test directory, etc.)

  4. Install the Cucumber framework by running the command npm i @cucumber/cucumber .

  5. Install additional libraries if necessary
    npm install typescript
    npm install ts-node

  6. Created directories tests And test-examples can be deleted.

  7. Check the functionality by running the command npx cucumber-js

The console should display a message that the steps for the current scenario are not defined. File singup_page.feature has one scenario with 2 steps. This means all the tools are installed correctly and the dependencies work.

The result in the console after all preparatory operations have been completed

The result in the console after all preparatory operations have been completed

  1. You can optionally install multiple Cucumber extensions for VSC.
    Cucumber (Gherkin)
    Cucumber Reference Support

4. Writing an auto test

Open the script file signup_page.feature By default, it already has 1 scenario with 2 steps. When creating a new .feature file, create a similar scenario.

singup_page.feature

singup_page.feature

Scenario 1

Step 1 – Opening the page

Let's open the file signup_page_steps.ts and create a basic description for the first step Given SignupPage open page

singup_page_steps.ts

singup_page_steps.ts

Let's open the file signup_page.tslet's add url our page and create a function openPage() to perform the page opening operation.

singup_page.ts

singup_page.ts

All standard operations that can be performed with various elements are placed in a separate file. BaseFunctions.ts in the folder utils.
Function openPage() includes basic function openUrl() and passes the url parameter.

Let's open the file BaseFunctions.ts and create a basic function openUrl()the final action is the method goto().

BaseFunctions.ts

BaseFunctions.ts

To perform this operation, everything could be described in one function. openPage(), but we maintain a structure of division into operations that apply only to this page and operations that can be applied to any other.

Let's check it for functionality step 1 – run the test npx cucumber-js

Console result - Step 1 completed successfully.

Console result – Step 1 completed successfully.

Step 2 – Check the Title

Sign Up Page Title

Sign Up Page Title

Let's go to the file signup_page_steps.ts and create a description for the second step

When SignupPage verify the header "Sign Up page"

Adding step 2 signup_page_steps.ts

Adding step 2 signup_page_steps.ts

In this case, we pass the value (title) as a string {string}. Any changes to the text will only require changing the value in the .feature file.

In the file signup_page.tsadd a locator (X-path, or element attribute) for the title and create a function isHeadingVisible() to perform an element search operation.

Adding step 2 singup_page.ts

Adding step 2 singup_page.ts

Into the basic function findElement() we pass the selector value already with the replaced text from the initial step When SignupPage verify the header “Sign Up page”. By means of .replace meaning %s becomes equal Sign Up page.

Adding findElement() function to file BaseFunctions.ts

BaseFunctions.ts

BaseFunctions.ts

The method chosen for this operation was waitForSelector().

Let's run our test again npx cucumber-js

Result in console - Scenario 1, step 2 completed successfully

Result in console – Scenario 1, step 2 completed successfully

Let's check whether the test is running correctly, whether the required page has actually loaded and whether the test checks the title name – change the value in step 1 “Sign Up page” -> “Sign Up page Fail”

We get an error in the console when performing step 2 – Error: function timed out...

Result - error at step 2.

Result – error at step 2.

It seems true, but I would like to get more information in this case.

Let's rewrite the function findElement() in the file BaseFunctions.ts. Let's add an additional function erifyElementExists()which will output a more detailed description of the error to the console. You can also add a timeout value.

BaseFunction.ts

BaseFunction.ts

Restart the test npx cucumber-js

We get a different result in the console – Error: Can't find the element '//h2[text()='Sign Up page Fail']' within the specified timeout

Result in console - error with details

Result in console – error with details

Now you can immediately check if the locator for the element is correct. It is easy to check by copying this path from the log and pasting it into devtools.

Matches 0.
But if we delete the extra text that we added earlier, it will find the necessary element.

we correct the value – we return the original one in step 1.
Restarting the test – 1 scenario (1 passed), 2 steps (2 passed). We get the desired result.

Scenario 2 – Checking Labels

Step 1 remains the same – opening the page.

Step 2 – Check the element field name

We create a new step in singup_page.feature file. Since there are many similar elements in the form, it is advisable to create a step using a table. Later, when it is completed successfully, we will add the rest of the shortcuts that are in the form. To begin with, we will take the shortcut from the first field First Name

In the file singup_page_steps.ts We describe step 2 taking into account the transfer of values ​​from the table.

In the file singup_page.ts create a function verifyLabels() and add a selector for the label element.

This function uses an existing base function findElement() from BaseFunctions.ts.

Since we now have 2 scenarios, we only launch the second scenario using the @test2 tag. npx cucumber-js --tags=@test2

The test result is passed.

Let's add the rest of the shortcuts that are in the form to the table.

singup_page.feature

singup_page.feature

Restarting scenario 2 npx cucumber-js --tags=@test2

Result – we got an error. The last label from the table “Accept learning the Cucuwright” – cannot be found.

Console result: element search error.

Console result: element search error.

After a little analysis it is clear that the shortcut for the element checkbox has a different structure in the DOM tree. This means that you will have to create a separate step for this element.

Create a new step in the file .feature. Let's create a step with the transfer of table values ​​in case this method is used for a page with several checkbox elements.

singup_page.feature

singup_page.feature

In the file singup_page_steps.ts let's add a step description

In the file singup_page.ts create a function verifyCheckbox() and add a selector for the element checkbox_label. In the selector we used X-path to further specify the element – the element must be of the checkbox type with the required text.

Let's run the test npx cucumber-js --tags=@test2
Result: the script was executed successfully.

Result Scenario 2.

Result Scenario 2.

To double-check, you can perform a quick debug by adding an error to the value (name) of the shortcut – Accept learning the Cucuwright -> Accept learning th Cucuwright
As a result, we will get an error that the checkbox element with the given text cannot be found.

The result is an error in executing the last step.

The result is an error in executing the last step.

Scenario 3 – Validating entered values ​​in an input field

New script and step in file .feature

singup_page.feature

singup_page.feature

In the file singup_page_steps.ts Let's add a description of the step.

singup_page_steps.ts

singup_page_steps.ts

In the file singup_page.ts let's add a locator for the First Name field and create a function enterUserName(). This function will pass data as a string to the base function. enterText().

Let's create a basic function enterText() in the file BaseFunctions.

Let's check the functionality of the test npx cucumber-js --tags=@test3

Result - test completed successfully

Result – test completed successfully

Let's add the following step to scenario #3, checking the value in the input field.
A new step in the fall .feature

singup_page.feature

singup_page.feature

In the file singup_page_steps.ts Let's add a description of the step.

For the sake of example, let's make this step universal and applicable to other input fields. In addition to the main function verifyFieldValue() let's create an additional function determineField() defining the input field. It is also necessary to add locators for the remaining fields from the form in singup_page.ts file.

Depending on the value in the .feature file step, the field to check will be determined and if it is not in the list to check, an error will be displayed.

Next in the file BaseFunctions need to create a function verifyValue().

BaseFunctions.ts

BaseFunctions.ts

Let's run the test again npx cucumber-js --tags=@test3
Result: test completed successfully.

Result

Result

A little debug – let's try to enter an erroneous field name First Name -> Fail Name

singup_page.feature

singup_page.feature

As a result, we will get an error with the description that we added a little earlier.
Unknown field 'Fail Name', please check the name

Result

Result

Scenario 4 – Checking the radio button element

New script and step in file .feature

singup_page.feature

singup_page.feature

File singup_page_steps.ts – step description.

File singup_page.ts – adding a locator radio_btn and creating a function selectRadioButton().

singup_page.ts

singup_page.ts

File BaseFunctions – creating a basic function selectItem().

BaseFunctions.ts

BaseFunctions.ts

Running the test npx cucumber-js --tags=@test4
Result: test completed successfully.

Result

Result

Let's add the next step to check the selected value.

singup_page.feature

singup_page.feature

File singup_page_steps.ts – step description.

File singup_page.ts – creating a function isRadioChecked().

singup_page.ts

singup_page.ts

File BaseFunctions – creating a basic function isChecked().

BaseFunctions.ts

BaseFunctions.ts

Re-running the test npx cucumber-js --tags=@test4
Result: test completed successfully.

Result

Result

To double-check, let's add to the step in the table value the selection of the next element radio button female.

singup_page.feature

singup_page.feature

In this case, the result will be an error indicating that the radio button element male not selected.

Result

Result

Scenario 5 – Checking the dropdown field

New script and step in file .feature

singup_page.feature

singup_page.feature

File singup_page_steps.ts – step description.

File singup_page.ts – creating a function selectDdlValue(). Locator ddList has already been added earlier.

singup_page.ts

singup_page.ts

File BaseFunctions – creating a function selectOption()

BaseFunctions.ts

BaseFunctions.ts

Running the test npx cucumber-js --tags=@test5
Result: test completed successfully.

Result

Result

Add a next step to check the selected value in the drop down list.

New step in file .feature. Since we created a generic step earlier that applies to our dropdown list, we don't need to create anything else.

singup_page.feature

singup_page.feature

Re-running the test npx cucumber-js --tags=@test5
Result: the script was executed successfully.

Result

Result

Scenario 6 – Selecting a checkbox

New script and step in file .feature

singup_page.feature

singup_page.feature

File singup_page_steps.ts – step description.

File singup_page.ts – creating a locator checkbox and functions selectCheckbox().

singup_page.ts

singup_page.ts

Basic function selectItem() had already been created earlier.

Running the test npx cucumber-js --tags=@test6
Result: test completed successfully.

Result

Result

Adding the next step to check if the item was selected.

New script and step in file .feature

singup_page.feature

singup_page.feature

File singup_page_steps.ts – step description.

File singup_page.ts – creating a locator checkbox and functions selectCheckbox().

singup_page.ts

singup_page.ts

Basic function isChecked() had already been created earlier.

Re-running the script npx cucumber-js --tags=@test6
Result: the script was executed successfully.

Result

Result

Scenario 7 – Checking for a validation error.

New script in file .feature. We use the existing steps and create a new step for pressing the button Submit.

singup_page.feature

singup_page.feature

File singup_page_steps.ts – step description.

File singup_page.ts – creating a locator btn and functions clickButton().

singup_page.ts

singup_page.ts

File BaseFunctions – creating a basic function clickBtn().

BaseFunctions.ts

BaseFunctions.ts

Running the test npx cucumber-js --tags=@test7
Result: test completed successfully.

Result

Result

Adding new steps – checking validation error.

singup_page.feature

singup_page.feature

File singup_page_steps.ts – step description.

File singup_page.ts – creating a locator valid_error and functions verifyError(). Just as in the case of checking the value in the input field, this function has an auxiliary function for recognizing the path – which element to look for an error.

singup_page.ts

singup_page.ts

File BaseFunctions – creating a basic function verifyText().

Running the script npx cucumber-js --tags=@test7
Result: test completed successfully.

Result

Result

Let's add a validation error check for the Last Name field – “Required field” to this script.

singup_page.feature

singup_page.feature

Re-running the test npx cucumber-js --tags=@test7
Result: test completed successfully.

Result

Result

Let's change the error text to execute a negative scenario and recheck the created test

singup_page.feature

singup_page.feature

As a result we will get the expected error. Actual result "Please use only alphabetical characters"

Result

Result

Conclusion

As a result, we set up and launched a simple server, installed and configured the framework and wrote several auto tests. At the beginning of the article, I wrote that I would explain how, in my understanding, the connection cucumber + playwright can help a novice specialist write auto tests. When using this structure and working in a team, an experienced specialist can create the main skeleton based on a small part of the application and describe the main operations in the BaseFunctions file. In the case of a large web application and similar parts and using steps with universal methods, it will not be difficult for the second specialist, with less experience in writing auto tests, to cover the rest of the application with tests based on the existing backlog. As a result, these will be created files for other pages with duplication of existing operations and minimal changes. I wanted to show an example of creating tests for another page, but the article has already turned out to be not small and I think it will be superfluous. Also, the simplicity of understanding the written scripts in the .feature file for a technically unsavvy person will be a plus.

This is my first article, please treat with understanding if there are inaccuracies or errors. I will be glad to any criticism. I hope someone will find the article useful. In the future, I plan to create another article with practical tests for DB or API.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *