A handful of matchers cover the vast majority of everyday assertions. This lesson focuses on toBe, toEqual, toStrictEqual, and the defined/undefined checks you'll reach for constantly.
toBe vs toEqual vs toStrictEqual
.toBe() checks strict equality using Object.is(), effectively ===. Use it for primitives: numbers, strings, booleans, and reference checks on the exact same object instance.
.toEqual() recursively checks that two values have the same structure and values, ignoring object identity and undefined properties. .toStrictEqual() goes further: it also checks that object types match (so a class instance won't equal a plain object with the same shape) and that undefined properties are treated as present but missing rather than ignored.
.toBeDefined() passes when the value is not undefined.
.toBeUndefined() passes when the value is exactly undefined.
.toBeNaN() passes when the value is NaN, which .toBe(NaN) cannot check reliably.
Prefer these over manual typeof value === 'undefined' checks for clearer failure messages.
Common Matchers Cheat Sheet
The matchers you'll use in nearly every test file.
Matcher
Checks
.toBe(x)
Strict equality (primitives, references)
.toEqual(x)
Deep equality, ignoring undefined keys
.toStrictEqual(x)
Deep equality, including type and key presence
.toBeDefined()
Value is not undefined
.toBeUndefined()
Value is exactly undefined
.toBeNaN()
Value is NaN
.not.toBe(x)
Negates any of the above
toEqual vs toStrictEqual with Classes
A common surprise: .toEqual() treats a class instance and a plain object with matching properties as equal, because it only compares enumerable own properties. .toStrictEqual() also checks that both values share the same prototype/constructor.
class Point {
constructor(x, y) { this.x = x; this.y = y; }
}
const p = new Point(1, 2);
const plain = { x: 1, y: 2 };
expect(p).toEqual(plain); // passes
expect(p).toStrictEqual(plain); // FAILS: different constructors
When toBe() Is the Right Choice
Use .toBe() for primitive values (numbers, strings, booleans) and when you specifically care about reference identity — for example, confirming a function returns the same cached object instance instead of creating a new one each call.
const cache = {};
function getConfig() {
return cache;
}
expect(getConfig()).toBe(cache); // same reference, not just same shape
Common Mistakes
Using .toBe() on objects or arrays and getting confusing reference-equality failures.
Assuming .toEqual() checks object types, then being surprised .toStrictEqual() behaves differently.
Using expect(value).toBe(NaN), which always fails because NaN !== NaN under Object.is semantics used loosely; use .toBeNaN() instead.
Checking typeof value === 'undefined' manually instead of .toBeUndefined().
Key Takeaways
.toBe() is for primitives and reference equality.
.toEqual() performs deep structural comparison, ignoring undefined properties.
.toStrictEqual() additionally checks object types and key presence.
.toBeDefined(), .toBeUndefined(), and .toBeNaN() cover common defined-value checks cleanly.
Pro Tip
When a .toEqual() assertion passes but you feel it shouldn't have, try .toStrictEqual() instead — it often reveals subtle bugs like accidentally returning a class instance instead of a plain object.
You now know the matchers you'll use constantly. Next, explore truthiness matchers for checking null, undefined, and boolean-like values.