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:
- Deep Equal
- Not Deep Equal
- Ok
- Not Ok
- Contains
- Not Contains
- Type of
- Not Type of
- Greater than
- Greater than or Equal to
- Less than
- Less than or Equal to
- Within
- Not Within
- Match
- Not Match
Smart Assertion Query Mechanism #
In synchronous functional testing, you can execute assertions immediately after test actions.
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.
An additional timeout is usually added when you perform asynchronous functional tests.
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:
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:
- Promises returned from ClientFunctions;
- Selector properties;
- RequestLogger.count properties;
- RequestLogger.contains properties.
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 });