Back to Test Automation
2026-03-239 min read

Check out our example recipe extending chai with new assertions. (Test Automation)

Learn Check out our example recipe extending chai with new assertions. (Test Automation) step by step with clear examples and exercises.

Title: Extending Chai with New Assertions for Test Automation Using JavaScript (Selenium, Cypress, Playwright)


Why This Matters

In test automation, assertions are crucial to validate that the application behaves as expected. While popular libraries like Jest and Mocha offer a wide range of assertion functions, Chai is a flexible assertion library for JavaScript that allows you to write readable tests with its BDD (Behavior-Driven Development) style. However, sometimes the available assertions might not suffice, and you may need to extend Chai with custom assertions to meet your specific testing needs. This lesson will guide you through creating new assertions using Chai and show you how to use them in test automation projects with Selenium, Cypress, and Playwright.


Prerequisites

  • Basic understanding of JavaScript
  • Familiarity with Chai assertion library
  • Knowledge of test automation frameworks: Selenium, Cypress, or Playwright
  • Understanding of BDD (Behavior-Driven Development) style

To expand on the prerequisites section:

  1. Basic JavaScript knowledge is required to understand and implement custom assertions in your tests. You should be familiar with concepts such as functions, objects, and event handling.
  2. Familiarity with Chai is essential for writing custom assertions that work seamlessly within your test suites. Learn more about Chai's features and usage by visiting the official documentation: https://www.chaijs.com/
  3. To use these custom assertions in test automation projects, you should have experience with one or more of the following frameworks: Selenium, Cypress, or Playwright. These tools enable you to automate interactions with web applications and verify their behavior. Learn more about each framework by visiting their respective official websites:
  • Selenium: https://www.selenium.dev/
  • Cypress: https://www.cypress.io/
  • Playwright: https://playwright.dev/

Core Concept

To extend Chai with custom assertions, you'll create a new function that accepts the expected and actual values as parameters. The function will then compare the two values and throw an error if they don't match, using Chai's assert function. You can define your custom assertion globally or within a specific test file, depending on your project structure.

Here's an example of creating a custom assertion for checking if a string contains a specific substring:

Chai.Assertion.addMethod('containsSubstring', function(substring) {
const actual = this._obj;
if (!actual.includes(substring)) {
this.fail(`Expected '${actual}' to contain the substring '${substring}'`);
}
});

Now you can use this custom assertion in your tests like so:

it('should contain a specific substring', function() {
const text = 'Hello, World!';
expect(text).to.containsSubstring('World');
});

To expand on the Core Concept section:

  1. Chai allows you to create custom assertions by extending its Assertion class and defining a new method with the desired name (e.g., containsSubstring). The function receives the expected value as a parameter and checks whether the actual value matches it. If they don't match, an error is thrown using Chai's built-in fail method.
  2. You can chain multiple custom assertions together to create complex test cases that validate various aspects of your application's behavior.
  3. Custom assertions can be defined globally or within a specific test file, depending on your project structure and testing needs. If you define them globally, they will be available for all tests in the project. Defining custom assertions within a specific test file allows you to isolate their usage and reduce potential conflicts with other assertions.
  4. Chai provides several built-in assertion methods such as to.equal, to.deep.equal, to.be.false, and to.be.null. You can create custom assertions that build upon these foundational assertions to meet your specific testing needs.

Worked Example

Let's create a custom assertion for checking if an element's text content matches a specific CSS selector:

  1. Install Chai: npm install chai
  2. Create a new file named customAssertions.js and add the following code to define the custom assertion:
const { Assertion } = require('chai');

class ElementTextAssertion extends Assertion {
constructor(expected) {
super(expected, 'have text that matches CSS selector', true);
}

visit(subject) {
const element = subject.findElement(by.css(this._obj));
return element.getText().then((actualText) => {
this.actualize(() => expect(actualText).to.match(this._obj));
});
}
}

Chai.Assertion.addMethod(new ElementTextAssertion('^.*$'));
  1. Now, let's use our custom assertion in a Selenium test:
const { expect } = require('chai');
const { Builder, By, until } = require('selenium-webdriver');
const { ElementTextAssertion } = require('./customAssertions');

describe('Custom Assertion Example', function() {
let driver;

beforeEach(async function() {
driver = await new Builder().forBrowser('chrome').build();
await driver.get('https://example.com');
});

it('should have a specific text that matches CSS selector', async function() {
const headerText = await driver.findElement(By.css('#header h1'));
expect(headerText).to.haveTextThatMatchesCssSelector(/^Header Text$/);
});

afterEach(async function() {
await driver.quit();
});
});
  1. Repeat the process for Cypress and Playwright tests, adjusting the test runner setup accordingly.

To expand on the Worked Example section:

  1. In this example, we create a custom assertion called ElementTextAssertion that checks if an element's text content matches a specific CSS selector. The custom assertion extends Chai's Assertion class and overrides its visit method to interact with the test runner (Selenium in this case) and retrieve the actual text content of the element.
  2. We then use our custom assertion in a test case by importing it from the customAssertions.js file and chaining it with Chai's built-in expect function. The test case verifies that the header text on the example page matches the specified CSS selector.
  3. To make the custom assertion more versatile, we pass a regular expression as the expected value instead of a static string. This allows for more complex matching rules, such as case-insensitive or partial matches.
  4. By defining the custom assertion in a separate file (customAssertions.js) and importing it into our test files, we can easily reuse the assertion across multiple projects or test suites.
  5. For Cypress and Playwright tests, you'll need to adjust the test runner setup accordingly by installing the appropriate dependencies and modifying the test file imports.

Common Mistakes

  1. Forgetting to import Chai in your test file: Always include const { expect } = require('chai'); at the beginning of your test files.
  2. Not defining the custom assertion correctly: Make sure you extend Chai.Assertion, define the constructor, and use this._obj for the CSS selector.
  3. Using incorrect syntax for the custom assertion: Ensure that you're using the correct Chai method (.to.haveTextThatMatchesCssSelector) in your test cases.
  4. Not updating the test runner setup: Remember to include the customAssertions.js file in your test runner configuration.
  5. Forgetting to handle asynchronous tests: If your custom assertion relies on an asynchronous operation (e.g., interacting with the DOM), make sure you use promises or async/await syntax to ensure that the assertion is executed correctly.
  6. Not testing edge cases: When creating custom assertions, it's essential to consider various edge cases and validate that your assertion behaves as expected in different scenarios.
  7. Not considering browser compatibility: Ensure that your custom assertion works across multiple browsers (Chrome, Firefox, Safari, etc.) by testing it with each browser supported by the test automation framework you are using.
  8. Not handling exceptions properly: If an error occurs during the execution of a custom assertion, make sure to catch and handle it appropriately to prevent test failures due to unexpected errors.
  9. Not providing clear error messages: When creating custom assertions, ensure that error messages are informative and help developers understand why the assertion failed.
  10. Overcomplicating custom assertions: Try to keep your custom assertions simple and focused on a specific testing need. Avoid creating overly complex assertions that are difficult to maintain and understand.

Practice Questions

  1. Write a custom assertion for checking if an element's CSS class name matches a specific value.
  2. Create a custom assertion that verifies whether an array contains a specific value.
  3. Extend Chai to handle asynchronous tests, and write a custom assertion for checking if a promise resolves within a specific timeout.
  4. Write a custom assertion that checks if the text content of an element is within a certain range of characters (e.g., between 50 and 100 characters).
  5. Create a custom assertion for checking if an element's attribute value matches a specific value.
  6. Write a custom assertion that checks if a specific element is visible on the page.
  7. Create a custom assertion for checking if a specific element is interactable.
  8. Write a custom assertion for validating that a form input field has a specific error message when it's empty or invalid.
  9. Create a custom assertion for verifying that an image has the correct dimensions (width and height).
  10. Write a custom assertion for checking if a table row contains specific data in its cells.

FAQ

Can I use my custom assertions with other test runners like Jest or Mocha?

Yes, you can adapt the custom assertions to work with other test runners as well. However, you may need to adjust the test runner setup and importing of Chai accordingly.

How do I create a custom assertion for checking if an element's attribute value matches a specific value?

You can define a new function that accepts the attribute name and expected value as parameters. Then use element.getAttribute() to get the attribute value and compare it with the expected value.

Can I reuse my custom assertions across multiple test files or projects?

Yes, you can create a separate file for your custom assertions and import them into your test files as needed. This allows you to easily reuse the assertions across multiple projects or test suites.

How do I create a custom assertion for checking if a specific element is visible on the page?

You can define a custom assertion that checks whether an element is visible by calculating its position on the page and verifying that it's within the viewport or meets certain visibility criteria (e.g., not hidden by other elements).

Can I create a custom assertion for checking if a specific element is interactable?

Yes, you can create a custom assertion that checks whether an element is interactable by attempting to click or focus on it and verifying that the interaction is successful (e.g., no errors are thrown). This can help ensure that your tests validate the application's responsiveness and accessibility.

How do I create a custom assertion for checking if a form input field has a specific error message when it's empty or invalid?

You can define a custom assertion that checks whether an element contains a specific error message by using element.getText() to retrieve the text content and comparing it with the expected error message.

How do I create a custom assertion for verifying that an image has the correct dimensions (width and height)?

You can define a custom assertion that checks whether an image has the correct dimensions by using element.getSize() to retrieve the image's size and comparing it with the expected dimensions.

How do I create a custom assertion for checking if a table row contains specific data in its cells?

You can define a custom assertion that checks whether a table row contains specific data by using element.getText() to retrieve the text content of each cell and comparing it with the expected data.

How do I create a custom assertion for checking if an element's style property matches a specific value?

You can define a new function that accepts the style property name and expected value as parameters. Then use element.getAttribute() or element.getCssValue() to get the actual style property value and compare it with the expected value.

How do I create a custom assertion for checking if an element's background color matches a specific hexadecimal color code?

You can define a new function that accepts the expected hexadecimal color code as a parameter. Then use element.getCssValue('background-color')

Check out our example recipe extending chai with new assertions. (Test Automation) | Test Automation | XQA Learn