Assert

You can use assertions to check if the tested page's state matches the expected state.

TestCafe provides a comprehensive set of assertions that are based on the Behavior-Driven Development style (BDD-style).

This topic consists of the following sections:

Assertion Structure

To construct assertions, use the test controller's expect method.

The t.expect method is followed by an assertion method that accepts an expected value and optional arguments.

The following example shows the structure of the deep equality assertion:

await t.expect( actual ).eql( expected, message, options );

The code snippet below demonstrates how to use assertions in a test:

import { Selector } from 'testcafe';


fixture `Example page`
   .page `http://devexpress.github.io/testcafe/example/`;


test('Check property of element', async t => {
   const developerNameInput = Selector('#developer-name');

   await t
       .expect(developerNameInput.value).eql('', 'input is empty')
       .typeText(developerNameInput, 'Peter Parker')
       .expect(developerNameInput.value).contains('Peter', 'input contains text "Peter"');
});

The following assertion methods are available:

Smart Assertion Query Mechanism

In synchronous functional testing, you can execute assertions immediately after test actions.

Synchronous Functional Testing

Functional tests are asynchronous on the web. This means that we cannot get the expected changes immediately after a user's actions. For example, it can take time for the tested page to send a request to the server for the required data or a user's action to invoke an animation after which the page reaches its final state. All these intervals cannot be pre-calculated because they depend on various factors: computer performance, network connection speed, etc. In this case, if we perform assertions immediately after the test action, we can get an inconclusive result.

Asynchronous Functional Testing

An additional timeout is usually added when you perform asynchronous functional tests.

Asynchronous Functional Testing with Extra Waiting

To stabilize asynchronous functional tests, you need to add a timeout that allows changes to be applied. Note that adding a timeout can increase the test's duration.

TestCafe uses the smart assertion query mechanism if the assertion receives a Selector's DOM node state property or client function promise as an actual value: if an assertion did not pass, the test does not fail immediately. The assertion retries to pass multiple times, and each time it requests the actual property value. The test fails if the assertion could not complete successfully within a timeout:

TestCafe Smart Assertion Query Mechanism

Example:

The following web page is an example:

<html>
    <body>
        <div id="btn" onclick="window.setTimeout(() => this.innerText = 'Loading...', 100)">Click me!</div>
    </body>
</html>

Test code for this page can be as follows.

test('Button click', async t => {
    const btn = Selector('#btn');

    await t
        .click(btn)
        // A regular assertion fails immediately, but TestCafe retries to run DOM state
        // assertions many times within the timeout until this assertion passes successfully.
        // The default timeout is 3000 ms.
        .expect(btn.textContent).contains('Loading...');
});

The solution described above allows you to create stable tests with improved runtime performance. It also reduces the risk of errors.

You can specify the assertion query timeout in test code with the options.timeout option. To set the timeout when you launch tests, pass the timeout value to the runner.run method if you use API or specify the assertion-timeout option if you run TestCafe from the command line.

Smart Assertion Limitations

The smart assertion's auto-retry mechanism only works with:

The auto-retry feature does not work with DOM Node state properties. If you execute the selector as an asynchronous function, its value is immediately resolved and is not updated. The corresponding test fails as a result.

Example:

<html>
    <body>
        <div id="btn" onclick="window.setTimeout(() => this.innerText = 'Loading...', 100)">Click me!</div>
    </body>
</html>
test('Button click', async t => {
    const btn = Selector('#btn');

    await t
        .click(btn)
        .expect(await btn.textContent).contains('Loading...'); //fails because the selector value does not update according to page behavior

    await t
        .click(btn)
        .expect(btn()).contains({ innerText: 'Loading...'}); //fails because the selector value does not update according to page behavior

    await t
        .click(btn)
        .expect(btn.innerText).eql('Loading...'); //passes because the promise returned from the selector eventually updates
});

Options

options.timeout

Type: Number

The time (in milliseconds) an assertion can take to pass before the test fails if a selector property or client function promise is used.

Default value: The timeout is specified with the runner.run API method or the assertion-timeout command line option.

await t.expect(Selector('#elementId').innerText).eql('text', 'check element text', { timeout: 500 });

In addition to built-in assertions, you also can use assertions from Node.js's assert module or 3rd-party library (for example chai). In this case, specify the time required to complete asynchronous actions with the t.wait(timeout) method.

options.allowUnawaitedPromise

Only promises the selectors and client functions return can be passed as the assertion's actual value. If you pass a regular unawaited promise, TestCafe throws an error.

If you need to assert a regular promise, set the allowUnawaitedPromise option to true.

await t.expect(doSomethingAsync()).ok('check that a promise is returned', { allowUnawaitedPromise: true });