Check out a free preview of the full Testing Fundamentals course
The "Referential Equality" Lesson is part of the full, Testing Fundamentals course featured in this preview video. Here's what you'd learn in this lesson:
Steve explains the options for testing equality. Functions like toBe, toEqual, and toStrictlyEqual behave differently depending on the data type in the comparison. Other functions can provide more flexible comparisons by only checking if properties are contained on a datatype.
Transcript from the "Referential Equality" Lesson
[00:00:00]
>> Steve Kinney: We need to talk about equality in terms of JavaScript, which is, I think a lot of the things that we we know from, React and it's siblings, all the front end frameworks, honestly, is this idea of replacing objects in immutable state and all those kinds of things, right?
[00:00:19]
And so a lot of times in something like React, we want the next version of the object to be different than the last version 'cause that's how we trigger a re-render. But that can become slightly problematic when we are trying to test stuff, right? Which is, we've stayed with mostly simple values so far.
[00:00:41]
Two plus two should be four, right? And in memory, there is one number four, right? If you make a string of the word four, there's one of those in memory. So if you take any given string of F-O-U-R and any other one of the same letters, that's the same one in memory.
[00:00:58]
So they are equal. You can put three triple equals signs in there, life is good, right? Well, one triple equals sign, or three single equal signs, your choice, three, triple, if you put nine equals in a row, I don't know what happens, and like that works. Where it falls apart is that that doesn't work for objects, right?
[00:01:17]
Including arrays, so on and so forth. Which is two arrays with the exact same contents are not triple equal to each other, right? Two objects with exact same keys and values are not equal to each other, right? Which is, again, I understand those methods at the bottom of the screen where I'm like, they're not equal to each other.
[00:01:36]
So we have to use something called two equal I don't make the rules here, I just explain them, okay? Naming things is hard. So, when we look at something like 2b that is literally, is this the exact same object? Which means that if you took an object and had a function that mutated it and then did a 2b it would be the test would pass, right?
[00:02:00]
But if you returned a brand new object with the same properties, it would not, right? And so in those cases, we have to swap out for one of these two other methods on expect that handle those cases. One I use all the time, the other I don't really use.
[00:02:19]
But, I'm here to show them to you. So we're gonna take a look real quick at this set of tests right here that kind of these will all pass. And so we can go over here and just run them to validate that that are not lying to you.
[00:02:36]
They all pass, which will kind of show us some of the differences, and we'll make them not pass and pass a few more times. So you can see instead of tobe, I'm using toequal, right? And in this case, if we did to be, it will fail, right? Cuz this object and this object are different objects in memory, even though they look and feel the exact same to us, right?
[00:03:01]
And the nice part is Vita is not gonna make your test pass, or V test or Jest or whatever. They're not gonna make your test pass, per se, but they kind of know what happened, right? And so at the very least, you will get at a failing error message, which is like, it seems like you might have just used the wrong one here.
[00:03:26]
Which is nice because I don't wanna talk about the times that I lost an hour or two of my life cuz I forgot. And cuz it's like they JSON serialize the same string, they were probably the same, but they're not effectively. And you don't necessarily want your test suite guessing for you, right?
[00:03:45]
It can suggest things to you, but you probably don't want it guessing. So, if we use to equal, you'll see that it will pass, right? And as a fun bonus, you'll notice that, there's another little helper that you can use. In this case, the .not, right, which is you're kinda expecting it to be the opposite of it.
[00:04:09]
Honestly, the time that I use that the most is I might choose to have a test where it expect whatever not to throw, right? Now, if it's throws, it will also like failure test, but you can kind of like if you do need the opposite, that can happen as well.
[00:04:28]
The other one that again I can't wholeheartedly recommend, but my job sometimes is to just show you everything and you decide what you wanna do with your life, is you can also write test.fails. And that will kinda flip the entire thing inside out, right? So, now we expect this test to fail.
[00:04:46]
Nobody needs that in their life. That is useful for when you think you might have a false positive or something like that. I would not leave that, I would not commit that, you know what I mean? That is when you need a sanity check to like, is this passing because it's supposed to pass or I wanna see a failure message so I can verify that everything is working the way I think it does, then I think it makes a lot more sense.
[00:05:09]
But I can't necessarily recommend it as something you commit in there. You could argue the same thing for .todo unless like you do intend on doing it. Because what nobody needs is a code base full of tests that say all that .todo on it. Could you set up ESLint rules that don't allow you to at least commit a .skip, or a .todo?
[00:05:31]
Cuz you could also accidentally skip tests that you meant to have in there because you were triaging and debugging. Ask me how I know that.
>> Student: [LAUGH]
>> Steve Kinney: Anyway, these tests all passed because they're just here to demonstrate how these things work. And you'll notice on the Vest Jest thing, you'll even notice that like, VS Code is even actually filling in thinking this is Jest expectation.
[00:05:54]
So, if you needed proof that most of this stuff will work in Jest just as well, VS Code thinks I'm using Jest right now. So we've got that in place, so we can see that to be they would not be equal, but to equal, what it does is basically, if it's an object or in this array.
[00:06:09]
It goes through all of the values, and it's basically saying, hey, okay, go through all the keys for each key that's the same. Make sure the value is the same. It's basically iterating down until it gets those primitive values, and if one of them doesn't match, then they're not to equal, right?
[00:06:26]
And the difference between two equal and two strict equal is like, for instance, someone mentioned TypeScript earlier. TypeScript is super cool as a type system, because, let's say you have an object that has A is 1, B is 2, C is 3, right? And your type necessitates A as a number, as B as a number.
[00:06:47]
You could have extra properties, typescripts, like, since we're not touching them, it's fine, right? That is true for to equal, but if you really want to say, like, strictly no, are they exactly the same? Right, then you could use toStrictEqual. 99.999% of the time, I will likely just go with this one.
[00:07:09]
In the use case, you truly want to make sure that there is not something undefined or something like that that you're not using. Because this one is basically saying A is 1. This one has A, and it also has this extra B on it. That's fine with toEqual, we don't really care as long as we have all the properties we want.
[00:07:26]
But if you truly want to make sure that there is no extra properties, and it doesn't necessarily have to even be undefined or anything along those lines, but toStrictEqual will absolutely verify it. Same thing here, which is, it also needs to be an instance of the same object.
[00:07:42]
So this person that we have up here has a name property. It's effectively the same. It's got a different prototype, however. They are equal but they're not toStrictEqual. And a lot of times like if I'm testing a constructor or something like that, I just wanna make sure the property is the same.
[00:08:00]
I don't don't necessarily care. I don't wanna make a second person object, so on and so forth. This most part does what I want. The important part here is that to be and to equal serve very different purposes. To be for primitive values, to equal for any kind of array or object.
[00:08:17]
Strict equals there for the, if you feel like you need For some particular use case, I don't.
Learn Straight from the Experts Who Shape the Modern Web
- In-depth Courses
- Industry Leading Experts
- Learning Paths
- Live Interactive Workshops