Testing React Applications, v2 Component Testing Q&A
This course is no longer being maintained. We recommend the testing section of the Intermediate React course instead. We now recommend you take the Intermediate React, v5 course.
Transcript from the "Component Testing Q&A" Lesson
>> So in some cases we don't have a submit button whenever user clicks on tab, you'll just submit the data to the backend. So how to test this particle functionality?
>> So, you do something like onblur or something?
>> So, I would do fireEvent.blur.
>> If we'll wait for some second, let say user is not typing in anything, uhu?
>> If you wait, yeah. So in that situation, you probably using a set timeout or something. So what I would recommend is just has this useFakeTimers method and then inside of your test you can say, just.runAllTimers.
[00:00:43] And then it'll just speed them all ahead. So if you're waiting a 300 millisecond, you don't actually have to wait that time in your test. If you don't want to do that cuz that is like technically that's mocking. I don't have a problem doing that but if there was a situation where you didn't need to wait for something then you can pull in wait or wait for element.
[00:01:03] And you can use those APIs, you check out the docs for those. They're pretty handy. Okay, yes?
>> Is there a way to check the state of a component? So after some event, you may be setting some internal state, you wanna ensure that that state is set.
>> Yes, I'm glad that you asked that.
[00:01:25] So, let me ask you a question. Why do you want to, can you give me an example of?
>> So, let's say when you click the button, you have a little spinner that comes up, cuz it could be a long API call or whatever. You want to insure that typically I guess we have you set the state is submitting that type of thing.
>> The react re-renders, you have a spinner component and then if its renders itself if it should or not.
>> Right, yeah, that's perfect, perfect question. So if you, whenever I ask myself, so how do I test this, I try to take a step back and think.
[00:02:04] If I were a manual tester, how would I test this? If I only had the interface, didn't have the depth tools, how would I do this. And I would click on the thing and then I would make an assertion. And I'd jot down okay yes, I see the loading spinner test path.
[00:02:17] So that's how I would test it. Rather than checking the internal state, I would say, I click the button and the loading spinner shows up so I'd verify that the loading spinner's there. And then you probably have that network request mocked out. And even if you don't, if it's like a full end to end test, you're gonna wait for that thing to go away, and then you'll make the rest of your assertions.
[00:02:38] And so you can do all of that with the react-testing-library, so the reason that I would avoid checking state is because yes, maybe you are setting, is submitting state properly but you could have. Like somebody goes and refactors the render method and it actually messes things up where it doesn't actually show the loading spinner anymore.
[00:03:00] So your test passes, but your application is busted. And so by testing it as close to the way that the user would test it, then you can avoid that. You get both the fact that the state is being set and the fact that it's being rendered properly. But the fact that state is being set is actually irrelevant to the test, cuz it doesn't really care.
[00:03:21] You could be using jQuery for all I care, it's like I don't really care how that happens. So just the fact that it does is what I want to verify. And that kind of harkens back to the implementation details versus testing the public API. And you can consider the dom that it renders, part of the public API.
[00:03:40] Great question, yeah.
>> Well, I just can say because if you're testing state then theoretically if you wanted to make sure that everything is working the way that you had hoped for to, you'd have to write more test for all the individual components. Whereas if you write, you're drawing a larger box around the problem and you're measuring the end result, that's just one single test.
[00:04:05] Any of the things that fed into that could break and you won't be able to detect it that way.
>> Exactly, yeah. Now there is something to be said for more specific unit tests because when those break, it's a lot easier to identify what it was that broke.
[00:04:20] And so, because if we were dogmatic about this and said, okay, only the way the user tests it, we just tested the high bird's eye level of everything, and just about anything could break those kinds of tests. And so that is why I don't do purely only end-to-end tests.
[00:04:39] Because they’re generally harder to debug in a lower level unit test. So there is a balance here. We try to avoid dogma in testing because it’s just a path to sadness. So I’m looking for that nice balance of I'm getting the confidence that I'm looking for, but I don't have to write like 30 tests just to make sure things are integrating together properly.
[00:05:05] Just maybe one test to make sure things integrate together properly, and then a bunch of other tests to test the edge cases. But even with those edge cases, I still wouldn't worry about testing internal state. Because in those situations, a refactor will break your test. Well, okay, I'm gonna change the name of this state that really doesn't change how the thing works, but if you're asserting on the instance state now, your tests are broken and that's kind of annoying.
[00:05:32] That's actually one of the reasons why a lot of people don't like testing in general, is because I refactored my code, and then a whole bunch of tests went red, and now I don't like testing. So tests that don't break when you refactor are pretty nice.