toEqual vs toBe
This one tripped me up big time when I started. I kept getting confusing error messages because I used toBe when I should have used toEqual, or the other way around. Let me clear this up once and for all.
Here is the thing. toBe uses Object.is to compare values. toEqual recursively checks every property. That difference matters a lot when you deal with objects and arrays.
When toBe Works Fine
For simple values like numbers, strings, booleans, and null, toBe works perfectly. These are primitive values and they compare by value.
test('toBe works for primitives', () => {
expect(42).toBe(42);
expect('hello').toBe('hello');
expect(true).toBe(true);
expect(null).toBe(null);
});
Why toBe Fails for Objects
Here is where people get confused. Two objects with the same properties are not the same object in JavaScript. They have different references in memory.
test('toBe fails for objects', () => {
const obj1 = { name: 'Alice' };
const obj2 = { name: 'Alice' };
expect(obj1).not.toBe(obj2);
expect(obj1).toEqual(obj2);
});
See that? toBe says they are different because they live at different spots in memory. toEqual says they are the same because they have the same content.
The Same Goes for Arrays
Arrays work the same way. Two arrays with the same elements are different references.
test('arrays with same content', () => {
const arr1 = [1, 2, 3];
const arr2 = [1, 2, 3];
expect(arr1).not.toBe(arr2);
expect(arr1).toEqual(arr2);
});
Simple Rule of Thumb
Use toBe for primitives. Use toEqual for objects and arrays. That is it. If you follow that rule, you will never be confused again.
Try it Yourself →Key Takeaways
- toBe checks value equality using Object.is
- toEqual recursively checks object/array contents
- Use toBe for numbers, strings, booleans, and null
- Use toEqual for objects and arrays
- Two objects with the same properties are not the same reference