Why you should never use .toBe in Jest/Vitest
#9
TheJaredWilcurt
started this conversation in
Articles
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
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.Most do! And that right there is the problem. Here's the difference:
.toEqualworks based on deep equality.toBeis literally just doing aObject.is(x, y)under the hood. Which is slightly different, but basically the same asx === y.Here is an example where the two differ:
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.
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.In these cases the
.toEqualand the.toBeare equivalent, because the first thing they both check is if the values are strictly equal. So performance wise there is no difference..toEqualjust handles more cases if the strict equality fails on non-primatives.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
.toEqualin all cases to prevent any confusion. For the same reason that I don't use++xorx++in my codebases. I don't want to assume that the person that wrote that line of code understands the subtle differences between.toEqualand.toBeor the very subtle differences betweenObject.isand===. It's much safer to always use.toEqualso anyone in the codebase will follow this same approach. I'd rather just avoid the issue. Plus, consistency matters.Sure, here's that hypothetical, and where people might wrongfully tell you to use
.toBe: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
.toBeworks, 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)Benefits of this approach:
===works and to understand we are purposefully checking if both variables reference the same value..toEqualfor this will match the rest of your tests. It should be the default choice when doing matchers..toBeworks. Which they don't. I literally had to correct the stack overflow post after looking up the Jest source code)..toBe, and by extension,Object.isworks.)Yes,
.toBeis never required, while.toEqualoften is. So use it by default in all cases and completely avoid.toBe.If you want to enforce this with a linting rule, I made an ESLint plugin for this:
Credits:
All reactions