## DEV Community

The Jared Wilcurt

Posted on • Updated on

# Why you should never use .toBe in Jest/Vitest

Alright, this is going to be a short one. Let's just get to the point, what should you use instead, and why.

`.toEqual()` is a better choice in every scenario.

Wait... I thought these were the same thing, just aliased?

Most do! And that right there is the problem. Here's the difference:

• `.toEqual` works based on deep equality
• `.toBe` is literally just doing a `Object.is(x, y)` under the hood. Which is slightly different, but basically the same as `x === y`.

Here is an example where the two differ:

``````let x = { z: true };
let y = { z: true };

expect(x)
.toBe(y); // FALSE

expect(x)
.toEqual(y); // TRUE
``````

Now sure, this confusion could have been avoided had these been named something like `.toDeepEqual()` and `.toStrictlyEqual()`. But that is not the world we live in! And it is unlikely to ever be, since they already have `.toStrictEqual()` built in which actually is closer to a deep equal, than a strict equal (`===`). Not at all confusing! ðŸ¤¬

In most cases, you are comparing an actual value with a hard coded expectation.

``````test('Generates kitten', () => {
let kitten = generateKitten();

expect(kitten)
.toEqual({
fluffy: true,
type: 'kitty',
tail: true,
feet: 4
});
});
``````

So in these cases, `.toEqual()` gives you exactly what you want. It also shows a diff of the specific properties and values that do not match when a test fails.

But what about primatives? Like `undefined`, `4`, `'text'`, `true`?

In these cases the `.toEqual` and the `.toBe` are equivalent, because the first thing they both check is if the values are strictly equal. So performance wise there is no difference. `.toEqual` just handles more cases if the strict equality fails on non-primatives.

Okay, so if it doesn't matter, then I can use either for primitives?

You can... but you shouldn't. The naming of them is close enough that the subtle difference between when one should be used over the other isn't intuitive or obvious. You should default to using `.toEqual` in all cases to prevent any confusion. For the same reason that I don't use `++x` or `x++` in my codebases. I don't want to assume that the person that wrote that line of code understands the subtle differences between `.toEqual` and `.toBe` or the very subtle differences between `Object.is` and `===`. It's much safer to always use `.toEqual` so anyone in the codebase will follow this same approach. I'd rather just avoid the issue. Plus, consistency matters.

But what if I actually do want to test if something is a reference?

Sure, here's that hypothetical, and where people might wrongfully tell you to use `.toBe`:

``````// Two players, both happen to have the same name and age
const player1 = { name: 'John', age: 25 };
const player2 = { name: 'John', age: 25 };
const players = [player1, player2];

function getFirstPlayer () {
return players[0];
}

test('getFirstPlayer', () => {
// USING TOBE
expect(getFirstPlayer())
.toBe(player1); // passes

expect(getFirstPlayer())
.not.toBe(player2); // passes

// USING TOEQUAL
expect(getFirstPlayer())
.toEqual(player1); // passes

expect(getFirstPlayer())
.not.toEqual(player2); // fails
});
``````

In this example we actually want to know if a value is a reference. In most cases we don't want that, but here we do. So using `.toBe` works, but it isn't obvious to others that we are using it to validate that something is a reference. So, even though the test passes, it's not really a good choice. We should make the intent of our code clear and obvious.

Here is a more obvious approach. (Note the use of `.toEqual`)

``````test('getFirstPlayer', () => {
const result = getFirstPlayer();

expect(result === player1)
.toEqual(true);

expect(result === player2)
.toEqual(false);
});
``````

Benefits of this approach:

1. Intent is obvious, and Obvious is always better. It is reasonable to expect other developers to be familiar with how `===` works and to understand we are purposefully checking if both variables reference the same value.
2. Consistency. Using `.toEqual` for this will match the rest of your tests. It should be the default choice when doing matchers.
3. Reduces reliance on assumptions. (Assuming everyone knows how `.toBe` works. Which they don't. I literally had to correct the stack overflow post after looking up the Jest source code).
4. Reduces need for communication. (Verifying that everyone knows how `.toBe`, and by extension, `Object.is` works.)

Ahh ok I get it. Reduce the cognitive overhead of choosing one over the other

Yes, `.toBe` is never required, while `.toEqual` often is. So use it by default in all cases and completely avoid `.toBe`.

Credits:

## Top comments (4)

Nikita

It's helped me! I didn't quite understand why i should use .toEqual if we have .toBe but now i do!
Thank you!

Evgeniy Troynov

According to the docs `toBe` is only for:

Use .toBe to compare primitive values or to check referential identity of object instances.

Why did you try to use it to compare objects?

The Jared Wilcurt

That is one of its uses. It just doesn't work how most people expect it to, which was the point of this article. To warn people to stop using `.toBe`.

TheHumbleSikh • Edited

Great post Jared. Really helpful to learn! :)