Explain Codes LogoExplain Codes Logo

Jasmine JavaScript Testing - toBe vs toEqual

javascript
jasmine
matchers
testing
Alex KataevbyAlex Kataev·Aug 5, 2024
TLDR

The toBe matcher checks whether two items refer to the identical object (same reference), just like JavaScript's ===. The toEqual matcher instead checks whether two objects have the same value, making it ideal for inspecting object contents.

Quick Examples:

expect(1).toBe(1); // Correct, 1 is indeed 1. expect({ a: 1 }).toBe({ a: 1 }); // Incorrect, same properties, but not the same memory space. How unfortunate! expect({ a: 1 }).toEqual({ a: 1 }); // Correct, same contents, Jasmine is happy.

Exploring the fine-print of toBe and toEqual is vital for effective JavaScript testing.

Under the hood – toBe vs toEqual

toBe, toted as the «matcher of strict sameness», uses the rigid === comparison, making it the chief choice for primitives when an exact match is expected. Beware, though, for even two independent objects with identical contents will stumble over toBe:

const bobby = {}; const bobbyClone = {}; expect(bobby).toBe(bobbyClone); // Incorrect. Same looks, different minds. Oops!

On the opposite end, toEqual runs a deep comparison, checking each property and its children for equality:

const bobby = { child: { toy: 'Rubber Duck' } }; const bobbyClone = { child: { toy: 'Rubber Duck' } }; expect(bobby).toEqual(bobbyClone); // Correct! Looks alike, thinks alike. Success!

toEqual also plays nice with special JavaScript objects such as Date, RegExp, and wrapped types like Number, focusing on the value, not the wrapper.

Special scenarios

Counting the beans, Numerical comparisons

When dealing with numeric comparisons, selecting the right matcher can avert subtle errors. Let's say you're a banker:

const vaultGoldBarsString = "100"; const vaultGoldBarsNumber = 100; expect(+vaultGoldBarsString).toBe(vaultGoldBarsNumber); // Correct, string was cunningly converted to a number. Theft averted! expect(vaultGoldBarsString).not.toEqual(vaultGoldBarsNumber); // Correct again, comparing apples and oranges...or strings and numbers.

The «Doppelgänger Disorder», Comparing object references

Imagine you have a getSingleton function which should always return the same signleton object:

const singleton = {}; function getSingleton() { return singleton; } expect(getSingleton()).toBe(singleton); // Correct! Same object, same memory space.

The Mirror Maze, arrays and complex objects

When you're traversing arrays or juggling complex objects, toEqual is your staunchest ally:

const swanLakeBallet = [1, 2, 3]; const swanLakeBalletRehearsal = [1, 2, 3]; expect(swanLakeBallet).toEqual(swanLakeBalletRehearsal); // Correct! Same steps, same performance.

Time Trekkers and String Wranglers, special JavaScript objects

With value comparisons, toEqual handles special JavaScript objects adeptly:

expect(new Date('2023-01-01')).toEqual(new Date('2023-01-01')); // Correct! You're not getting older. expect(new RegExp('ab+c')).toEqual(/ab+c/); // Correct! Regex match, score!

Pitfalls to avoid

Beware the Tiny Gap, floating point numbers

When dealing with floating point numbers, be wary of the classic trap of precision:

expect(0.1 + 0.2).toBe(0.3); // Incorrect, due to precision error. Binary went on a vacation! expect(0.1 + 0.2).toBeCloseTo(0.3, 5); // Correct, works around the precision issue. Binary is back!

The Shapeshifter, object mutability

In mutable objects, toBe can spring surprises:

const originalOrder = [1, 2, 3]; const messedUpOrder = originalOrder; messedUpOrder.push(4); expect(messedUpOrder).toBe(originalOrder); // Correct! But beware, same ref despite mutation. 'mutatable' is the evil twin of 'immutable'.

Suit Up, value types with constructors

Don't forget, toBe is not suitable for value types constructed using the new keyword:

expect(new String('hello')).toBe('hello'); // Incorrect! Same string, but one is more than meets the eye.

Deep dive into Jasmine's secret archives

To truly conquer the innards of Jasmine's matchers, venture into the source code. Decode the enigma of the toBe matcher's strict comparison (===) and toEqual matcher's elaborate deep equality check. The source is available on GitHub, for those brave enough.

Key learnings for further honing

Peruse through the Jasmine docs, pore over online tutorials, or indulge in community discussions at the Jasmine GitHub Wiki for enlightening insights and nifty tricks.