TestCafe vs Selenium

Ryan Song
7 min readSep 2, 2020

--

A comparison between Selenium(Java) and TestCafe (JavaScript), part one.

Many articles compare Selenium and TestCafe test frameworks, but few of them compare these frameworks’ specific features through task execution. In this article, I will show you how to execute the same task by using Selenium and TestCafe, so that you can tell their differences at a glance and therefore choose a test framework that best suits you. (Spoiler alert: I prefer to use TestCafe over Selenium.)

1. Programing Language

When it comes to selecting a test framework, one of the most common questions is “which language should I use?” Selenium supports different types of programing languages, and the most popular language choices are Java and Python. Java Selenium is very popular for enterprise-level projects and Python Selenium is becoming more popular for small and middle-sized projects. On the contrary, TestCafe is a NodeJS based tool and it supports JavaScript, CoffeeScript, and TypeScript.

The go-to language for web development and browser interaction is JavaScript, not Java. That is to say, when you want to simulate user actions by scrolling to a specific part of a webpage, you will have to use JavaScript. When you choose Java Selenium as the framework to scroll the webpage to (x , y), you will need to use JavascriptExecutor, see code below:

JavascriptExecutor js = (JavascriptExecutor) driver;  
js.executeScript("window.scrollBy(x,y)");

TestCafe, supporting JavaScript, has a built-in mechanism so that it will automatically scroll to the element and execute the action when given the selector of a target (without x & y coordinates). If you want to scroll to a specific location based on x and y coordinates, you can use the ClientFunction and provide the coordinate’s value.

const scrollBy = ClientFunction((x, y) => {    
window.scrollBy(x, y);
});

In brief, Java Selenium and Javascript TestCafe can both get the job done, yet Javascript is more organic when it comes to web browser automation.

2. Selenium Locators vs. TestCafe Selectors

One of the key features for web automation testing is the locator strategy. There are many ways to locate an element on a web page when using Selenium, such as finding the element by id/name/xpath, and etc. TestCafe also has many built-in features and libraries that can be leveraged when trying to locate the element.

Selenium Locators
TestCafe Selector

Finding an element by id , by name and by class name are popular methods in Selenium when locating elements. In Selenium, you will need to provide the id, name or class name attribute values and this method will look for the id, name or class name in the DOM. TestCafe selector uses CSS selectors to locate these attributes. When locating the id attribute, you will need to add a “#” in front of the id attribute value. When locating the class name attribute, you will need to add a “.” in front of the class name attribute value. TestCafe selector does not directly support the find by name method, yet you can use “.withAttribute(‘name’, ‘password’)” method to locate the name attribute in DOM. You will need to provide the attributes such as “name” and value of the attribute “password”. If the element is a link/URL, the best approach is to locate those elements by the link’s text. Selenium will let you locate the element by linkText or partialLinkText. TestCafe selector will let you find the matching text for the link by using “.withExactText()” method. If you want to find by partial of the text, then you can use “.withText()” method and only specify partial of the text. Additionally, since the link will have a href attribute, you can also use the “.withAttribute(‘href’, ‘https://example.com’)” method to locate the link.

Sometimes you do not have any unique attribute to locate the element. In those scenarios, you will need to use css selector, tag names and xpath to locate the element. Selenium has find by cssSelector and tagName methods to locate the element in DOM, and it also has find by xpath method to locate the element through an XML path. TestCafe selector, too, can locate elements by using css selector or tag names and by using XPathSelector to locate the xpath. Additionally, TestCafe can be integrated with other JS libraries, and one of the popular ones is TestCafe Testing Library. TestCafe Testing Library provides additional API supports to locate elements in the web browser, such as locate by placeholder, get by text, query by text and etc.

npm install --save-dev testcafe @testing-library/testcafe
import { screen } from '@testing-library/testcafe'
screen.getByPlaceholderText('Placeholder Text')
screen.getByText('getByText')
screen.getByLabelText('Label For Input Labelled By Id')
screen.queryAllByText('Button Text')

In short, all the Selenium locators can be implemented by using TestCafe selectors; additionally, many JS libraries for testing can be integrated with TestCafe seamlessly.

3. Wait commands

Wait commands are essential in testing frameworks. The time for a web page to load or an element to appear on the page could cause Element Not Found Exceptions. So we will always need to include the wait commands in our code to improve the stability. There are three wait commands in Selenium: Implicit Wait, Explicit Wait and Fluent Wait.

Implicit Wait is to set a fixed wait time for the program. If you want a testing script to pause for 10 seconds, you will do the following.

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Explicit Wait will wait until a condition happened before moving to the next steps. This wait command is widely used in many Selenium frameworks, and it is usually wrapped inside waitTillEelementVisiable method to improve code reusability.

WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(10));
wait.until(ExpectedConditions.visibilityOfElementLocated("Xpath for the element"));

Fluent Wait will set up a max amount of wait time before failing the test case. If you are not sure when the element will be available, you can set the max wait time to 30 seconds and look for the element every 5 seconds.

Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
.withTimeout(30, SECONDS)
.pollingEvery(5, SECONDS)
.ignoring(NoSuchElementException.class);

TestCafe has six different types of wait commands/mechanisms. There are Wait method, Wait Mechanism for Actions, Selectors, Assertions, XHR/Fetch Requests and Redirects.

Wait Method is to pause the tests for a certain amount of time. For example, if the test scenario requires pausing the test for 3 seconds, you can pass the .wait(3000) in the test step.

test('Login test', async t => {     
await t
.typeText(usernameInput, 'username')
.typeText(passwordInput, 'password')
.wait(3000) // // time is in milliseconds
.click(submitButton);
});

Wait Mechanism for Actions will automatically wait for the element to become visible before an action is executed. In the code below, the .typeText action will be executed after usernameInput field becomes visible.

test('Login test', async t => {     
await t
.typeText(usernameInput, 'username')
.typeText(passwordInput, 'password')
.click(submitButton);
});

Wait Mechanism for Selectors will automatically wait for the element to appear in the DOM. TestCafe keeps trying to find the usernameInputElement appears in the DOM until timeout. If you want to ensure the element is also visible on the page, you can pass the optional parameter .with({ visibilityCheck: true }). Thereafter, you will know the element is available in the DOM and visible on the webpage.

const usernameInput = Selector ('#username');
test('Login test', async t => {
const usernameInputElement = await usernameInput.with({ visibilityCheck: true })();
});

Wait Mechanism for Assertions has a built-in smart assertion query mechanism. If an assertion did not pass, the test does not fail immediately. Within a timeout, the assertion retries many times until the assertion could not pass successfully. In the code example, the script will keep trying to obtain usernameInput.value until it equals username.

const usernameInput = Selector ('#username');
test('Login test', async t => {
await t
.expect(usernameInput.exists).ok()
.expect(usernameInput.value).eql('username');
});

Wait Mechanism for XHR and Fetch Requests will wait 3 seconds for XHR/fetch requests to complete before the script executes a test action. The test continues after responses are received or the timeout is exceeded.

Wait Mechanism for Redirect will wait for the server to respond. The test continues if the server does not respond within 15 seconds.

As you can see, many of those Wait Mechanisms depend on the timeout duration in TestCafe. There are two ways to set up the timeout period in test scripts, one way is to pass the timeout period as an optional parameter in each test step:

await t.expect(element.exists).ok('', { timeout: 10000 });

Another way is to configure the settings globally inside .testcaferc.json file.

Selenium’s Implicit Wait, Explicit Wait and Fluent Wait can be implemented by using TestCafe’s Wait Method, Wait Mechanism for Actions and Wait Mechanism for Selector. Meanwhile, TestCafe offers Wait Mechanisms for Assertion, XHR/fetch requests and Redirect, which offer additional support that enhances the stability of a test script. The global configuration file .testcaferc.json helps manage the timeout period synergistically.

  • More comparisons in the next story.

[1]: Code source and examples:

https://www.selenium.dev/documentation/en/

https://devexpress.github.io/testcafe/documentation/getting-started/

--

--