Table of contents
1.
Introduction 
2.
Core Plugin Concepts
2.1.
Accessing Utilities
2.2.
Using Flags
2.2.1.
Flag Usage
2.2.2.
Object Flag
2.3.
Composing an Assertion
2.3.1.
Basic Assertion
2.3.2.
Composing Error Message
3.
API Reference
3.1.
.addChainableMethod
3.1.1.
Program
3.2.
addMethod
3.2.1.
Program
3.3.
.addProperty
3.3.1.
Program
3.4.
.overwriteMethod
3.4.1.
Program
4.
FAQs
5.
Key Takeaways
Last Updated: Mar 27, 2024

Plugin Utilities

Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction 

Chai has made the developers who have always used a TDD (Test Driven Development) approach bring the best out of their tests as it can be easily paired off with any javascript testing framework. TDD is a process of software development that relies on software functionalities being converted to test cases and creating functions that pass all test cases in the test.

However, sometimes the assertions fall short of what the developer expects or needs at the moment. This is where Plugin Utility comes in. Plugin Utilities extends Chai with their own set of assertions to test their code with custom assertions better. By creating more assertions that test our functionalities in the ways we want it to we extend how we can make our tests flawless.

In this blog, we will learn in detail about some of these assertion techniques and how we can make our TDD even better.

Core Plugin Concepts

Plugins can be used in various ways for validating input data, asserting schema validation on an object, or ensuring proper behavior on a DOM element. The API here can encapsulate any synchronous task within a single assertion and can be reused multiple times in the tests.

Accessing Utilities

Accessing Utilities means creating a function similar to the Expect function that asserts whether the given test passes the given assertions. To achieve the above, we need to make a constructor bound to our Chai to use it along in our tests. We can not use utilities to make constructors of assertions in Chai. We will need to use the use method of the Chai export, which accepts a single function as an argument.

chai.use(function (_chai, utils) {
//..
});
You can also try this code with Online Javascript Compiler
Run Code

The function that contains the Assertion is passed two parameters to its scope. The first is the chai export, which will enable us to build helpers to use it in multiple test files and bundle it up for sharing.

module.exports = function (chai, utils) {
  var Assertion = chai.Assertion;

  // your helpers here
};
You can also try this code with Online Javascript Compiler
Run Code

An example of the actual test would require the Chai, helpers, and expect function in the test suite to make a test.

var chai = require('chai')
  , chaiModel = require('./helpers/model')
  , expect = chai.expect;

chai.use(chaiModel);
You can also try this code with Online Javascript Compiler
Run Code

Now we can create a constructor Assertion that works similar to expect(obj) but with a custom assertion.

Using Flags

Flags are key-value pairs that work as the core concept of how assertions work internally. Chai uses a small number of these internally; however, we can expand it as each Assertion has a set of primarily arbitrary flags.

Flag Usage

The flag utility can be used inside the use function by the utils.flag. If we pass three arguments in the function, it works as a setter. However, passing two arguments in the function makes it a getter.

var newAssert = new Assertion(obj);
utils.flag(newAssert, 'hello', 'world'); // sets key 'hello' to 'world'
var hello = utils.flag(newAssert, 'hello') //gets key 'hello', returns value
You can also try this code with Online Javascript Compiler
Run Code

Object Flag

Chai has a series of reserved flags used by Chai's core Assertions. It is advised not to interfere with flag names the same as the reserved flag to prevent any side effects. 

The object flag is the most important in any Assertion in Chai. This flag works as the subject of an assertion.  

var newAssert = new Assertion('hello');
var obj = flag(newAssert, 'object'); //obj === 'hello'
You can also try this code with Online Javascript Compiler
Run Code

The object is one of the most used flags; it contains a shortcut _obj property of a constructed assertion.

var obj = myAssert._obj; // obj === `hello`
You can also try this code with Online Javascript Compiler
Run Code

Some reserved flags are: ssfi, message, negate, deep, contains, lengthof.

Composing an Assertion

Now that we know how to create an Assertion, we need to invoke it and make a fallback in case there is a failure in gathering the Assertion.

For this, we use the assert method that takes multiple parameters and behaves according to whether the Assertion was negated or not.

Basic Assertion

First, let's create an Assertion, then we check it against our flags to see if it was negated or not.

var hello = new Assertion('hello');

hello.assert(
arthur._obj === 'hello'
, "expected #{this} to be 'hello'"
, "expected #{this} to not be 'hello'"
);
You can also try this code with Online Javascript Compiler
Run Code

Chai will check the first argument, pass the Assertion if it is true, and fail it with an error message thrown as part of a chai.AssertionError.

The assert method contains a total of six arguments:

  1. A boolean argument that has the result of the truth table.
  2. A string message is the message of the test fail case.
  3. A string message is the message of the test pass case.
  4. The expected value 
  5. The actual value is the same as the _obj 
  6. A boolean to determine whether to show the difference in the message in the test fail case.

Composing Error Message

Chai contains a lot of templates to create a dynamically generated error message. These templates are replaced by stringified objects that are referred there.

  • #{this}: the _obj of the Assertion
  • #{exp}: the expected value, if it was provided in assert
  • #{act}: the actual value defaults to _obj but can be overwritten by value provided in assert

API Reference

Chai has numerous APIs that help us in extending Chai with our assertions.

.addChainableMethod

This adds a method to an object such that it can later be chained. It takes in four parameters:

  • {Object} ctx: object to which the method is added 
  • {String} name: name of the method to be added
  • {Function} method: function to be attached to 'name' when called.
  • {Function} chainingBehaviour: function to be called every time the property is accessed.

Program

utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) {
  var obj = utils.flag(this, 'object');
  new chai.Assertion(obj).to.be.equal(str);
});
You can also try this code with Online Javascript Compiler
Run Code

Alternately it can also be accessed directly from chai.Assertion

chai.Assertion.addChainableMethod('foo', fn, chainingBehavior);.
You can also try this code with Online Javascript Compiler
Run Code

addMethod

This adds a method to the prototype of an object. It accepts three params:

  • {object} ctx: the object to which the method is bind
  • {string} name: the method to be added 
  • {function} method: function to be used as the method

Program

utils.addMethod(chai.Assertion.prototype, 'foo', function (str) {
  var obj = utils.flag(this, 'object');
  new chai.Assertion(obj).to.be.equal(str);
});
You can also try this code with Online Javascript Compiler
Run Code

This can alternatively be written from the chai.Assertion

chai.Assertion.addMethod('foo', fn);
You can also try this code with Online Javascript Compiler
Run Code

.addProperty

We can add properties to the prototype of an object.

  • {object} ctx: the object to which the property is added.
  • {string} name: the property to be added 
  • {function} method: function to be used for name

Program

utils.addProperty(chai.Assertion.prototype, 'foo', function () {
  var obj = utils.flag(this, 'object');
  new chai.Assertion(obj).to.be.instanceOf(Foo);
});
utils.addProperty(chai.Assertion.prototype, 'foo', function () {
  var obj = utils.flag(this, 'object');
  new chai.Assertion(obj).to.be.instanceOf(Foo);
});
You can also try this code with Online Javascript Compiler
Run Code

This can alternatively be written from the chai.Assertion

chai.Assertion.addProperty('foo', fn);
You can also try this code with Online Javascript Compiler
Run Code

.overwriteMethod

This can be used to overwrite already existing methods and provide access to previous function. Thus, there must be a returned function to be used.

  • {object} ctx: the object whose method is to be overwritten.
  • {string} name: the prototype to overwrite 
  • {function} method: function to be used for name

Program

utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) {
  return function (str) {
    var obj = utils.flag(this, 'object');
    if (obj instanceof Foo) {
      new chai.Assertion(obj.value).to.equal(str);
    } else {
      _super.apply(this, arguments);
    }
  }
});
You can also try this code with Online Javascript Compiler
Run Code

 

This can alternatively be written from the chai.Assertion

chai.Assertion.overwriteMethod('foo', fn);
You can also try this code with Online Javascript Compiler
Run Code

FAQs

1. What are plugins used for?

Ans: Plugins are generally used to add new functions to a host program without altering the hosting program itself. This when used in conjunction with chai.js helps us in adding customs assertions.
 

2. What is a chainable method?

Ans: Chainable methods are methods that combine many of the previous types into a single keyword.
 

3. What other API reference is there?

Ans: .expectTypes, .getActual, .getMessage, .getOwnEnumerableProperties are some other references that can be used as utilities.

 

4. Is TDD better than BDD?

Ans: In certain cases, TDD may tend better than BDD. However, the vice versa also tends to be true as well.

 

Key Takeaways

In this blog, we discussed how we can extend the assertions in the chai.js assertion library using the plugin utilities and the core concepts behind plugin utilities.

You may want to learn more about chai.js assertion library here.

Learning never stops, and to feed your quest to learn and become more skilled, head over to our practice platform Coding Ninjas Studio to practice top problems, attempt mock tests, read interview experiences, and much more.!

Happy Learning!

Live masterclass