On Using `assert` as Your Assertion Library
Colin J. Ihrig
This post is a more detailed followup to this tweet
in which I advocate for using Node's assert
module as your goto
assertion library.
Disclaimer: There are plenty of perfectly good JavaScript assertion libraries out there. If you're happy with your current choice in assertion libraries, please continue using them. This post is just my personal opinion. It does not represent the opinion of my employer, your employer, or anyone else.
Background
Node.js ships with its own assertion module, assert
. This module was created to serve Node's own
internal testing purposes. Publicly exposing assert
was largely considered to be a mistake, but
Node was unable to remove it from the public API because the ecosystem had come to rely on it. Instead,
the API was considered "locked" and the documentation actively discouraged its use. That all changed in
early 2017, and assert
is actively developed and maintained.
While all of this was going on, several popular userland assertion libraries came into existence. One
of the most popular is chai
. It exposes several styles of assertion
APIs, including one that is very much like assert
:
assert.notStrictEqual(3, '3', 'no coercion for strict equality');
Another style allows you to write assertions that almost resemble natural language:
expect([1, 2]).to.not.equal([1, 2]);
However, a problem was noted with some of chai
's assertions. Using chai
, it was easy to write incomplete
assertions by forgetting to add ()
to function calls. This lead to the creation of
@hapi/code
, a more minimal assertion library created specifically
for the hapi framework. It removed the use of getters, and required that assertions be proper function calls.
It even provided APIs to detect incomplete assertions. These APIs are consumed by hapi's test runner,
@hapi/lab
to report such errors during testing.
For a bit of additional context, I was the lead maintainer of @hapi/code
for approximately four years.
assert
?
So, why - Personal preference. If you have a personal preference to use another library, then continue to do so. I don't recommend revisiting every test you've ever written just to change assertion libraries. I still have a lot of tests that use
@hapi/code
, but I've moved toassert
for all new code, and generally migrate legacy code as I update it for other reasons. assert
is built into the Node.js platform, and actively maintained. This reduces the need for an additional dependency. This leads to simpler projects, and removes a security vulnerability vector. The fact thatassert
is actively maintained as part of the Node runtime means that support for new language features generally shows up fairly quickly.assert
has a simple API. Libraries likechai
and@hapi/code
tend to do a lot of magic under the hood. In 2014, I thought it was really cool to be able write assertions like English sentences. However, by 2018, I got tired of checking the documentation (for a library that I was maintaining!) to remember how some of the magic assertions worked, and how their behavior changed depending on if they were operating on objects vs. arrays vs. strings vs. primitives, etc. By comparison, theassert
API can be more or less memorized fairly easily.- It's pretty hard to write incomplete assertions with
assert
. Remember earlier when I said that@hapi/code
was created because ofchai
's incomplete assertion problem? Remember how I said that@hapi/code
has APIs for detecting incomplete assertions? You have to try pretty hard to write an incomplete assertion withassert
, and therefore, you don't need APIs to detect them. Simplicity is a great thing! assert
has access to more powerful APIs. As part of the Node.js runtime,assert
can (and does) reach into the C++ binding layer and get information directly from V8. This is particularly useful in a language like JavaScript that makes it very hard to determine a variable's real data type. Userland libraries have to either guess, build on top ofassert
, or access the binding layer, which is dangerous, not supported, and going away in future versions of Node.
Conclusion
I hope you found this quick analysis useful. Again, if you're happy with your current assertion library, then keep using it. As the former maintainer of a userland assertion library, I have personally moved to using assert
in new code, and have been happy with the decision.