TestCafe Tutorial: How To Select Page Elements Using TestCafe Selectors

Bonnie - Dec 23 '22 - - Dev Community

Let’s assume you want to build or create a web page as a web developer. First, you will create an HTML file that comprises semantic and non-semantic elements (e.g. < header >, < section >, and < footer > are examples of semantic elements). < div >, < span >, < h1 >, and < p > are examples of non-semantic elements.

You must style the HTML elements using CSS to ensure the web page is super-responsive on different viewport sizes. The best way to style an HTML element is by targeting it using CSS Selectors.

For instance, you could provide a unique id or class for styling the < header > element. The id and class attributes make it easier to target the < header > element and add styling to it on a CSS file. Therefore, there is a provision to add the id and class attributes by writing HTML code that looks like < header id=”header” > and < header class=”header” >.

What do CSS Selectors have in common with TestCafe Selectors? Before answering that question, let us first understand what is TestCafe and what are TestCafe Selectors in this TestCafe tutorial.

By the end of this TestCafe tutorial on TestCafe Selectors, you will have learned how to use TestCafe Selectors for selecting elements on the web page.

What is TestCafe?

TestCafe is a Node.js-based open-source automation testing framework that can be majorly used for End to End (E2E) testing of web applications. TestCafe supports both JavaScript and TypeScript.

As a web developer and technical writer, I have been working on a portfolio website that helps me showcase my expertise. However, how can I ensure that the website does what I expect it to do when viewed on different browsers and operating systems? This is where I leverage the benefits of end-to-end (E2E) testing.

I can run End to End tests using TestCafe because it does not require any external dependencies like WebDriver (in the case of Selenium). Also, TestCafe uses the browsers I already have on my machine.

At the time of writing this TestCafe tutorial, TestCafe had 9.4K stars and 659 forks, and the latest version was 1.20.1.

What are TestCafe Selectors?

TestCafe Selectors are selectors that filter a web page and return page elements that match specified user-defined criteria. In simple terms, TestCafe Selectors target page elements you want to test, akin to how CSS Selectors target the HTML elements you want to style.

For example, let’s consider a form on a web page with two inputs and a submit button. If you wanted to style the input elements and the button, you would have to target them using CSS Selectors, as you mentioned earlier.

What if you wanted to test whether a user can fill in the form and submit the input data using Testcafe?

TestCafe can identify the form inputs and buttons using TestCafe Selectors (like CSS selectors), as they both take advantage of unique ids or class attributes to locate the elements.

In this TestCafe tutorial on TestCafe Selectors, we will go through different types of TestCafe Selectors and learn how to use them to find page elements that you want to test.

Run TestCafe Tests on the cloud! Try LambdaTest Now!

How to install TestCafe?

In this section of this TestCafe tutorial on how to use TestCafe Selectors to select page elements, you will learn how to install TestCafe and use TestCafe Selectors. To install and use TestCafe in your system, you need an IDE, Node.js, and Node Package Manager (NPM) installed.

I will use Visual Studio Code as the IDE for the demonstration. However, you can use the IDE of your choice.

To install TestCafe on your machine, please follow the steps:

Step 1: Create a folder called “TestCafeSelectors,” then right-click on the folder and open it using Visual Studio Code.

Once the “TestCafeSelectors” folder has opened on VS Code, open the terminal on VS Code by clicking the “Terminal” option on the top of your VS Code window, and then select “New Terminal,” as shown below.

Step 2: Run the command below on your terminal to install TestCafe.

 npm install testcafe
Enter fullscreen mode Exit fullscreen mode

Step 3: Once the installation is done, run the command below to see the version of TestCafe installed.

    testcafe -v
Enter fullscreen mode Exit fullscreen mode

Step 4: Run the command below to create a package.json file.

  npm init
Enter fullscreen mode Exit fullscreen mode

The package.json file represents various metadata relevant to your project. The package.json file also helps NPM identify the project’s information and dependencies.

If you open the package.json file, it should look as shown above. The only thing we now need is to add TestCafe as a dependency for our project.

Step 5: Run the command below to add TestCafe as a dependency to the project.

 npm install testcafe
Enter fullscreen mode Exit fullscreen mode

Now, you find that TestCafe has been added as one of the dependencies.

Before we go through different types of TestCafe Selectors and learn how to use them to target page elements that you want to test, let me talk about the Page Object Model.

Check this out: XCUITest: A Detailed Guide To XCUITest Framework

Understanding Page Object Model

Page Object Model, also known as POM, is a design pattern commonly used by testers when performing automation testing. The primary aim of the Page Object Model is to avoid code duplication and enhance code reusability. The POM design pattern is more programmer-friendly, making it easier to maintain and enhance test code.

As mentioned earlier in this TesCafe tutorial on TestCafe Selectors, test automation frameworks like TestCafe help navigate a web page and perform relevant actions with the WebElements that are targeted using the appropriate TestCafe Selectors.

The Page Object Model houses all the WebElements, actions, and validations happening on a page in one single Page Object. The POM directs us to create an object representing the UI of the page we want to test.

The benefits of using the Page Object Model are more prevalent when testing complex and large-scale applications. Adopting the POM design pattern can be a huge time and cost saver on large-scale applications. The reason is that these applications are only expected to grow larger and more complex with every software release.

Improved maintenance reduces the overhead costs involved in enhancing the test code.

Implementing Page Object Model

As a developer, tester, or SQE, you should habitually implement the Page Object Model in your project.

Let’s look at how the Page Object Model can be implemented in a test case that demonstrates how to choose page elements using TestCafe Selectors.

Step 1: Create a new folder in your project and name it “TestCase” in the path “TestCafeSelectors/TestCase”.

Step 2: In the “TestCafe” folder, create two other folders called “PageModel” and “Tests”.

Step 3: In the “PageModel” folder, create a file called “selectors.js” in the path “TestCafeSelectors/TestCase/PageModel/selectors.js” as shown below.

The next step is to set up the Page Object Model to demonstrate how to use TestCafe Selectors to locate page elements. However, before I show you how to do that, let us assume you have an e-commerce website.

On this e-commerce website, customers have to register or create an account for them to be able to check out items they have added to the cart. Now, how can you ensure that customers can register successfully without any issues?

To ensure that the registration form works as expected, you can use TestCafe to run an automated test where TestCafe simulates the customer interaction with the inputs and buttons on the registration page.

To demonstrate how to use TestCafe Selectors to select page elements, I will be using the LambdaTest e-commerce playground. To set up the Page Object Model for this project, declare the “TestCafeSelectors” class in the “selectors.js” file and export its instance as shown below.

  class TestCafeSelectors {

       constructor() {
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

The next step is to import the Selector function on top of the “selectors.js” file. After that, let us add properties and assign a selector to them inside the constructor.

Check this out: Test On iPhone tester Simulator On Cloud

How to use TestCafe Selectors to select page elements?

Before performing any selector operation, you must find an XPath path to interact with the element. Some ways to get the element path are by ID, className, a unique attribute such as p, div, h1, or creating a custom XPath where you create relations between elements like child, parent, or sibling.

You can now see how TestCafe Selectors are closely related to CSS selectors. Let us now see some TestCafe element selector examples.

Selecting page elements by ID

To learn how to select a page element by ID, navigate to the e-commerce website registration page I mentioned earlier. Inspect the web page and get the ID locator of “First Name” input which the user is expected to fill when registering for an account, as shown below.

The next step is to add the “First Name” ID locator to the Page Object Model. To do this, let us introduce the “firstnameInput” property and assign a selector to it.

To assign a selector to the “firstnameInput,” we must import it at the top of the “selectors.js” file from TestCafe. The “selectors.js” file should now look as shown below.

  import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.firstnameInput = Selector('#input-firstname');
       }
    }

    export default new TestCafeSelectors();

Enter fullscreen mode Exit fullscreen mode

Let’s now create a test case that opens the browser, navigates to the e-commerce website registration page URL, and enters “John” into the “First Name” input field. Note that the test will use the existing directory structure we discussed earlier.

In our project’s “Tests” folder, create a file called “SelectorsTest.js,” as shown below.

In the “SelectorsTest.js” file, at the top, import the page model instance named “TestCafeSelectors” from the “Selectors.js” file in the PageModel folder, as shown below.

    import TestCafeSelectors from “../PageModel/Selectors”;
Enter fullscreen mode Exit fullscreen mode

After adding the page model module, let us create a variable called “pageURL” that will hold the e-commerce website URL, as shown below.

   import TestCafeSelectors from "../PageModel/Selectors";

    const pageURL =   'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'
Enter fullscreen mode Exit fullscreen mode

Next, let us declare a fixture named “Registration Page” as shown below.

    import TestCafeSelectors from "../PageModel/Selectors";

    const pageURL = 'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'

    fixture('Registration Page')
       .page(pageURL)
Enter fullscreen mode Exit fullscreen mode

Note that fixtures are used to divide the list of test cases into categories. They help to manage test cases with different test pages. For example, each fixture can represent tests on the Product Page, Check Out Page, or Home Page.

Let us now create a test named “FirstName,” as shown below.

    import TestCafeSelectors from "../PageModel/Selectors";

    const pageURL = 'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'

    fixture('Registration Page')
       .page(pageURL)

    test("FirstName", async t => {

    });
Enter fullscreen mode Exit fullscreen mode

The test case we declared above is an asynchronous function that contains test code with a test controller object(t). Note that all test actions are implemented as an async function of the test controller t, which is used to access the test run API.

When TestCafe executes a Selector query, it waits for the target element to appear in the DOM. To learn more about it, you can go through this blog on handling waits in Selenium.

To enable TestCafe to wait for the target element to load, let us add the “t.wait” function into our “FirstName” test as shown below:

   import TestCafeSelectors from "../PageModel/Selectors";

    const pageURL = 'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'

    fixture('Registration Page')
       .page(pageURL)

    test("FirstName", async t => {
       await t

    });
Enter fullscreen mode Exit fullscreen mode

Understanding t.wait Function In TestCafe

Wait commands are important for test automation frameworks such as TestCafe and Selenium. Including wait commands in your test code helps the testing framework to wait for a web page to load or an element to appear on the web page. If wait commands are not used, Element Not Found Exceptions might occur.

TestCafe has six types of wait commands or mechanisms. These commands or mechanisms are:

  • Wait Method.

  • Wait Mechanism for Actions.

  • Wait Mechanism for Selectors.

  • Wait Mechanism for Assertions.

  • Wait Mechanism for XHR and Fetch Requests.

  • Wait Mechanism for Redirect.

The t.wait Function is part of the second wait mechanism, which automatically waits for the element to become visible before an action is executed. Note that an element must be interactable before an operation can be performed on it.

TestCafe actions can interact with elements if they satisfy the following conditions:

  • An element is within the < body > element of a page window or an < iframe > window.

  • An element is visible.

  • An element is not overlapped.

TestCafe automatically waits for the target element to become visible when running a test. It tries to evaluate the specified selector multiple times within the timeout. If the element does not appear, the test will fail.

With the “t.wait” function in place, let us now use a method TestController called “typeText.” The TestController takes two parameters; where the first parameter is a selector that identifies the page element in the DOM to receive input focus.

The second parameter is the text we intend to enter in the selected page element, which in our case is “John.” The .typeText syntax looks as shown below.

t.typeText(selector, text)
Enter fullscreen mode Exit fullscreen mode

Since we already declared the Selector in the page model and imported it to our test file, let us add “firstnameInput’, which is the name we gave the selector, as our first parameter in the “.typeText” TestController as shown below in the final code.

    import TestCafeSelectors from "../PageModel/Selectors";

    const pageURL = 'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'

    fixture('Registration Page')
       .page(pageURL)

    test("FirstName", async t => {
       await t
           .typeText(TestCafeSelectors.firstnameInput, 'John')
    });
Enter fullscreen mode Exit fullscreen mode

To make sure that TestCafe is able to select the “First Name” input element and type the name “John,” run the command below on your command line.

    testcafe chrome TestCase/Tests/SelectorsTest.js
Enter fullscreen mode Exit fullscreen mode

Note that the command specifies the browser to use and the file that has the test we want to be performed on the Test Web Page.

TestCafe will launch the Chrome browser, navigate the e-commerce website registration page URL and enter the name “John” into the “First Name” input field.

If there are no errors, you should be notified on the terminal that the test ran successfully, as shown below.

Check this out: Test On Android Emulator Online. Test your web and mobile apps on Android Emulators online.

Selecting page elements by Class Name

In this section of this TestCafe tutorial, we will learn to select page elements by Class Name locator. Let us consider a page on which you want to interact with an element with no ID. What can be done in such cases? The first thing you need to do is to check whether the page element has a class name.

For example, when you inspect the e-commerce website registration page to get ID locators, you will find that the “Continue” submit button has no ID. To enable TestCafe to locate the button, you need to get the submit button class name, then add “input.” before the class instead of “#,” which represents ID locators.

In the test case project, the first step is to add the “Continue” submit button class name locator to the Page Object Model.

To do that, let us introduce the “continueBtn” property and assign a selector to it, as shown below on the “selectors.js” file.

  import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.continueBtn = Selector('input.btn-primary');
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

To test the submit button, let us use a method TestController called “.click,” which performs a click on the page element. The TestController takes one parameter, which is used to identify the page element. To learn more about it, you can refer to this blog on the Selenium click method button.

Once you have imported the page model to your test file, the “SelectorsTest.js” file should now look as shown below in the snippet:

    import TestCafeSelectors from "../PageModel/Selectors";

    const pageURL = 'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'

    fixture('Registration Page')
       .page(pageURL)

    test("SubmitButton", async t => {
       await t
           .click(TestCafeSelectors.continueBtn)
    });

Enter fullscreen mode Exit fullscreen mode

Run the command below, and TestCafe can select the submit button as it was able to select the “First Name” input when locating an element using ID.

    testcafe chrome TestCase/Tests/SelectorsTest.js
Enter fullscreen mode Exit fullscreen mode

Check this out: Exploratory Testing Tutorial: A Comprehensive Guide With Examples and Best Practices

Selecting page elements by Attribute

When selecting a page element by attribute, you use a Selector.withAttribute method, which finds elements with the specified attribute or attribute value. The syntax of the method looks as shown below.

   Selector().withAttribute(attrName [, attrValue]);
Enter fullscreen mode Exit fullscreen mode

Attribute name (attrName) is case-sensitive together with attribute value (attrValue), but attribute value is optional.

Understanding Attribute Name and Attribute Value

Attributes are used to give more meaning to HTML tags, where they define additional characteristics or properties of the page element. Attributes are always specified in the start or opening tag, where they usually consist of attribute name and value pairs such as name=”value.” Note that attribute values should always be enclosed in quotation marks.

In the example below, “for” inside the < label > tag is an attribute name, while “input-firstname” is the attribute value.

<label for=”input-firstname”> </label>
Enter fullscreen mode Exit fullscreen mode

Let us assume that you want to test the “First Name” input element on the e-commerce website page I mentioned earlier, but it has no ID or Class Name locators.

What you can do is check whether the input has any attributes. In this case, the “First Name” input tag has attribute name “name” and attribute value “firstname,” as shown below.

To see if TestCafe can locate the “First Name” input element by attribute, the page model code in the “Selectors.js” file should look as shown below.

    import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.firstnameInput = Selector('input').withAttribute("name", "firstname");
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

Import the Page Object Model to the “SelectorsTest.js” file and the code should look as shown below.

  import TestCafeSelectors from "../PageModel/Selectors";

    const pageURL = 'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'

    fixture('Registration Page')
       .page(pageURL)

    test("FirstName", async t => {
       await t
           .typeText(TestCafeSelectors.firstnameInput, 'John')
    });

Enter fullscreen mode Exit fullscreen mode

Run the command below and see if the test runs successfully.

testcafe chrome TestCase/Tests/SelectorsTest.js
Enter fullscreen mode Exit fullscreen mode

After hitting the enter button to run the command on the command line, you will run into the error below.

The issue is that TestCafe waits for the browser to be ready but times out before the browser is ready. The solution is to increase the value of the “browserInitTimeout” option, which will give enough wait time until the browser is ready.

To give TestCafe more wait time, add “.wait(5000)” to your code in the “SelectorsTest.js” file, as shown below.

   import TestCafeSelectors from "../PageModel/Selectors";

    const pageURL = 'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'

    fixture('Registration Page')
       .page(pageURL)

    test("FirstName", async t => {
       await t
           .typeText(TestCafeSelectors.firstnameInput, 'John')
           .wait(5000)
    });


Enter fullscreen mode Exit fullscreen mode

Run the test command and you should be notified on the terminal that the test ran successfully as shown below.

Selecting page elements by custom XPath

XPath is a technique used to navigate through the HTML structure of a page. It can be used to navigate both HTML and XML documents. XPath provides an option to search for an element within a web page dynamically. You can refer to this XPath cheat sheet to learn more about XPath locators.

To use Custom XPath in TestCafe to select a page element, you must create a custom function and import it into your test file. Let us implement Custom XPath in our project by creating a file named “XPathSelector.js” in the PageModel folder, as shown below.

In the “XPathSelector.js” file, import Selector from TestCafe at the top and create a custom function named “getElementsByXPath.” Then export the function at the bottom. Your code in the “XPathSelector.js” should look as shown below.

  import { Selector } from 'testcafe';

    const getElementsByXPath = Selector(xpath => {
       const iterator = document.evaluate(xpath, document, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
       const items = [];

       let item = iterator.iterateNext();

       while (item) {
           items.push(item);
           item = iterator.iterateNext();
       }

       return items;
    });

    export default function (xpath) {
       return Selector(getElementsByXPath(xpath));
    }

Enter fullscreen mode Exit fullscreen mode

The next step is to import XPathSelector from “XPathSelector.js” at the top of the “Selectors.js” file in the PageModel folder to use the “getElementsByXPath” function.

Let us now use the XPathSelector in the Page Object Model, which targets elements with the custom path “//*[@id=’input-firstname]” as shown below.

Your code in the “Selectors.js” file should look as shown below.

    import { Selector, t } from 'testcafe';
    import XPathSelector from './XPathSelector';

    class TestCafeSelectors {

       constructor() {
           this.firstnameInput = XPathSelector("//*[@id='input-firstname']");
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

Let us now create a test case that uses the Page Object Model in “SelectorsTest.js” file in the Tests folder. In the test, TestCafe opens a browser instance, navigates to the e-commerce website registration page URL, and enters “John” into the “First Name” input selected by custom XPath “//*[@id=’input-firstname]”.

Your code in the “SelectorsTest.js” file should now look as shown below.

    import TestCafeSelectors from "../PageModel/Selectors";

    const pageURL = 'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'

    fixture('Registration Page')
       .page(pageURL)

    test("FirstName", async t => {
       await t
           .typeText(TestCafeSelectors.firstnameInput, 'John')
           .wait(5000)
    });
Enter fullscreen mode Exit fullscreen mode

Run the command below to see if TestCafe is able to locate the “First Name” input element and enter “John”.

    testcafe chrome TestCase/Tests/SelectorsTest.js
Enter fullscreen mode Exit fullscreen mode

If there are no errors, you should be notified on the terminal that the test ran successfully, as shown below.

Check this out: Ad Hoc Testing: A Comprehensive Guide With Examples and Best Practices)

Selecting page elements by relations

Apart from selecting a page element using TestCafe with the methods mentioned above, TestCafe provides other methods to select a page element by relations between elements. Relations between elements include:

  • Parent

  • Child

  • Sibling

Every web page comprises an HTML document referred to as a document tree. Elements in the document tree can be described as a family tree where there are parents, children, and siblings.

A parent is an element directly above and connected to an element in the document tree. A child is directly below and connected to an element in the document tree. A sibling is an element that shares the same parent with another element.

Selector.parent Method

The Selector.parent Method has three types of syntax which are parent(), parent(index) and parent(cssSelector).

The first method syntax looks as shown below, and it returns an array of parent elements, starting with the closest relatives.

  Selector().parent()
Enter fullscreen mode Exit fullscreen mode

Here is how you can use the method in an example that selects all ancestors of all div elements.

   import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.inputClosestParents = Selector('input').parent(0);
       }
    }

    export default new TestCafeSelectors();

Enter fullscreen mode Exit fullscreen mode

Here is how you can use the method in an example that selects all furthest ancestors of all inputs.

   import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.inputFurthestParents = Selector('input').parent(-1);
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

The third method syntax looks as shown below and it looks for parent elements that match the CSS Selector parameter.

  Selector().parent(cssSelector)
Enter fullscreen mode Exit fullscreen mode

Here is how you can use the method in an example that selects all divs that are ancestors of a form element.

   import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.formDivParents = Selector('form').parent(‘div’);
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

Selector.child Method

The Selector.child Method has three types of syntax which are child(), child(n), and child(cssSelector). The first method syntax looks as shown below, and it returns an array of child elements, starting with direct descendants.

    Selector().child()
Enter fullscreen mode Exit fullscreen mode

The method can be used in an example that selects all children of a form element, as shown below.

   import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.formChildren = Selector('form').child();
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

The second method syntax looks as shown below, and it returns an array of n-th closest descendant elements.

  Selector().child(n)
Enter fullscreen mode Exit fullscreen mode

If n is negative, the method returns an array of n-th most distant descendant elements.

The method can be used in an example that selects all the closest children of all div elements, as shown below.

    import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.formChildren = Selector('form').child();
       }
    }

    export default new TestCafeSelectors();

Enter fullscreen mode Exit fullscreen mode

The second method syntax looks as shown below, and it returns an array of n-th closest descendant elements.

    Selector().child(n)
Enter fullscreen mode Exit fullscreen mode

If n is negative, the method returns an array of n-th most distant descendant elements.

The method can be used in an example that selects all the closest children of all div elements, as shown below.

    import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.divClosestChildren = Selector('div').child(0);
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

The method can also be used in an example that selects all furthest children of all div elements as shown below.

   import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.divFurthestChildren = Selector('div').child(-1);
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

The third method syntax looks as shown below and it looks for element descendants that match the CSS Selector argument.


    Selector().child(cssSelector)
Enter fullscreen mode Exit fullscreen mode

The method can be used in an example that selects all input elements that are children of a form element, as shown below.

   import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.formInputChildren = Selector('form').child(‘input’);
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

Selector.sibling Method

The Selector.child Method has three types of syntax which are sibling(), sibling(n), and sibling(cssSelector). The first method syntax looks as shown below, and it returns an array of sibling elements, starting with the closest relatives.

    Selector().sibling()
Enter fullscreen mode Exit fullscreen mode

The method can be used in an example that selects all siblings of all input elements, as shown below.

  import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.inputSiblings = Selector('input').sibling();
       }
    }

    export default new TestCafeSelectors();

Enter fullscreen mode Exit fullscreen mode

The second method syntax looks as shown below and it returns an array of n-th closest sibling nodes.


    Selector().sibling(n)
Enter fullscreen mode Exit fullscreen mode

If n is negative, the method returns an array of n-th most distant descendant sibling nodes.

The method can be used in an example that selects all div elements’ siblings that go first in their parent’s child list as shown below.

   import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.divClosestSiblings = Selector('div').sibling(0);
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

The method can also be used in an example that selects all form elements siblings that go last in their parent’s child lists, as shown below.

    import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.inputFurthestSiblings = Selector('input').sibling(-1);
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

The third method syntax looks as shown below and it looks for element siblings that match the CSS Selector argument.

 Selector().child(cssSelector)
Enter fullscreen mode Exit fullscreen mode

The method can be used in an example that selects all input elements that are succeeding siblings of a form element, as shown below.


    import { Selector, t } from 'testcafe';

    class TestCafeSelectors {

       constructor() {
           this.formInputSibling = Selector('form').sibling(‘input’);
       }
    }

    export default new TestCafeSelectors();
Enter fullscreen mode Exit fullscreen mode

Accessing Shadow DOM

Shadow DOM is a DOM tree with elements and styles isolated from the DOM. Shadow DOM differs from the regular DOM in that the main CSS does not affect the styling.

The Shadow DOM is completely encapsulated, keeping the markup structure, style, and behavior hidden and separate from other codes. The encapsulation is so that different parts do not clash, and the code can be kept nice and clean.

Some examples of shadow DOM are:

  • Embedded forms.

  • Embedded tweets.

  • Embedded YouTube videos.

  • Chat pop-ups.

When testing, you cannot access shadow DOM elements directly. To interact with the shadow DOM in TestCafe, identify the root node of a shadow tree, and use other selector methods to traverse it. You can identify the root node of a shadow tree using Selector.shadowRoot Method.

Selector.shadowRoot Method

This method returns the shadow root node chain to other methods to traverse the shadow DOM. The method returns null if the shadow DOM is not open and its syntax looks as shown below.

 selector.shadowRoot()
Enter fullscreen mode Exit fullscreen mode

The example below shows how to identify the root node, access the shadow tree, and return the < p > element from the shadow DOM.

   import { Selector } from 'testcafe';

    fixture`ShadowDOM`
       .page`https://devexpress.github.io/testcafe/example/`;

    test('ShadowDOM Test', async t => {
       const shadowRoot = Selector('div').withAttribute('id', 'shadow-host').shadowRoot();
       const paragraph = shadowRoot.child('p');

       await t.expect(paragraph.textContent).eql('This paragraph is in the shadow tree');

       try {
           await t.click(shadowRoot);
       }
       catch (error) {
           await t.expect(error.code).eql('E27');
       }
    });
Enter fullscreen mode Exit fullscreen mode

Let’s have a walkthrough of the code above.

Step 1: The selector function is imported from TestCafe to be used in the test code.

Step 2: A fixture called “ShadowDOM” is declared, where it represents a group of tests targeted by one URL.

Step 3: The Test.page method is used to specify the URL of the web page being tested.

Step 4: A test case called “ShadowDOM Test” is declared, where it is an asynchronous function that contains test code with a test controller object (t).

Step 5: A variable called “shadowRoot” is declared where its value is a “selector.shadowRoot method” that selects a “div” with attribute name “id” and attribute value “shadow-host.”

Step 6: A variable called “paragraph” is declared where it calls “shadowRoot” declared in step 5. The variable creates a method called “shadowRoot.child()” that returns an element child “p.”

Step 7: “t.expect.eql method” is used where the method asserts that the actual value is equal to the expected value. “paragraph.textContent” is the actual value while “This paragraph is in the shadow tree” is the expected value.

Step 8: Try statement is used to define a block code to be tested for errors while it is being executed. Also, a catch statement defines a block of code to be executed if an error occurs in the try block.

Note: In this case, the try statement will cause an error if the shadow root is targeted directly or used in assertions.

Check this out: Run Automated Puppeteer Testing Online

Test your Puppeteer test scripts online.

How to find Shadow DOM?

To identify shadow DOM in a web page:

  1. Navigate to the web page and open the devtools as shown below.

2- Click the settings gear in the top-right corner of the devtools window to open settings as shown below.

3- Under the “Elements,” enable the “show user agent shadow DOM” checkbox as shown below.

4- Go back to devtools, and you should be able to identify shadow DOM, as shown below.

Watch this video to learn what Shadow DOM is and how to automate it using Selenium WebDriver.

Check this out: What is Regression testing: Complete Guide With Best Practices

Limitations of TestCafe Selectors

There are three types of TestCafe Selectors. These TestCafe Selectors are:

  • Keyword-Based TestCafe Selectors

  • Function-Based TestCafe Selectors

  • Selector-Based TestCafe Selectors

Keyword-Based TestCafe Selectors filter the page in search of elements that match a CSS selector. Function-Based TestCafe Selectors execute a client-side function that traverses the DOM. Selector-Based TestCafe Selectors execute or filter the results of another Selector query.

These TestCafe Selectors have limitations. These limitations are:

  • Selector queries cannot access user variables outside their scope.

  • Keyword-Based TestCafe Selectors and Selector-Based TestCafe Selectors do not accept custom arguments.

  • Function-Based TestCafe Selectors cannot contain generators or async/await keywords.

Check this out: Regression test: Complete Guide With Best Practices

Running tests using TestCafe on cloud Selenium Grid

As developers, when we create a web app and push it to production, users can access it using different browsers, browser versions, and operating systems. Your task as a developer or tester is to ensure that the web app performs as expected on all these browsers, browser versions, and operating systems.

To test the web app on all these browsers and operating systems, you need an in-house test infrastructure. Unfortunately, running and maintaining an in-house test infrastructure can be quite expensive. Using TestCafe and cloud Selenium Grid can be beneficial because it eliminates the need to invest in the maintenance of the in-house test infrastructure.

Cloud Selenium Grid provides you with an option to run tests on a range of virtual browsers, browser versions, and operating systems securely over the cloud. LambdaTest is one of the top cross browser testing platforms offering cloud Selenium testing, a secure, scalable, and reliable cloud-based Selenium Grid Infrastructure that lets you run tests at scale on an online browser farm of 3000+ browsers and operating systems.

Check this out: Mobile Emulator Online

Test your mobile websites and smartphone apps using our scalable on cloud mobile emulator.

You can follow the LambdaTest YouTube Channel for more such videos around Selenium testing, CI/CD, Cypress UI testing, and more.

To use LambdaTest Selenium Grid together with TestCafe to run your tests, you will need a LambdaTest account.

  1. Navigate to the LambdaTest website and log in if you already have an account, or create one if you don’t have an account yet.

2- Once you are logged in, navigate to the automation page by clicking Automation on the left sidebar of your screen and selecting “Builds”

3- To use TestCafe with LambdaTest Grid, you need LambdaTest credentials (i.e., username and access key). To get the credentials, click the “Access Key” button on the right side of your screen.

4- Let us now save the credentials (username and access key) to environment variables LT_USERNAME and LT_ACCESS_KEY in our project.

5- To save username to environment variable LT_USERNAME and access key to LT_ACCESS_KEY on Linux/Mac, run the following commands.

  $ export LT_USERNAME= insert your username
    $ export LT_ACCESS_KEY= insert your access_key

Enter fullscreen mode Exit fullscreen mode

6- For Windows, run the following commands.

    $ set LT_USERNAME= insert your username
    $ set LT_ACCESS_KEY= insert your access_key
Enter fullscreen mode Exit fullscreen mode

7- To add these credentials to an environment variable in your project, run the following command on the Visual Studio command line.

   nano .bashrc
Enter fullscreen mode Exit fullscreen mode

8- Then add your credentials as shown below.


    $ export LT_USERNAME= insert your username
    $ export LT_ACCESS_KEY= insert your access_key
Enter fullscreen mode Exit fullscreen mode

9- Make sure you save the file by pressing CTRL + X and enter.

10- LambdaTest has an npm plugin that allows you to integrate TestCafe with LambdaTest for seamless cross browser compatibility and true test coverage. You can install the plugin by running the following command:

  npm install testcafe-browser-provider-lambdatest
Enter fullscreen mode Exit fullscreen mode

11- Run the below-mentioned command to look at the browsers supported by the LambdaTest Selenium Grid:

testcafe -b lambdatest 
Enter fullscreen mode Exit fullscreen mode

12- Let us save our TestCafe credentials in our project so that our authentication on LambdaTest Selenium Grid goes through. You can save the credentials by running the commands below.

   $ set LT_USERNAME=*insert your username*
    $ set LT_ACCESS_KEY=*insert your accesskey*
Enter fullscreen mode Exit fullscreen mode

Let’s assume you want to test the “First Name” input element of the e-commerce website registration page we mentioned earlier on a Chrome browser version 85.0 + macOS combination.

  1. To define your desired set of browser and operating system combinations, you can use LambdaTest Capabilities Generator as shown below:

2- After setting your desired combinations, create a file called config.json and add your combinations as shown below without changing the code.

   {
       "Chrome@85.0:MacOS Catalina": {
           "build": "TestCafe Demo",
           "network": true,
           "visual": true,
           "resolution": "1024x768"
       }
    }
Enter fullscreen mode Exit fullscreen mode

3- Navigate to the e-commerce website registration page. Inspect the web page and get the ID locator of “First Name” input which the user is expected to fill when registering for an account, as shown below.

4- The next step is to add the “First Name” ID locator to the Page Object Model. as shown below.

    import { Selector, t } from 'testcafe';

    class TestCafeSelectorsID {

       constructor() {
           this.firstnameInput = Selector('#input-firstname');
       }
    }

    export default new TestCafeSelectorsID();
Enter fullscreen mode Exit fullscreen mode

5- Since we already declared the Selector in the page model and imported it to our test file, let us add “firstnameInput’, which is the name we gave the selector, as our first parameter in the “.typeText” TestController as shown below in the final code.

   import TestCafeSelectorsID from "../PageModel/SelectByID";

    const pageURL = 'https://ecommerce-playground.lambdatest.io/index.php?route=account/register'

    fixture('Registration Page')
       .page(pageURL)

    test("FirstName", async t => {
       await t
           .typeText(TestCafeSelectorsID.firstnameInput, 'John')
    });
Enter fullscreen mode Exit fullscreen mode

6- To run a test on (Chrome 85.0 + MacOS Catalina) combination, run the command below.

    testcafe "lambdatest:Chrome@85.0:MacOS Catalina" TestCase/Tests/SelectByIDTest.js
Enter fullscreen mode Exit fullscreen mode

7- If you visit your LambdaTest Dashboard on the right side of your screen, you should be able to see your recent tests, as shown below.

8- If you click on one of the tests, you will be redirected to the Automation Dashboard, where all the information about the test is available. This information includes a video and a screenshot that shows you how the test went.

If you are a developer or a tester, this certification will acknowledge your expertise in using JavaScript to create automated browser tests. The Selenium JavaScript 101 certification is a globally-recognized certification that proves your expertise and skill in using Selenium with JavaScript.

Conclusion

With this, we have reached the end of this TestCafe tutorial on TestCafe Selectors. As you have seen from the examples used in this TestCafe tutorial, TestCafe Selectors are similar to CSS Selectors in both purpose and syntax. We have learned about TestCafe Selectors and how to use them to select page elements.

We further deep-dived into accessing Shadow DOM and showcased how to perform TestCafe testing on a cloud Selenium grid like LambdaTest.

Happy Testing!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .