Thinking about automating your web application and your obvious choice is Selenium. Well, that’s understandable since Selenium is still the most popular test framework. But if you think there aren’t any other testing frameworks out there that are not easier to configure, run and learn you are mistaken. One framework that is currently a hot topic around the automation world is TestCafe, and I’ll explain why by providing brief info on why that framework was created, how to use it, and how to configure it with a real example.

What’s TestCafe and why you should use it?

A free Node.js E2E test framework used for automating web apps compatible with all operating systems. You can write JS or TS-based tests, it’s easy to use, and it has a lot of features that overcome the problems of installing plugins, extensions, or additional configurations like when using Selenium.

You will start to appreciate TestCafe when you learn the following:

  • Quick downloading, installing, configuring, and getting started process
  • No additional browser driver, since it runs within the browser itself
  • No need to add explicit waits since it has an in-built waiting system for UI elements
  • No need for extra plugins or libraries like other frameworks that require to install them
  • Easy parallel test execution setup

The good thing about TestCafe is that it was created from scratch and did not rely on Selenium or any other platform. It combines the browser and Node.js scripts that you can run them against.

Getting Started

A typical installation of TestCafe includes:

  • Make sure you have Node.js installed on your computer
  • Create a project folder and navigate to it
  • Then install it by using the NPM command: npm i -g testcafe
  • Start creating your first .js or .ts file
  • Write test code (TS based):
  • Run the file with testcafe chrome test.ts
  • Done


Let me show you a really simple but effective POM structure example using this framework. Qamind‘s contact page will be used in this example, specifically the subscription to the newsletter functionality.

Creating the project folder

Let’s create our project folder first. I’ll call it TestCafe_Tests. Inside that folder, I’ll create a /src folder where all my test code will be stored. In the root folder, there will also be folders and files like node_modules (npm packages installed), reports folder that is generated after test execution, .gitignore to ignore specific files from GIT, package.json, the runner, and readme file.


In the /src folder the POM structure looks like this:

Assertion folder for verifying actual vs expected, a page-object folder for creating the locators and page object methods per page, and last but not least, the test folder itself where all the tests per page are stored.

Creating the POM structure

The POM is a widely used design pattern in the automation world where all the methods and locators for a page are created in a one-class file. Let’s dive into the example a bit more.


The t which I import is a const of type TestController. This allows us to get access to the test run API and do various actions and verifications. Then I’m creating two methods, the first includes checking that the returned boolean value is true and the second one is verifying that the actual vs expected values are equal. As you can see with this controller, it’s very easy to do assertions. It’s a similar approach to Chai’s assertion library.


Page Objects

First, I’ll create the BasePage where all the elements-related methods will be included. The getElement method accepts the selector as an argument and returns an element that you can later do some actions on. Then I’ll have methods like click(), getText(), enterText(), drag(), etc.


All these methods will be used for different page actions. They accept an element as an argument and they perform various actions like entering text getting text dragging to that specific element, clicking on that element, etc. You can notice that I didn’t use any explicit waits as we need to when using Selenium for example. TestCafe takes care of that in the background.

Now, the Contact Page will include all the elements that we need for this test.


We extend from BasePage to get access to the generic element-related methods from the BasePage and then we create private properties which will be the UI elements we do actions on. In the constructor, we initialize them with a selector value.

Then, the method called submitContactForm() where accepts 6 arguments, and the input is controlled directly from the test itself. Since it is a subscription form there are many elements to be populated, selected, or clicked. Populating first name, last name, email, and description, and choosing gender, age and hobbies are all actions performed by this method against the elements. As a result, a success message appears after a successful subscription which we’ll fetch and store in a variable for later assertion.


Before every test, we need to specify the fixture to which all the tests will belong. With the fixture keyword, we define the root URL to navigate as well as any before or after hooks that need to be executed. The test itself is just an async function that executes whatever we put inside. In this case:


We are importing the Contact Page so that we get access to that method, we pass the specific arguments and we store the message in a variable. In the assertion part, we check that the successful message is equal to the one we’ve provided. Done!

Now the test runner part.

Creating the runner

This is the part where I love about TestCafe. Defining the runner with all the configurations in one place is really straightforward. Just a main function that includes deleting the reports folder before each execution so that we have a fresh report every single time and creating the testcafe module.

In the try-catch block, we create the runner and every single configuration is chained to each other which makes it very readable and flexible.

  • Source files e.g. the test files to be executed
  • Which browser should be used
  • Which type of reporter should be created
  • Screenshots of the execution, their full path, name, and when to be created
  • Videos of the test execution
  • And the Run configs where you can specify selector, assertion and page timeouts, speed of execution
  • And finally, closing the runner and browser

Run the tests

I created an npm script in the package.json where I run the runner.


Let’s run the test and check the results.

Check the results

As you can see from the screenshot below, the test passed. Chrome and Windows versions are also shown in the console report.


Latest Posts