Edge Cases and Limitations

This topic contains information about edge cases of using selectors and selectors API limitations.

Calling Selectors from Node.js Callbacks

Selectors need access to the test controller to be executed. When called right from the test function, they implicitly obtain the test controller.

However, if you need to call a selector from a Node.js callback that fires during the test run, you have to manually bind it to the test controller.

Use the boundTestRun option for this.

import { http } from 'http';
import { Selector } from 'testcafe';

fixture `My fixture`
    .page `http://www.example.com/`;

const elementWithId = Selector(id => document.getElementById(id));

test('Title changed', async t => {
    const boundSelector = elementWithId.with({ boundTestRun: t });

    // Performs an HTTP request that changes the article title on the page.
    // Resolves to a value indicating whether the title has been changed.
    const match = await new Promise(resolve => {
        const req = http.request(/* request options */, res => {
            if(res.statusCode === 200) {
                boundSelector('article-title').then(titleEl => {
                    resolve(titleEl.textContent === 'New title');


    await t.expect(match).ok();

This approach only works for Node.js callbacks that fire during the test run. To ensure that the test function does not finish before the callback is executed, suspend the test until the callback fires. You can do this by introducing a promise and synchronously waiting for it to complete as shown in the example above.


  • You cannot use generators or async/await syntax within selectors.

  • Selectors cannot access variables defined in the outer scope in test code. However, you can use arguments to pass data inside the selectors, except for those that are self-invoked. They cannot take any parameters from the outside.

    Likewise, the return value is the only way to obtain data from selectors.