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) {
//..
});
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
};
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);
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
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'
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`
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'"
);
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:
- A boolean argument that has the result of the truth table.
- A string message is the message of the test fail case.
- A string message is the message of the test pass case.
- The expected value
- The actual value is the same as the _obj
- 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