React July 2022 Meetup
"TDD in React" by Nik Krimm
Test-Driven Development (TDD) involves writing a failing test before writing the code to make it pass. TDD encourages simple designs and inspires confidence, as well as guiding you to more modular, flexible code. How does this technique apply to React, and what tooling is available? We’ll write a simple feature, test-first to demonstrate.
We are actively looking for speakers! Reach out
at [email protected] you would like to give a talk
Hey, I'm going to do a short talk on TV. I'm going to check my screens here real quick. Okay, great. You said that stands for Pet driven Development. Testing is a big and broad topic and we have a short talk. I'm really going to focus on that. First deep test driven development. What does that mean? Tech first development. This strategy where you are going to, before you write code, write a test that expresses the feature you want to have. Then write the smallest amount of code you possibly can to satisfy that feature. Rinse, repeat, repeat until you built a substantial feature, constantly stopping in a green state or a red state. Writing a test passing. Writing a test passing lets you do less design upfront and gives you points where you can stop reorganize your code safely and know that you can down the working state of the application. For me, it was an awkward way to get started. But at this point I tried to do all development this way. Start with a test that describes the world that I want to live in, then build the world, right? And today we're going to build a real fancy one. I want to introduce you guys to this app here. You probably have seen it around somewhere recently. And I have in this other tab loaded up Create React app. And I cheated a little bit by copying some styles over this directory. But otherwise it's just the Create React app and we're going to start to build this other one. Let's see what we have over here. I have a couple of terminal windows open. I have the application running in this terminal. I have this one open to start in just a moment. And then I have this guy open. It needs to be balanced, but has my code in it. Give me just a second here. Is this still big enough to read here? Go ahead. At the very beginning, before I do anything else, I'm going to just run the test week. If I do Create React app, it actually comes with a passing test, which is exciting. This says that it renders the Learn React link. And if we go over and look at the application, this is accurate. It does render it. So this is a great starting point. There's all these different ways to filter and look at different sets of tests that could choose ones that have certain names or certain file names. But if I only have one, I'm not going to be able to demo that for you. So this pointing is out here. The first thing we're going to do is I'm going over here to my test file. Let me point out a feature. One of the features I noticed on this app is that it says, Hello React. I'm going to try to duplicate that feature first. This is a small feature, but let's see how this works. I want to say render reading. Hello. I'm going to type for a minute. I know, I'll explain. Hey, I'm going pretty quick again. What I want to focus on is the deep test driven development. I'm not going to talk a ton about the React testing library, but just so we're in context, I'm going to read out this out a little bit. The first thing I'm going to do is beginning to test render the app. I have a real simple app. I really only have one component at this point. That's what I render. I've imported from my testing library entity called Screen, which gives me a bunch of selectors so I can select different things in the application. And then I have an assertion that I believe that this entity, that a graph heater, should exist as a document. This test is on watch. So when I switch the tab, the test will have run. What will have happened? Failed. That's awful tech. Okay, so I got my first failure. I've started by writing a description of what I want the world to be like. I want this to say hello. React chicago. And it does not test. Doesn't say it does. I don't even look at the browser yet. I know it doesn't work. I've got a failure. Hey, where's it failing? I'm going to go up my screen, and it's failing. I can't find this text. Hello, Chicago. That makes sense. And then this testing framework also gives us a nice print out of the Dow so I don't have to flip back and forth. I can scroll down to see if it doesn't work. Okay, what was the second part of this test driven development? We write a picture of the world we want, and then we do the simplest possible thing we can do to get it to pass. So I'm literally just going to type hello. React chicago. No idea. Okay, this is super valuable test. It's not a super valuable test, but we have started describing what we want the application to look like. We have a running test suite, and we have a groundwork to start building more interesting things on. Hey, what's another feature that I noticed? I'm my own magician's assistant here. I noticed that it's a dark mode, and there's an app to turn it on. Hey, let's build that page. The first one, I'm going to say it renders the application in dark mode by default. And again, I'm going to render the app. That's where I'm going to start. And then I want to nothing exists for this yet at this point in time, when I'm writing the test is when I'm thinking through how do I actually want it to work? This is a paradigm shift for me to write it in the task first rather than an application. That's what the D is about. That's what they're talking about, right? What I want to happen is I want the main container to have a class called that's how this is going to be implemented. And so the first thing I'm going to do is I'm going to create a reference to application container and I'm going to say screen get by testid. I'm going to talk about this too. App container. And I expect that my app container when I've gotten this all working to have class of I apologize for my misbehaving autocomplete here. My puppy does the same thing. Shows up when I don't want them. Okay? So hey, this is what I want to happen. I want to have a thing called an app container. And when the application starts up, I want it to be dark. If I flip over to test right now, it's going to happen. Billy anybody guess what? What I really like about this React test framework is that it stops exactly where the error is. So I'm actually going to proceed to this test line by line. I'm going to be test driven, but line by line, we're going to fill it in. So I need something that has a test ID of app container. Why test ID? I'm going to give my main note this, and I'm going to talk about test ID. And there's a whole bunch of ways to grab elements on the page. And the React testing framework wants you to look at the page of the user looks at it. So this is the preferred method, what a user would see. Grab that. But if you are dropping down to talk about attributes on HTML elements or React components, whatever you want to call these, if you attach your selectors to classes, then you're at risk when you change your CSS. We ran your CSS test break. You want to set a couple. Now if you're looking at other HTML attributes, they all have other responsibilities. So React testing framework actually gives some preference to this idea of using a testid. We can grab a test ID. We can tag any node we want with this, and we change our application structure. We can move that test ID somewhere else without having other side effects. Now I have an app container. Is my test work? I went down a lot. Now this one passes. It can't grab the app container, but it doesn't have the class dark mode. Hey, what's the simplest thing I could do to make this test work? Really? I was going to type dark mode. Did Dan did you say that too? Okay, again. Hey, this is an interesting test in this district. No, but now we have a baseline. The next feature I want to talk to you guys about is this one. I can toggle dark. And now we're talking about application functionality. We're going to write some tests for that as well. But we have this incremental build. We know how the application works as we start moving code around. As we start building on it just says Dark code. So it actually can turn dark mode on and off. We're building with a small step that's guided by our tests. And you guys are super bored right now. This is the last test I'm writing, but it's the most thrilling. This is the third act. Okay. So user can toggle here. I'm going to render my app and then in this case, what I want to say to be some kind of Toggle target. You guys who have written this code before, this is such an inversion of the paradigm. I'm starting with the idea that eventually I'm going to document that I want to have a toggle target. I don't have anything up here. It's called dark mode. And I'm going to add another thing to my imports here because I have moved to the point of just checking stuff to interacting with it. This testing library is going to give me a fire event entity as well. And here I'm going to fire an event. I'll click at my toggle target. Then what do I expect to happen? I expect my container not to have the class. Does it make sense to everybody? Yes. Thank you for joining. I appreciate it. And then what's going to happen if I go to my test? I'm going to fail here. Okay, but now can I just type dark mode and make this test pass now? No. Just for those dial. I'm going to give this clients name and I'm going to create a label. Type equals checkbox. If I switch over to my test, I see that I have something called dark mode. I can fire an event at it. Fantastic. But my app container, I don't have any reference map context. I've failed to create a reference here. I'm going to fix this. Just voicing this guy up here. Okay, now I have an app container and I expected to not have this class coming faster. Hey, at this point, I need to add some states to this application. Okay, thank you. Are you ready? And I'm going to create a little bit of dark mode. And this attribute is true earlier in a test, I'm going to have to come down here to my check box. I'm going to cause it to do something on change again. My goal is I want to toggle dark mode. Toggle dark mode. Right. This one's. In this case, I'll be passing event. And this function is event target, check driver. So what's going to happen now? That's really good. It took me a little bit of time to figure that out and I'm a little disappointed you got it so fast. Okay, let me get back here. So when we load the app, even though we think it's in, let me show this test that's what this is about. Okay, so I fail. I'm not in dark mode. And what I notice is what this gentleman just pointed out when I go back to look at my app. Hey, this is working as not even working as expected. It's even worse than I thought. And so we have to do a couple of things here. We have to let the class name be updated. I still have a hard coded dark mode. I'm going to make a little function that says const app, container classes. And I want it to say app. And then if dark mode is true, I'm going to give my class dark mode. Otherwise. Now I have an array with these potentially two things in it. I'm going to join up with this space. Oh, man. And I'm going to return it. Okay. And then having to replace this guy. And now I think I'm where I was at before. Okay. Hey, what's going to happen now? Hang on. Really? Sure. Okay. But now I have the checkboxes working. Do you know what's missing right now? That's right when I click the test, clicks it, but puts it in this state. So I'm going to fix this by giving my initial state down here it as checks. And what do you think? Container is not a function. I'm going to just Julia job the rest of this guy and show like, hey, I did all the work presentation to write all of these tests. Hey, describe all of the features. I built it up the same way, a little at a time. Understanding what happened every time I recite. And the reason I get really excited about this is this is still not perfect code. But the code gives me all this opportunity to be back to restructure and move parts of my code around, change my approaches while still feeling really confident. It works. Everything that I've done so far still says react, welcome, react group. It still does dark mode, et cetera. Okay. Do I have another thing for this? Hey, again, abruptly, am I talking questions? Yes. Was that the question? Yeah. Why is it like that? I was just going too fast. Any other questions? Got it. Yes. In a nontrivial application, I would write test perfect home. And I might have some, especially if I have global states that I might have some tests, a test at a high level, but most of the times I want to test it at the lowest possible level at a component. Any other questions? Persistent.