Modifiers
Modifiers enhance your test assertions by adapting matcher behavior for different scenarios. T hey connect your xExpect()
statement to the actual matcher, allowing for more flexible and powerful tests in your xJet test suites.
not
Inverts your assertion to verify that something is false rather than true.
test('verifies incorrect password is rejected', () => {
// Check authentication fails with wrong credentials
xExpect(authenticate('user', 'wrong_password')).not.toBeTruthy();
// Verify element is not in the expected state
xExpect(component.getStatus()).not.toBe('ready');
});
resolves
Unwraps a fulfilled promise's value so you can test the resolved result directly.
test('API request completes successfully', async () => {
// Using async/await - recommended approach
await xExpect(api.fetchData('/users')).resolves.toMatchObject({
success: true,
count: xExpect.any(Number)
});
// Alternative approach with Promise.then()
return xExpect(api.fetchConfig()).resolves.toHaveProperty('version');
});
TIP
Best Practice: The async/await syntax is generally more readable than the return approach. It allows for cleaner test organization, especially when you need to perform additional assertions after the promise resolves.
rejects
Tests that a promise rejects and allow you to verify the rejection reason. The modifier works with both promises that explicitly call reject()
and those that throw exceptions inside the promise executor. .rejects
Promise rejection patterns
xJet treats these rejection patterns equivalently with : .rejects
// Pattern 1: Explicit rejection with reject()
function explicitReject(): Promise<any> {
return new Promise((resolve, reject) => {
reject('error message');
});
}
// Pattern 2: Throwing inside promise executor
function throwInPromise(): Promise<any> {
return new Promise((resolve, reject) => {
throw 'error message';
});
}
// Both can be tested the same way
test('promise rejection patterns', async () => {
await xExpect(explicitReject()).rejects.toBe('error message');
await xExpect(throwInPromise()).rejects.toBe('error message');
});
You can use either toBe()
to match the exact rejection value or for error-like objects: toThrow()
test('different assertion styles with rejects', async () => {
// When rejecting with a string
function rejectWithString(): Promise<any> {
return new Promise((resolve, reject) => {
reject('validation failed');
});
}
// These assertions are equivalent
await xExpect(rejectWithString()).rejects.toBe('validation failed');
await xExpect(rejectWithString()).rejects.toThrow('validation failed');
// When rejecting with an Error object
function rejectWithError(): Promise<any> {
return new Promise((resolve, reject) => {
reject(new Error('network error'));
});
}
// These assertions work for Error objects
await xExpect(rejectWithError()).rejects.toThrow('network error');
await xExpect(rejectWithError()).rejects.toBeInstanceOf(Error);
});
INFO
While both toBe
and can be used with, using is generally preferred when testing Error objects as it provides better error messages and can check error types toThrow()
, .rejects
, toThrow()
Combining Modifiers
You can use modifiers together with various matchers to create powerful assertions:
test('demonstrates advanced modifier usage', async () => {
// Verify a promise resolves to a non-null value
await xExpect(storage.getSettings()).resolves.not.toBeNull();
// Verify a function doesn't throw under valid conditions
xExpect(() => parser.parseConfig('{"valid": true}')).not.toThrow();
// Verify an async operation doesn't resolve with a specific error state
await xExpect(permissions.check('admin')).resolves.not.toEqual({
denied: true
});
});