Selector.addCustomDOMProperties Method
Adds custom properties to the Selector object.
Use the addCustomDOMProperties method to retrieve DOM element properties not included in the standard Selector API.
Selector().addCustomDOMProperties({
    property1: fn1,
    property2: fn2,
    /* ... */
}) → Selector
| Parameter | Type | Description | 
|---|---|---|
property1, property2, … | 
String | Property name | 
fn1, fn2, … | 
Function | Client-side function that calculates the property value. | 
Functions that calculate property values (fn1, fn2, …) accept the following parameter:
| Parameter | Type | Description | 
|---|---|---|
node | 
Object | The DOM node. | 
Example
import { Selector } from 'testcafe';
fixture`Selector.addCustomDOMProperties`
    .page`https://devexpress.github.io/testcafe/example/`;
test('Check Label HTML', async t => {
    const label = Selector('label').addCustomDOMProperties({
        innerHTML: el => el.innerHTML,
    });
    await t.expect(label.innerHTML).contains('input type="checkbox" name="remote"');
});
If you use TypeScript, extend the Selector interface with your custom properties:
interface CustomSelector extends Selector {
    innerHTML: Promise<any>;
}
interface CustomSnapshot extends NodeSnapshot {
    innerHTML: string;
}
// via selector property
const label = <CustomSelector>Selector('label').addCustomDOMProperties({
    innerHTML: el => el.innerHTML
});
await t.expect(label.innerHTML).contains('input type="checkbox" name="remote"');
// via element snapshot
const labelSnapshot = <CustomSnapshot>await label();
await t.expect(labelSnapshot.innerHTML).contains('input type="checkbox" name="remote"');
Propagation
TestCafe propagates all custom properties and methods down every selector chain.
import { Selector } from 'testcafe';
fixture`Selector.addCustomDOMProperties propagation`
    .page`https://devexpress.github.io/testcafe/example/`;
test('Propagate custom properties', async t => {
    const div = Selector('div').addCustomDOMProperties({
        innerHTML: el => el.innerHTML,
    });
    await t
        .expect(div.innerHTML).contains('<header>')
        .expect(div.nth(2).innerHTML).contains('<fieldset>')
        .expect(div.withText('Submit').innerHTML).contains('<button');
});
Additions to your Selector chain change the target of your custom method. You may unwittingly request a property that does not exist on the client. Make sure your code does not fail due to propagation:
import { Selector } from 'testcafe';
fixture`Selector.addCustomDOMProperties propagation in the chain`
    .page`https://devexpress.github.io/testcafe/example/`;
test('Check Label HTML', async t => {
    const fieldSet = Selector('fieldset')
        .addCustomDOMProperties({
            legend: el => el.querySelector('legend').innerText,
        })
        .addCustomMethods({
            getLabel: (el, idx) => {
                return el[0].elements[idx].labels[0];
            },
        }, {
            returnDOMNodes: true,
        });
    // This assertion passes.
    await t.expect(fieldSet.nth(1).legend).eql('Which features are important to you:');
    // This line throws an error.
    try {
        await t.expect(fieldSet.nth(1).getLabel(3).textContent)
            .eql('Easy embedding into a Continuous integration system');
    }
    catch (err) {
        await t.expect(err.errMsg).eql('TypeError: Cannot read properties of null (reading \'innerText\')');
    }
    // When TestCafe evaluates "getLabel(3)", it also tries to propagate
    // the "legend" property to the result. So, it queries for a
    // <legend> inside the <label> element, which returns nothing.
});