The Next Recession Will Be a Doozie!

We may be in the midst of one of the longest economic expansion cycles on record, but the Great Recession is still at the top of many investors’ minds including Yours Truly’s. The 2018 Q2 Zillow Home…

Smartphone

独家优惠奖金 100% 高达 1 BTC + 180 免费旋转




Testing Arrays and Objects with Chai.js

When it comes to testing arrays and objects with Chai.js sometimes the selection of flagging properties and assertions becomes confusing. nested? deep? own? include? all? In this article we’ll dive into how you can be an ace at testing arrays and objects with Chai.js.

If you missed part 1, the differences between a flagging property and chainable method, it’s worth skimming through that article to catch up before proceeding.

At the heart of much of the confusion around making assertions on arrays and object is Javascript’s notion of equality.

This can be surprising, and downright frustrating at times, especially for programmers coming to Javascript from other languages. The equality being expressed in the example above is actually a core mechanic of Javascript, not of Chai.js. Open up a node session and try the following:

Javascript equality is strict; it’s testing if the expression on the left is referring to the same point in memory that the expression on the right resides at. In the example above there are two copies of [1,2,3] (one on the left and one on the right). Because each copy has it’s own address in memory, Javascript’s strict equality considers them not equal as they do not share the same identity.

In Chai.js, the equal assertion, along with most other included Chai assertions, uses Javascipt’s strict equality.

During testing, it often is the case that strict equality is not desired, but instead equality in the sense that two objects are “equivalent” in that they have the same content.

Sameness seems simple on the surface, but becomes more complex when those expressions have children which themselves have children. Deep equality compares sameness to all depths.

Similar to arrays, comparing two objects will use strict or deep equality.

Deep equality is an excellent approach, but it enforces both order and contents when comparing arrays. Often the case arises in testing where the order doesn’t matter, but the contents do.

While eql compares content and enforces order, members only compares content allowing assertions that only care about values being present.

Danger Zone: A common mistake is to write the above assertion with include instead of have.

The distinction between include and have is an important one. Have is a cosmetic property. It does nothing to the expectation but make it easier to read. However include is a chainable method. It is setting a flag which changes the behavior of members to only test for the given values being in the value under test, regardless of what other values are in the array.

Between ordering and the exactness of members, there’s a 2x2 truth table of which matcher to use in what instances.

Another point of confusion on testing unordered array membership is Chai’s two flagging properties any and all. As of version 4.x, those flags do not change the behavior of the members assertion (they only affect the keys assertion which is discussed below).

And and all can be included if it makes the expectation easier to read, but are effectively acting as cosmetic properties at that point and run the risk of just making it confusing for other engineers that are familiar with what any and all do on other assertions. The following two are functionally equivalent.

Similarly, with an array of primitive values (non-objects) it’s possible to write the same expectation with eql or .ordered.members.

The difference between .ordered.members and .eql, aside from the way it reads to human readers, is the error message.

The difference between choosing eql and .ordered.members becomes more obvious when comparing arrays of objects. Mentioned before, eql is an equality assertion in Chai.js which will perform a deep equal instead of a strict equal. An third way to compare two arrays of primitive values is to use the flagging property deep.

While the expectation above is functionally equivalent to using eql, the difference the deep flag makes is when mixed with other assertions, such as members.

Important Concept: By default, all assertions in Chai are performing a strict equality comparison. Thus, asserting that an array of objects has a member object will cause those two objects to be compared strictly. Adding in the deep flag signals to the assertion to instead use deep equality for the comparison.

In case that was slightly mind blowing, it’s permissible at this point to react with, “Wow! That’s deep.”

When comparing objects, sometimes it’s only important what properties those objects have, not what the value of the properties are. A naïve approach would be to expect the existence of a property directly.

The main problem with writing tests this way is the error message it produces:

It doesn’t matter how long someone has been programming or how well they know a code base, error messages like this make problems unnecessarily difficult to figure out.

As expected, Chai provides the keys and property assertions which can assert the existence of a single property (property) or multiple properties (keys) on an object.

As an added bonus, if the value matters, the property assertion can be used with a second parameter, the expected value.

An alternative way to test for the existence of a property is with the include assertion. Include is acting in the same capacity that it did with arrays, checking that the given properties are methods of the value under tests, not that the given properties are the whole of the value under test.

As with other examples in this article, the difference comes in two ways: first in the error message that is printed out when it fails; and second in how it interacts with the deep flag.

deep.include is useful in some instances, but for anything more than a level or so deep can become unwieldy. For really deep inspections, the nested flagging property can be used. Nested signals that in all places where the property name (key) would have been, it is now a property path. This is particularly helpful when working with extremely complex JSON structures.

Something interesting about nested is that arrays can also be referenced by path as well. If, in the example above, filter became an array of terms, and not just a single term, accessing the array by index could be included in the nested property name.

The nested flagging property works with both the property and keys assertion.

Add a comment

Related posts:

Living on a Boat in Marina del Rey

Interview about how to save money and live deliberately on a sailboat in the Los Angeles areas with advice for others considering unconventional, tiny or shared housing.

Cyntoia Brown and the Years Lost by Juvenile Lifers

In The Princess Bride, Prince Humperdinck has Wesley strapped to a device known as The Machine, which has a lever that can be raised from 1 to 50. When the lever is turned to 1, the machine sucks…

How Much Does it Cost to Develop a Mobile App in 2023?

Worried about the cost of app development for your business? This blog discusses the rates prominent in 2023, considering all the responsible factors.