Airbrake Blog

Node.js Error Handling - AssertionError

Written by Frances Banks | Dec 2, 2017 1:30:51 AM

Starting off into our detailed Node.js Error Handling series, today we'll be going over the AssertionError. As with many other programming languages, Node.js comes with an assert class as part of its core modules set, allowing simple assertion tests to be performed. When such an assertion fails an AssertionError is thrown to indicate what went wrong.

Throughout this article we'll explore the AssertionError in greater detail, starting with where it sits in the overall Node.js Error Class Hierarchy. We'll also look at some functional sample code illustrating how these errors are typically thrown and how you can handle them in your own code, so let's get crackin'!

The Technical Rundown

Most Node.js errors inherit from the Error base class, or extend from an inherited class therein. The full error hierarchy of this error is:

Full Code Sample

Below is the full code sample we'll be using in this article. It can be copied and pasted if you'd like to play with the code yourself and see how everything works.

const assert = require('assert');
const AssertionError = require('assert').AssertionError;

function executeTests () {
console.log("++++++++++++++++++++++++++++++");

assertStrictEquality(0, 1);

console.log("++++++++++++++++++++++++++++++");

assertStrictEquality(0, 1, "0 and 1 are not equal!");

console.log("++++++++++++++++++++++++++++++");

assertStrictEquality(1, 1);

console.log("++++++++++++++++++++++++++++++");

assertStrictInequality(4, 4);

console.log("++++++++++++++++++++++++++++++");

assertStrictInequality(4, 4, "4 and 4 are equivalent!");

console.log("++++++++++++++++++++++++++++++");

assertStrictInequality(4, 5);
}

function assertStrictEquality (a, b, message = null) {
try {
// Output test.
console.log(`----- ASSERTING: ${a} === ${b} -----`);
// Assert equality of a and b parameters.
assert.strictEqual(a, b, message);
// Output confirmation of successful assertion.
console.log(`----- CONFIRMED: ${a} === ${b} -----`);
} catch (e) {
if (e instanceof AssertionError) {
// Output expected AssertionErrors.
console.log(e);
} else {
// Output unexpected Errors.
console.log(e);
}
}
}

function assertStrictInequality (a, b, message = null) {
try {
console.log(`----- ASSERTING: ${a} !== ${b} -----`);
// Assert inequality of a and b parameters.
assert.notStrictEqual(a, b, message);
// Output confirmation of successful assertion.
console.log(`----- CONFIRMED: ${a} !== ${b} -----`);
} catch (e) {
if (e instanceof AssertionError) {
// Output expected AssertionErrors.
console.log(e);
} else {
// Output unexpected Errors.
console.log(e);
}
}
}

executeTests();

When Should You Use It?

As mentioned, the only time you should experience an AssertionError in a Node.js application is when making use of assert API calls. Thus, it's worth briefly going over what assert is used for before we get into the errors it produces.

In general terms, a test assertion is an expression or statement that encapsulates a snippet of testable logic, with a clearly defined target to be tested. Each test assertion should be simple and easily executable, without attempting to perform more than a singular task. Thus, most assertion libraries/modules found in programming languages perform only the most rudimentary tests, such as testing for equality of two values.

The assert class in Node.js provides a handful of basic methods, such as assert.equal to test equality, assert.notEqual for inequality, and assert.ok to test the "truthiness" of the passed argument. Regardless of what assert method is being called a failure will always throw an AssertionError.

To illustrate this in action we've got some super simple code:

const assert = require('assert');
const AssertionError = require('assert').AssertionError;

We start by requiring the assert core module, along with assigning the AssertionError constant to the AssertionError found in the assert module. It's worth noting that AssertionError directly inherits from the Error class, which gives it a number of built-in functionalities we'll look at in a moment.

Next we define the first of our two test functions, assertStrictEquality (a, b, message = null):

function assertStrictEquality (a, b, message = null) {
try {
// Output test.
console.log(`----- ASSERTING: ${a} === ${b} -----`);
// Assert equality of a and b parameters.
assert.strictEqual(a, b, message);
// Output confirmation of successful assertion.
console.log(`----- CONFIRMED: ${a} === ${b} -----`);
} catch (e) {
if (e instanceof AssertionError) {
// Output expected AssertionErrors.
console.log(e);
} else {
// Output unexpected Errors.
console.log(e);
}
}
}

For the most part, this function is just a wrapper to perform an assert.strictEquality(...) call on the two a and b parameters of our function. We've included some useful log output showing what our attempted assertion is, and if it succeeded. In the event of a failure, we catch the error and perform a check of the error class type before outputting it to the log.

Let's make a few calls to assertStrictEquality(...) and see what happens:

console.log("++++++++++++++++++++++++++++++");

assertStrictEquality(0, 1);

console.log("++++++++++++++++++++++++++++++");

assertStrictEquality(0, 1, "0 and 1 are not equal!");

console.log("++++++++++++++++++++++++++++++");

assertStrictEquality(1, 1);

Running these tests produces the following output:

++++++++++++++++++++++++++++++
----- ASSERTING: 0 === 1 -----
{ AssertionError [ERR_ASSERTION]: 0 === 1
at assertStrictEquality (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:35:12)
at executeTests (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:7:3)
at Object.<anonymous> (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:67:1)
at Module._compile (module.js:632:14)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Function.Module.runMain (module.js:676:10)
at startup (bootstrap_node.js:187:16)
generatedMessage: true,
name: 'AssertionError [ERR_ASSERTION]',
code: 'ERR_ASSERTION',
actual: 0,
expected: 1,
operator: '===' }

++++++++++++++++++++++++++++++
----- ASSERTING: 0 === 1 -----
{ AssertionError [ERR_ASSERTION]: 0 and 1 are not equal!
at assertStrictEquality (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:35:12)
at executeTests (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:11:3)
at Object.<anonymous> (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:67:1)
at Module._compile (module.js:632:14)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Function.Module.runMain (module.js:676:10)
at startup (bootstrap_node.js:187:16)
generatedMessage: false,
name: 'AssertionError [ERR_ASSERTION]',
code: 'ERR_ASSERTION',
actual: 0,
expected: 1,
operator: '===' }

++++++++++++++++++++++++++++++
----- ASSERTING: 1 === 1 -----
----- CONFIRMED: 1 === 1 -----

As expected, the first assertion that 1 equals 0 fails and produces our first AssertionError with the default error message of 0 === 1. As mentioned, since AssertionError derives from the base Error class, the actual AssertionError that is caught is an anonymous object that contains a handful of useful properties. One such property is generatedMessage, which is a boolean indicating if the associated message was automatically generated by Node.js, or whether it was manually provided elsewhere.

Our second function call makes use of this custom message capability by passing an argument to the message parameter, which is passed as the third argument to the underlying assert.strictEqual(...) method. Consequently, even though we get another AssertionError since 0 and 1 are not equal, the associated message is now a custom message: 0 and 1 are not equal!.

Finally, to make sure everything works as expected we pass two equivalent values of 1 and 1 and the log output confirms the assertion succeeded.

Next up, our assertStrictInequality (a, b, message = null) function does much the same as the previous function, but inverses the logic:

function assertStrictInequality (a, b, message = null) {
try {
console.log(`----- ASSERTING: ${a} !== ${b} -----`);
// Assert inequality of a and b parameters.
assert.notStrictEqual(a, b, message);
// Output confirmation of successful assertion.
console.log(`----- CONFIRMED: ${a} !== ${b} -----`);
} catch (e) {
if (e instanceof AssertionError) {
// Output expected AssertionErrors.
console.log(e);
} else {
// Output unexpected Errors.
console.log(e);
}
}
}

Just as before, we'll perform three test calls with various arguments for each invocation:

console.log("++++++++++++++++++++++++++++++");

assertStrictInequality(4, 4);

console.log("++++++++++++++++++++++++++++++");

assertStrictInequality(4, 4, "4 and 4 are equivalent!");

console.log("++++++++++++++++++++++++++++++");

assertStrictInequality(4, 5);

And, also as we saw with the strictEqual assertion tests above, these calls produce the expected console outputs:

++++++++++++++++++++++++++++++
----- ASSERTING: 4 !== 4 -----
{ AssertionError [ERR_ASSERTION]: 4 !== 4
at assertStrictInequality (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:53:12)
at executeTests (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:19:3)
at Object.<anonymous> (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:67:1)
at Module._compile (module.js:632:14)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Function.Module.runMain (module.js:676:10)
at startup (bootstrap_node.js:187:16)
generatedMessage: true,
name: 'AssertionError [ERR_ASSERTION]',
code: 'ERR_ASSERTION',
actual: 4,
expected: 4,
operator: '!==' }
++++++++++++++++++++++++++++++
----- ASSERTING: 4 !== 4 -----
{ AssertionError [ERR_ASSERTION]: 4 and 4 are equivalent!
at assertStrictInequality (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:53:12)
at executeTests (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:23:3)
at Object.<anonymous> (D:\work\Airbrake.io\Exceptions\NodeJS\Error\AssertionError\app.js:67:1)
at Module._compile (module.js:632:14)
at Object.Module._extensions..js (module.js:646:10)
at Module.load (module.js:554:32)
at tryModuleLoad (module.js:497:12)
at Function.Module._load (module.js:489:3)
at Function.Module.runMain (module.js:676:10)
at startup (bootstrap_node.js:187:16)
generatedMessage: false,
name: 'AssertionError [ERR_ASSERTION]',
code: 'ERR_ASSERTION',
actual: 4,
expected: 4,
operator: '!==' }
++++++++++++++++++++++++++++++
----- ASSERTING: 4 !== 5 -----
----- CONFIRMED: 4 !== 5 -----

Airbrake's robust error monitoring software provides real-time error monitoring and automatic error reporting for all your development projects. Airbrake's state of the art web dashboard ensures you receive round-the-clock status updates on your application's health and error rates. No matter what you're working on, Airbrake easily integrates with all the most popular languages and frameworks. Plus, Airbrake makes it easy to customize error parameters, while giving you complete control of the active error filter system, so you only gather the errors that matter most.

Check out Airbrake's error monitoring software today and see for yourself why so many of the world's best engineering teams use Airbrake to revolutionize their exception handling practices! Try a free 14-day trial today.