Check out a free preview of the full Intermediate React, v5 course

The "Snapshots" Lesson is part of the full, Intermediate React, v5 course featured in this preview video. Here's what you'd learn in this lesson:

Brian demonstrates snapshot tests and explains why they are low confidence, low cost ways of writing tests. A copy of the rendered markup is saved in a __snapshops__ directory. When the test is run again, the current markup is compared to the saved copy. If something has changed, the test fails.


Transcript from the "Snapshots" Lesson

>> I am not a fan of seeking 100% test coverage, cuz I think it's dumb. I think it's dumb, because for the most part, you don't need 100% test coverage. There's things that you just don't need to test. But if you want to, I'm gonna show you how to cheat.

There's a thing called snapshot testing, which in general, I think is a bad idea. But it's built into Vitest, it's built into Jest, and it's very easy. So snapshot testing, it's low effort, low confidence tests. So they're very easy to write, but they inspire very little confidence. So cheap tests that don't do much.

Now, you have to ask yourself, is that a good thing for me? Do I like that? For me personally, they're too noisy, and I also don't get very much value out of them. But I'm gonna show you how to write them nonetheless. So let's do it with Results.jsx.

I want you to create a file here, Results.test.jsx. Here, we're going to import expect, and test from vitest. And I'm going to import render from testing-library react And I'm going to import Results, From ../Results, okay? Test renders correctly with no pets, async function, doesn't have to be async, but I just make it async anyway.

Then we're gonna grab this thing out called asFragment, = render(<Results pets = empty array). Okay, and then we're gonna say, expect(asFragment), which is a function. And you're gonna call this magic function called toMatchSnapshot. Okay, what happened here? It just doesn't have any tests, which is fine. So if I save this, It's gonna say, hey, I wrote a new snapshot for you.

Then you can look in the snapshots directory up here, and you can see that it renders out this document fragment here of what this looks like rendered to HTML directly. And then now, every time that I run this, it's just going to compare this to what it was previously, right?

So it's gonna say, okay, this is what I saw last time, does this look exactly the same this time? So to prove my point here, let's look at Results. And I'm gonna put No Pets Found with a bunch of exclamation points, and I am gonna get a failing test, why?

Because before, it said No Pets Found, and now it says, No Pets Found!. Does exactly what it says it is like. I'm gonna take a frozen snapshot of this and then I'm going to compare this in the future that this is what I expect to see. Now what I can do here is, I can go and say, you know what, this is actually what I expect, right?

I want this to now match that, if I just hit you now, it's like, all right, you're the boss. I'm gonna tell you now that's what it's gonna look like in the future. So now if I open this again, Notice that it says it's okay, close this. Yeah, don't save, please refresh it.

And now if I say snapshot, you can see here now it actually says what I have here. Do you think that's useful? Maybe, sometimes. If you had something that truly you'd never really expected to change and for some reason it was changing underneath you, by all means, this could be a valid use case for that.

For me this is just testing that my UI is not changing and I also expect my UI to change. I used to write a lot of these so that I could get 100% test coverage. I don't think that's useful anymore, so I don't write very many of these.

The one thing I can show you here, let's go back, this is writing to match snapshot. If I put to match inline snapshot, now I'm gonna save this, it'll actually write this directly here if you don't wanna have a separate file, that's up to you, some people like that better, but that's totally up to you.

I wasn't gonna say about that. Yeah I don't write too many of these anymore, but I wanted to show you how to do it in case you wanted to know how to do it. Some people find that very useful. Snapshots is not just for react by the way, you can do with JSON, for example, right?

So if I have some JSON API response that I'm expecting to not change over time, I can just give it a JSON object instead of a document fragment, and that'll work as well. But as you can see, two lines here of testing stuff generates a test, some people are really into that, I'll leave that to your discretion.

So this is doing with no pets, if you wanna see what it looks like with pets, let's just go nab this, I have some sample data here that you can grab really quick. So let's go grab the sample data, I literally just took this directly from an API response.

There we go, grab an API response. We'll just say right here, blah equals blah. We'll have to import static router as well. So import StaticRouter from react-router-dom/server, okay. And then down here we'll write another test that looks relatively similar test renders correctly with some pets. And here you can say, const asFragment = render StaticRouter Results pets = pets.

And then, expect asFragment toMatchSnapshot. There you go. You'll see that it wrote a snapshot, we can go back and look at our snapshot file. And you can see here it's rendering out that, Luna rendered correctly with dog Coveny, Seattle, Washington, so on and so forth. So that's what that would look like.

Let me tell you my minor problem with this, what happens if I change something in pet? Let's just go do it, just for funsies. So I change these from m dashes to normal dashes or something like that, something really silly or I'll just put names like this. All right, so now my tests are gonna fail, and this is gonna fail because it says, Jacqueline and Lyda and Si and all those kinda things.

Which test is failing? The results test. Where's there the problem? The pet's component, the wrong test is failing, right? When I have a test fail, I wanna know exactly what's wrong. This one gives me some indirection of what has gone amiss, I don't like that, I want my test to be very specific of what I'm testing.

There's something you can do to get around this called shallow rendering, which we would have to go grab another library called react-test-renderer, and you can do a shallow render. So instead of actually rendering everything down to the pet level, it'll say basically, instead of that, It'll say that this is trying to render a pet with all the props, right?

I'm not gonna type out all the props, but it will actually give you the name of the react component as opposed to the actual full HTML. That's a bit better if you're gonna be doing lots of snapshot testing, I would suggest going to do that. I'll show you how to do that in v7, if you wanna do that, but I've decided to de-emphasize snapshot testing in this course because I don't think it's a good idea.

I want you to be aware of it, because you're definitely gonna come across at a company that does it, but use at your own peril. Does that make sense? Does this make sense? Okay, two things about snapshot test, you do check them in to get, some people are hesitant to do that, most people say, don't check in machine generated files.

These ones you do check in, right, because you wanna check them later, right? So it's important that you do check these into Git and never modify them directly, right? I think that makes sense, these should only ever be machine generated, please do not edit them by hand.
>> Craig online just said, I found that snapshot tests work well for API integration testing on a test API endpoint.

>> Yeah, no, I could buy that. To Craig's point, I believe that snapshot testing is a much better use case to making sure that your JSON response shapes are not changing between your client and your server. It's basically like you're giving a guarantee from the back end developer to the front end developer like a handshake agreement.

This is what this looks like, our tests are gonna fail if these drift apart. That is a super valid reason to use a snapshot test, and one that I've done before, so yes, I agree with that. But this is, It gets you towards 100% test coverage, right? So we're gonna look at test coverage here in just a second.

It's going to show results.jsx as being 100% test covered. What did we test? Nothing, right? That's why I don't like test coverage is because it doesn't really tell you anything. I could cover this entire application in five minutes with snapshot tests, it will show with 100% coverage and I would have 0% confidence in my tests, right?

Your test are only as useful as like how much effort and thought you put into them. Okay, that's enough for me on snapshots.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now