Implementation:DevExpress Testcafe Assertion API
| Knowledge Sources | |
|---|---|
| Domains | Testing, Web_Automation |
| Last Updated | 2026-02-12 04:00 GMT |
Overview
Concrete implementation of smart assertions in TestCafe through the `Assertion` class, providing chainable assertion methods with automatic retry logic for dynamic values.
Description
The `Assertion` class is created by calling `t.expect(actual)` and provides methods for various assertion types. Each method accepts an expected value, optional custom message, and optional configuration (timeout, allowUnawaitedPromise). The assertion is enqueued as a command in the TestController's action queue and executed with retry logic when the actual value is re-executable (like Selector properties).
Usage
Call `t.expect(actual)` to create an assertion, then chain an assertion method. Use Selector properties as actual values to enable smart retry. Provide custom messages for clearer test output.
Code Reference
Source Location
- Repository: testcafe
- File: src/api/test-controller/assertion.ts
- Lines: 35-154
Signature
class Assertion {
constructor(actual: any, testController: TestController, callsite?: object)
// Equality
eql(expected: any, message?: string, options?: AssertionOptions): TestController
notEql(expected: any, message?: string, options?: AssertionOptions): TestController
// Boolean
ok(message?: string, options?: AssertionOptions): TestController
notOk(message?: string, options?: AssertionOptions): TestController
// Contains
contains(expected: any, message?: string, options?: AssertionOptions): TestController
notContains(expected: any, message?: string, options?: AssertionOptions): TestController
// Type
typeOf(expected: string, message?: string, options?: AssertionOptions): TestController
notTypeOf(expected: string, message?: string, options?: AssertionOptions): TestController
// Comparison
gt(expected: number, message?: string, options?: AssertionOptions): TestController
gte(expected: number, message?: string, options?: AssertionOptions): TestController
lt(expected: number, message?: string, options?: AssertionOptions): TestController
lte(expected: number, message?: string, options?: AssertionOptions): TestController
// Range
within(start: number, finish: number, message?: string, options?: AssertionOptions): TestController
notWithin(start: number, finish: number, message?: string, options?: AssertionOptions): TestController
// Pattern matching
match(expected: RegExp, message?: string, options?: AssertionOptions): TestController
notMatch(expected: RegExp, message?: string, options?: AssertionOptions): TestController
}
interface AssertionOptions {
timeout?: number;
allowUnawaitedPromise?: boolean;
}
Import
// Assertion created via t.expect(), no direct import needed
test('My test', async t => {
await t.expect(Selector('h1').textContent).eql('Welcome');
});
I/O Contract
Inputs
| Name | Type | Required | Description |
|---|---|---|---|
| actual | any | Yes (constructor) | Value to assert on (often Selector property) |
| expected | any | Yes (most methods) | Expected value to compare against |
| message | string | No | Custom error message for assertion failures |
| options.timeout | number | No | Maximum time in milliseconds to retry assertion |
| options.allowUnawaitedPromise | boolean | No | Allow promises without await (advanced) |
Outputs
| Name | Type | Description |
|---|---|---|
| testController | TestController | Returns TestController for chaining more actions |
Usage Examples
Equality Assertions
import { Selector } from 'testcafe';
fixture`Assertions`
.page`https://example.com`;
test('Check equality', async t => {
const heading = Selector('h1');
const count = Selector('.item').count;
await t
.expect(heading.textContent).eql('Welcome', 'Heading should say Welcome')
.expect(count).eql(5)
.expect(heading.visible).eql(true);
});
test('Check inequality', async t => {
await t.expect(Selector('.error').exists).notEql(true);
});
Boolean Assertions
test('Boolean checks', async t => {
const checkbox = Selector('#terms');
const errorMessage = Selector('.error-message');
await t
.expect(checkbox.checked).ok()
.expect(errorMessage.exists).notOk();
});
String Assertions
test('String contains', async t => {
const paragraph = Selector('p.description');
await t
.expect(paragraph.textContent).contains('TestCafe')
.expect(paragraph.textContent).notContains('deprecated');
});
test('Pattern matching', async t => {
const email = Selector('#email-display');
await t
.expect(email.textContent).match(/^[a-z]+@[a-z]+\.[a-z]+$/)
.expect(email.textContent).notMatch(/admin/);
});
Type Assertions
test('Type checking', async t => {
const count = Selector('.item').count;
const text = Selector('h1').textContent;
await t
.expect(count).typeOf('number')
.expect(text).typeOf('string');
});
Comparison Assertions
test('Numeric comparisons', async t => {
const itemCount = Selector('.product').count;
const price = Selector('.price').textContent;
await t
.expect(itemCount).gt(0, 'Should have at least one product')
.expect(itemCount).gte(1)
.expect(itemCount).lt(100)
.expect(itemCount).lte(50);
});
Range Assertions
test('Range checking', async t => {
const rating = Selector('.rating-value').textContent;
await t
.expect(parseFloat(await rating)).within(1, 5)
.expect(parseFloat(await rating)).notWithin(0, 1);
});
Custom Timeout
test('Assertion with custom timeout', async t => {
// Wait up to 10 seconds for slow-loading element
await t.expect(Selector('.delayed-content').visible).ok('', {
timeout: 10000
});
});
Smart Retry with Dynamic Values
test('Automatic retry for dynamic content', async t => {
// Clicks trigger AJAX request that updates counter
await t.click('#load-items');
// Assertion automatically retries until count changes
const items = Selector('.item');
await t.expect(items.count).gte(1);
// Works with any Selector property
await t.expect(items.nth(0).textContent).contains('Product');
});
Multiple Assertions
test('Chain multiple assertions', async t => {
const loginButton = Selector('#login-button');
await t
.expect(loginButton.exists).ok()
.expect(loginButton.visible).ok()
.expect(loginButton.hasAttribute('disabled')).notOk()
.expect(loginButton.textContent).eql('Log In')
.expect(loginButton.classNames).contains('btn-primary');
});
Assertions with Custom Messages
test('Custom error messages', async t => {
await t
.expect(Selector('.item').count).gte(1, 'Expected at least one item in the list')
.expect(Selector('#error').exists).notOk('Error message should not be visible');
});