I was doing a code review for a colleague recently and noticed his test used toEquals() to compare two separate arrays. Wait! What? You can't do that? I checked out the code and stepped through it using IntelliJ's debugger. Indeed the code did work. I needed to find out what toEquals() was! Up until then, I'd primarily focused on toBe() for comparisons in unit tests. When I needed to compare an array or array items, I'd often dig deep and compare individual elements, or properties on such elements. I'm a bit embarrassed I never knew there was a better / easier way. Let's look at toEqual() along with a dose of ToBe().

Which is Which?

  • >toBe(): The toBe() comparison will compare two references. If they are equal, you'll get a success and if not, you'll get a failure. It uses `===` under the hood.
  • >toEqual(): The toEqual() compares values in the object. It is a deep equality comparison.

For simple values, both toBe() and toEquals() are essentially identical. toEqual() becomes much more interesting when dealing with objects, or arrays.

Object Comparison

Object Comparisons are pretty easy to set up in a test. First, create the test outline:

view plain print about
1it('Should compare Objects', () => {

Now, create two objects in the test:

view plain print about
1const obj1 = {id: 1, foo: 'bar'};
2const obj2 = {id: 1, foo: 'bar'};

We have two objects, and therefore two object instances, but the properties and values inside each object are identical.

Run these two assertions:

view plain print about
1expect(obj1).not.toBe(obj2); // reference compare; not equal
2expect(obj1).toEqual(obj2); // property compare; equal

The toBe() comparison checks for references. Both obj3 and obj4 are pointed at different objects, and as such the compare will fail. I added a not to the compare so it would succeed.

The toEquals() comparison will check the values in each object. Since they match up, and all have equivalent values on each property, it passes.

If there is any difference between the properties of the two objects the toEquals() compare will fail. Let's add a third object:

view plain print about
1const obj3 = {id: 1, foo: 'bar', foo2: 'bar2'};

And a new assertion:

view plain print about
1expect(obj1).not.toEqual(obj3); // property compare; not equal

Since the third object has a new property, the two objects are not comparatively equal.

Array Comparison

This use case is more interesting to me. You can use toEqual to compare the objects in two separate arrays.

As with the previous sample, let's start with two objects:

view plain print about
1const obj1 = {id: 1, foo: 'bar'};
2const obj2 = {id: 2, foo: 'bar2'};

And create two arrays from these objects:

view plain print about
1const array1 = [obj1, obj2];
2const array2 = [obj1, obj2];

Each array is different, but has the exact same objects in the exact same order.

Normally in a situation like this I'd drill down into the array elements, possibly accessing specific properties to determine equality:

view plain print about
1expect(array1[1]).toBe(array2[1]); // reference compare, equal

It works, but is not the most elegant way.

Comparing the two arrays with toBe() will cause a failed assertion:

view plain print about
1expect(array1).not.toBe(array2); // reference compare; not equal

I make this pass by using the 'not' operator. Using toEqual() on the other hand succeeds:

view plain print about
1expect(array1).toEqual(array2); // element compare; same references, equal

That is awesome.

The order of elements in the array must be equal. We can add another array:

view plain print about
1const array3 = [obj2, obj1];

It contains the same objects, but in the reverse order. The comparison will fail:

view plain print about
1expect(array1).not.toEqual(array3); // element array; different order, not equal

The equals() comparison is drilling down into objects for specific values. In the array it is not comparing references.

Let's create a third object:

view plain print about
1const obj3 = {id: 1, foo: 'bar'};

The 3rd object is the same as our first object, in terms of values. Let's also add a fourth array:

view plain print about
1const array4 = [obj3, obj2];

The fourth array is different from array1, in that it references a different array instance, and in the fact that the first element is a different object. However, since obj3 and obj1 are similar, we can still compare with toEquals() succesfully:

view plain print about

I can definitely see using this in future tests more than I have in the past.

I threw together some samples using Angular, because that was the TypeScript framework I had easily available to set up some quick experimental tests.

Check out the code sample.