Designing Effective Tests With React Testing Library

Rate this content
Bookmark

React Testing Library is a great framework for React component tests because there are a lot of questions it answers for you, so you don’t need to worry about those questions. But that doesn’t mean testing is easy. There are still a lot of questions you have to figure out for yourself: How many component tests should you write vs end-to-end tests or lower-level unit tests? How can you test a certain line of code that is tricky to test? And what in the world are you supposed to do about that persistent act() warning?


In this three-hour workshop we’ll introduce React Testing Library along with a mental model for how to think about designing your component tests. This mental model will help you see how to test each bit of logic, whether or not to mock dependencies, and will help improve the design of your components. You’ll walk away with the tools, techniques, and principles you need to implement low-cost, high-value component tests.


Table of contents

- The different kinds of React application tests, and where component tests fit in

- A mental model for thinking about the inputs and outputs of the components you test

- Options for selecting DOM elements to verify and interact with them

- The value of mocks and why they shouldn’t be avoided

- The challenges with asynchrony in RTL tests and how to handle them


Prerequisites

- Familiarity with building applications with React

- Basic experience writing automated tests with Jest or another unit testing framework

- You do not need any experience with React Testing Library

- Machine setup: Node LTS, Yarn

151 min
14 Jun, 2023

Comments

Sign in or register to post your comment.

AI Generated Video Summary

In this Workshop, the speaker covers various topics related to testing React components. They discuss the importance of testing the contract, behavior, and inputs/outputs of components. The use of React Testing Library and Jest module mocks is highlighted. The speaker also emphasizes the significance of testing user interaction events and external functions. Different testing approaches, best practices, and trade-offs are explored throughout the Workshop.

1. Introduction and Workshop Overview

Short description:

In this first part, Josh introduces himself and his experience as a software developer. He also mentions his book on test driven development and provides information on how to get a discount. Josh works at Test Double and encourages participants to ask questions during the workshop. He covers the topics that will be discussed and invites participants to join the Discord community for further discussion.

So with that let's jump in. My name is Josh, as Mike said. You can reach me online at codingitwrong.com. And I like to say that after the workshop you will be able to decide for yourself if I am coding it wrong, and it's okay if you decide that. So a little bit about why I think it's okay to spend a little time listening to me. And you might consider the things that I'm saying.

So I've presented some of this testing information in a few different places. So I've been a professional software developer since 2004, worked across back end web, front end web, and mobile as well, including react and React Native. So I got the chance from React Advanced London to do similar workshops to this one last year. Also at Chain React this year, I did a React Native testing workshop. A lot of the approaches on React Native are similar. And at React Native EU, I gave a talk on test driven development. And I really appreciate Git Nation and React Summit for giving me the opportunity to be here again today.

I have a book on test driven development. And so today, we're focused on testing in general, not test driven development in particular. That's a particular testing approach. But if you're interested in the kind of philosophies and the things we talk about today, I think you'd enjoy the book. It's sort of an extension. And test driven development is a way to get yourself into the mindset of testing that we're going to be describing today. I have a link specific to React Summit to get $10 off the eBook. Amazon doesn't let me do that. So you can get the paperbook on Amazon. But that will be full price. And there's free sample chapters as well. And so if you want to check those out first, those might be helpful to you. And you can see if you like the book. That is available on the conference workshop webpage as well.

I work at Test Double. Software consultancy. And the reason I get to work on fun stuff like doing this workshop is because it's a great that gives me fun stuff to do at work. And gives me work-life balance to do on the side. We love to join existing teams and to help them. And so if you would like someone to join your React team to help with testing, or other project or process challenges, we would love to talk to you. You can go to testdouble.com. And that link is on the workshop webpage as well. So thanks to Test Double.

Today in the workshop we're gonna cover the React testing library. As well as associated library user event, part of the same family. And JestDOM, to make easier simpler assertions. I want to encourage you all to ask questions all through the workshop. You can ask questions in the Zoom chat, if you'd prefer, to type them in. You can also unmute and ask over audio. Or whether your video is on or not. Ask questions any way you like. It's a great way to make sure I'm providing something helpful. If you have a question, somebody else on the workshop does, as well. I'll do my best. I have the chat in front of me. If I miss your question, I'm gonna try during the breaks to go back and look at them. Feel free to answer each other's questions in the Zoom chat. If I miss it. And share your own thoughts. We're all learning from each other. Afterwards, this conference workshop webpage will stay up indefinitely. You can refer back to it. If you're watching the recording of this workshop later, check out that website. There's a link to a Discord community there that I have for my React and React Native and testing content. So you can jump in there to ask me more questions. I love talking about testing stuff. Feel free to reach out any time.

2. Encouragement to Decide and Apply

Short description:

Testing is complex and there are different views and challenges. It's important to learn and try different testing approaches to find what works for you and your organization. Don't blindly follow absolute statements about testing. Apply your own perspective.

Another thing that I want to say, kind of the last thing before we get started. I want to encourage you when it comes to testing to decide for yourself. I feel like after focusing, kind of specialized on testing for years and years, that testing is irreducibly complex. You don't get to the point where it's like, oh, here's three simple things to do for testing and you don't have to think anymore. There's always challenges to go through. I'm applying these React Testing Library approaches on my current client project and we have challenges every day and every week. And there are different views of testing with different trade-offs. So I would encourage you, learn what we're going to be talking about today. Learn different views on testing. Try them out and decide what works for you and for your organization. I would say when someone makes a very absolute statement about testing, take it with a grain of salt. It's likely a helpful thing. But things are probably more complicated than you might think at first glance. So I just want to invite you to apply your own view as we talk about testing together today.

3. Introduction to React Component Testing

Short description:

To get started, we'll discuss the simplest aspect of testing React Components, which is rendering. We'll focus on React's testing library, the most popular component testing library for React. The workshop will cover both the use of this specific tool and general frontend testing philosophies. Learning testing approaches takes effort, but it will benefit your career in any technology.

All right. So to get started, we're going to talk about the simplest aspect of testing React Components. Which is rendering. To get into it first, I want to talk about what a component test is. Because there's many, many different types of automated tests in software, and even within React Web Application testing, there's multiple approaches.

You might have unit tests. Well, that word is used in many different ways, but a lot of times a term unit test refers to very low-level tests. Maybe it's just a vanilla JavaScript function. You're not using React at all. It's just passing data in and responding data out. Those are really valuable. Maybe you have end-to-end tests. This is tests where your whole running React application, maybe even by itself, or maybe connecting to backend services, maybe multiple backend services that are all being tested together. The term end-to-end testing tends to be used for that kind of testing. Component test is specifically a term referred to testing React components. It lets you render a component, configure it with wrapping things and pass props to it just like you do in production code, and it lets you interact with that component.

In the workshop today, we're going to be focused on React's testing library. It's certainly the most popular component testing library for React. You've probably heard about it before. And whether you have or not, this will be a good introduction to it today. The npm package name is testing library slash React. And testing library.com is the website. They have libraries for many different frontend frameworks. So if you work in Vue or Solid or other frameworks as well or React Native, as I mentioned, there are similar testing frameworks. And that's another important point to make. I'm going to be talking in this workshop half about the use of this specific tool. But half about general frontend testing philosophies. And so even if you're working in another framework or another tool in the future, the mental mindset we're talking about for designing effective React testing library tests is gonna go with you and pay dividends whatever technology you work on in the future. So learning testing approaches takes some effort. But just be encouraged that that effort will continue to go with you wherever you go in your career.

4. Testing the Contract of React Components

Short description:

We will be focusing on testing the contract of React components, which involves thinking about inputs and outputs. Props and user interaction events are common inputs, while the rendered UI and calls to external functions are outputs. We will go through each of these in detail, starting with the rendered UI. I will provide an example codebase for demonstration purposes. Please note that it is different from the exercises repository we will be using later. If you need the text to be bigger, let me know in the Zoom chat. You can find the link to the workshop homepage in the Zoom chat as well.

So we've got a testing library. The first thing that comes to mind is what do we test? What is it that is being tested in components? And over the years as React testing approaches have changed, questions have come up. React when we had well, you might still have React class components. That's fine. This testing library works. But when all we had were class components in React, those classes had methods. All right, can I call that method? Should I call that method in my test? Or even in a React hook's world, there are functions inside of my component. Like event handler functions. Can I call those functions? I need to execute that. I need to run it. Also you're probably storing state in some form or another. Maybe in React use state. Maybe in a third party state library. So can I check that the state of my components is being updated appropriately and properly based on the actions I'm doing? So these are very obvious approaches that you might take for testing. But I and many of us would really encourage a different way of thinking. I'm going to appeal to authority here. Here's a tweet from Dan Abramov, well known on the React core team. Back from 2019. And he said we don't encourage reading implementation details like state variables themselves. Instead, test observable behavior. For example, what your component renders or does. A term you could use for this idea is testing the contract. And this is the term we're going to be spending the whole three hours on together today. So here's a quote from a different author. This is actually from book testing view JS applications. But as I said, these principles apply to any framework. David Yarbrough said a component contract is the agreement between the component and the rest of the application. Going further he says other components can assume the component will fulfill its contractual agreement and produce the agreed output if it's provided the correct input. So testing the contract is all about inputs and outputs. It's all about thinking about a component in terms of I'm not focusing on what's happening inside. I'm focusing on what's going in and what's coming out. That's a common way of approaching lower level testing in general.

So here's a question and I want to throw this out to you to answer. If you like you can unmute and answer, or you can answer in the zoom chat. When you think about the inputs and outputs that a React component has what are the kinds of inputs and outputs? So go ahead and share your thoughts out loud or in the zoom chat. What are some of the kinds of inputs and outputs that components have? Jory says props and hook states. Yes, props. These are all good answers. Props definitely. Hooks get complicated. So we'll get into that in the latter part of three hours. There's several ways in which hooks and their values and things can apply. But if you're getting state variables from a hook that is an input to your component. Let's see here, I've got a number of different answers. Wow, thank you for your answers. I've got to scroll up to see them. Clicks, yeah, user interactions. Oftentimes people don't think about those as inputs. But yes, that is a super essential part of the inputs. Input fields, text coming in, timers. Oh, yeah, that's tricky. We're not going to explicitly get to that one. But let's talk in the Discord later if you have thoughts on that. JSX elements is outputted from the component to the screen. Context is a more complex way that data gets to your screen. Output is the HTML part, yep. Params, focus and hover. That's a great point because that's some of the more complex user interactions that you wouldn't think of always, right from the back. The component receives callbacks when those get called. You are hitting more of the inputs than most of the workshops I've been at on this, so great job. Query parameters as well. I'm sure there are more that I haven't thought of. But yeah, thank you for those ideas. Here's the key ones that I summarized and that we're going to be focusing on together today. I would point first to props as an input to the component, and user interaction events. As I mentioned a minute ago, oftentimes folks don't think of those as inputs because it's not programming input, but a user interacts and that call to a function makes it as an input into your component with text that they typed or a coordinate they flipped. A focus and hover, even. Outputs are the rendered UI is an output from your component. And also calls to external functions, whether it's a function in another module or ultimately calling out to a web service, those are outputs from your component as well. The additional things you said fall in the categories. This list of inputs and outputs is going to form the structure of what we walk through today and we're going to go through one at a time. Out of order, actually, because inputs and outputs made sense to me in the order, but as far as writing the tests, showing the rendered UI first is going to make the most sense. So, let's focus on rendered UI and go to the code.

So, what I've confused my attendees before. I'm going to show you some code in just an example codebase. This is not the same as the exercises repository you have. We're going to get to the exercises a little bit later. It's very similar, but just know, if you're looking at that code checked out locally, you won't see the same files I have here. We'll get back to that. All right. So, here we have a, that is the exercises there. Let's get the lecture sandbox and so, I've tried to make the text big enough in the editor here. I'm sorry the text in the editor and the text in my terminal here is hopefully big enough. If you'd like the text to be bigger, let me know in the Zoom chat and I'll Zoom it up for you. All right. I got to get my notes up here. Yes, Bruno, is there a project to clone? Let me place that in here. So, that is the link to the workshop homepage. I put this in the Zoom chat and from there, you can get to the exercises project to pull it down. Cool.

5. Testing the Display of Welcome Message

Short description:

In this part, we start with a simple display-only component called hello. We test the text being rendered using the React Testing Library's render function. By adding an assertion with the expect function, we confirm that the welcome message is displayed. We discuss the importance of testing the behavior of the component and break the code to ensure that the test fails when the component is broken. We then fix the code and verify that the test passes again. We also mention that the getByText function in React Testing Library doesn't match substrings by default, but can be used with regular expressions for substring matching behavior.

All right. Thanks, Tor. If several people say it could be smaller, I will bump it down. All right. And I got to hide the participants list here. Give me a minute to get organized. So, we're starting out. We'll start with just as simple as possible. Well, I guess I added a few more images in here. But just a simple display-only component. This is a hello component. It renders out a hello-world message. And then it actually pulls in a squirrel image and a waving-hand SVG, just to greet people in a very multimedia way.

And so, we're going to look at – you know, this component doesn't have any logic. It's just rendering things out. But we're going to look at how to test to confirm that it's working. And I do need to show you the squirrel, because when I found it I just got so excited. Here's the squirrel image. This makes me very happy to be here. How do you capture a squirrel that's that happy? I don't think it was made by an AI or anything like that. I think it's a real squirrel. Anyways, so we want to make sure – we love that squirrel image so much. We want to make sure we're greeting our users with the squirrel image. So, let's jump in.

So, first, let's test the text that's being rendered. If you write boring utility apps like me, checking for text is going to be by far the most common thing you do. So, we're in a hello spec file here. React testing library usually runs through jest, a test runner, very well adopted in the React world. So, to test the hello component, usually I have one test file per component. That matching usually works really well. And I'm going to create a test. I'm going to say it displays the welcome message. That's the first thing we want to test for. So, in the React testing library, the render function is your friend. This is how you render out a component. And in here, you can type out the same JSX you type in your production code, including passing props, as we'll see in a little bit, in the same way. It makes very readable tests. So, if I add this to render out the hello message, and I save, and the test now runs and passes. Before that, I think it was just saying, it was saying you don't have any tests in your file. So, that's fine. So, when I add that test in and I do rendering out, the test passes. So, so far, this confirms that the component doesn't crash. And that's good. That's something rather than nothing. And I have seen tests like that in code bases. But usually when you're thinking about testing the contract, you want to think about, what does the user see? It's not enough for the user. If your components don't crash, they want to actually be given something that is useful. And in this case, we want to confirm that we're displaying the welcome message. So, the way we can do that is by adding an assertion. In Jest, you say expect. And then in here, you pass something that you're checking against. Now, we use another API provided by React Testing library called Screen. This allows you to look for various different things on the screen, which is to say, on the web page. So, first going to use... You see if you've got autocomplete, even if you're not using Visual Studio Code, you get API and there's lots and lots of different ways to get things on the screen. After this first segment, we're going to talk more about the different options that are available to you. But getByText is one of the most basic ones. And you can say, I want to look for Hello World. And then what do I want to confirm? I want to expect to be visible. That message should be visible on the page. So, now I'm going to save again. And the test runs, and it passes. So, one of the big meta principles I want to get across to you is, if you're writing your test after you write your production code and they pass, be nervous! Don't believe it, because you don't know yet if you're really confirming that the behavior works. It's important to go back and break your production code to make sure that the test will fail if something is broken in your production code. A way that I hear it said is, make sure you've seen every test fail. Because if you haven't seen it fail, you don't know if it actually is going to fail. Or if you get a false positive, a test that passes even if the component is broken. So, let's go and break our code here. We'll say goodbye world. A little morbid. So, when I save this, I break my component so it's no longer giving the hello message. I get some errors here. And it's a little verbose in my big text size, so let me scroll up. So, it says, unable to find an element with the text hello world. And it gives you a few tips on that. And then React testing library will render out the JSX of your component here. And so, you can see the goodbye world and an image in SVG is rendered out. And we can see from this helpful error output, I see. I said goodbye instead of hello. And so, I can fix it from there. So, we have now seen the test fail, so we know it will really protect us. So, now we can go back to hello world, fix it again, and we're good to go. A few notes about get by text. By default, it doesn't match substrings. If I look for hello, it will fail. I can't find an element with the text, hello, but it shows the hello world. It's not matching substrings. If you want substring matching behavior, you can use JavaScript regular expressions. This just means a string that contains hello. If you search for that, it is going to pass.

6. Testing Visibility and Accessibility

Short description:

The React testing library allows testing the visibility and presence of elements. It encourages accessibility by ensuring text equivalents for elements. The library also supports testing images by checking the alt prop. The speaker answers questions about testing static components, language translations, and SVG files. The benefits of test-driven development are highlighted, and getter functions like getByText and getByTitle are explained.

It's going to match substrings. Yeah, Bruno asked what if it was display none? 2Bvisible confirms a few things about visibility, including display, including opacity, as well. The React testing library docs have information on that. But 2Bvisible is helpful. There's a less rigid one called 2B in the document that we will look at in a minute. And my autocomplete here might help. Check it out. It says element is visible if it does not have the CSS property display set to none. 2Bvisible adds some extra realism checks there to make sure. Usually I don't have elements that I'm setting display none or opacity on. But I like to use the 2Bvisible matcher just for the extra assurance, the extra realism of what a user would see. Cool. So let's move on from there. So now let's talk about, yeah, testing things that aren't text. For example, the squirrel photo. I don't know. I guess you could write a test library and look for that on the page but that's a little challenging. So it turns out, one of the great things about React test library is it encourages accessibility, which is to say a web application that's usable by any users, visually impaired users using screen readers, motor skill impaired users and things like that. One of the things that React testing library encourages you to do is have a text equivalent for all the elements that you're asserting against on your page. So by writing a test to make sure the squirrel appears, we're actually going to make sure this is more accessible as well. Now you may have noticed this annoying yellow outline in my editor. If I hover over this, we actually, the JSX accessibility ESLint plugin that's in a lot of React steps by default says, image elements must have an alt prop. Since way back in my old school days of the web, yes, it's a good idea to have an alt prop describing an image. So we're going to fix that for the sake of ESLint anyway. But with this, we're going to be able to assert against it. So that's going to help. So let's add that. Displays the squirrel photo. We're going to render hello again. And we're going to say, expect screen get by alt text squirrel waving to be visible. So this make sure that the squirrel is present. Let's break this to make sure. If it was a fox waving, will the test fail? Yes, it will. Unable to find the element with the alt text squirrel waving. And we can see that it says fox waving. So we can fix that. That's a way to confirm the present of images. Yes. Oh, Elena asks a great question. I understand this is a study case. What do you think should the developer test things like this that are just statically present? And no logic around it. That is a great question. And I wouldn't, you know, if I had a static component here that always renders out certain content, like I wouldn't necessarily write a test for it. You might decide as a team that you want to test for every single component just to make sure you're checking something. But much more commonly, it's logic, it's behavior that I would test against. So if the hello message is sometimes there and sometimes not, I would write a test that is present in one case and absent in another case. So that's a great question. Cool. Another question, language translations, how to deal with that? That's a great question as well. I think there's different ways to set up GEST so that it's either using your internationalization translation library or not. And so depending on how you set it up, you can set it up so that your primary language shows up in there, so it's German or it's French or it's English and shows up in the tests. And you just write your test against that one language. So I think some internationalization libraries will set it up so that you can just render out the key. So then your tests would just have the key name of your text instead of any particular language and there's some minor trade-offs between that, but in general, I would not write the full coverage of all your tests in all your different languages, maybe just one test to make sure that each of your translations are working or something like that. I split the VS Code view so we see the component in the test code at the same time. Yes, I will do that. This is actually subline text, but I'm going to, let's see here, file, create 2, below. Yeah, there we go. All right, cool. I'm going to keep going. It seems like you all are answering some of each other's questions in the chat, and so that's really great. Thank you for that, so we can kind of stay time efficient. Let's do SVG files real quick. I'm sure there's multiple ways to use SVG files in React. I'm importing it here as a component and using it as a React component. I think this sandbox is created with create-react-app, which is not so much in use now, but you can see how they have SVGs setup. In this example approach, for SVGs, you can use a title prop. In this case, let's write the test first to get a little bit of test-driven development going on. I'm going to do it, render, displays a waving hand icon. We're going to render. Next screen, Git by title, so Git by title is also available. I think there are different ways to do accessibility with SVGs, so if you're aware of a better one, please feel free to share that. This is just an example. So if I search for this, an element by a title prop, I'm going to get the error unable to find an element with the title waving hand. If I add a title prop waving hand, and I save, and the test passes. This is actually one of the benefits of test-driven development is you always see the test fail because that's the first step is to write the test and watch it fail, and then you, the next step is to write the code that makes the test pass, but that way you're sure you're not getting a false positive. You are sure your test is actually testing something and protecting you from something. Cool. All right. I'm going to glance here. Snapshot testing. We will get back to that a little bit later. Yeah, some good answers there in the chat about to be in the document, but to be visible. Let's go to the slides where I talk about that a little bit. So, getter functions, we saw a few of these. The screen.getByText, getByTitle, alt text. There's also a label text that we'll see a bit further when we start interacting with form components. So, for text, just to show you on a slide what we saw before, when you have text rendered out to the page, you can do screen.getByText. When you have a form element that has a label, getting that form element by its label text is helpful and that is helpful for accessibility as well to confirm that this input actually has a label. So, this input is retrieved by the label text, enter your name, that's associated with it because of the HTML structure.

7. Using Get By Role and Improving Accessibility

Short description:

Images have alt text and SVGs have titles. The Testing Library recommends using queries that resemble how users interact with your code. The top recommendation is get by role, which allows you to get an element by its ARIA role. Learning about ARIA roles can improve accessibility and make tests easier to write. Use get by role where possible and gradually increase the accessibility friendliness of your tests and code.

Images have alt text and you can get them by those. SVGs have titles and you can get them by those, at least in the SVG import process that I'm using here. So then you have a question, which query should I use? We can get by text, label text, there's test IDs. So, Testing Library has a lot of guidance on this. And on this page, again, these links will be available in the slides, actually the slides are already available, so if you want to download these slides to reference from the workshop page, you can do so. But in this document from the Testing Library docs, they say the goal is your test should resemble how users interact with your code as much as possible. And in light of that, this is kind of the queries they recommend. Sorry, the text is a little small, but you can refer to that webpage to see it a bit better. Ideally, you're using queries as accessible to everyone, and they do reference get by label text and placeholder text and text. And they actually put this get by role at the top as the number one recommendation, so let's talk about that. So it is the top recommendation, this lets you get an element by its ARIA role. Is it a button? Is it a checkbox? Is it a column header? Things like that. So I do recommend learning get by role. There is a bit more of a learning curve because you need to learn about ARIA roles, which is to say web accessibility roles, but that is work that's worth doing. So when you learn, oh, buttons have a button role, and that means that screen readers see them as a button. Oh, this custom element that I added doesn't have the ARIA role that's necessary. On my current client project, the accessibility of a code has improved when we saw that something was hard to test in the test, and then we improved the accessibility. Now the test was easier to write and screen reader users benefit as a result. So even though we're not focusing on get by role in the workshop, I would recommend that you take the time to try it out. And we don't use it on every single query, but use it where you can. When you find you're not able to use it, file that away and circle back to it at some point. you can gradually increase the accessibility friendliness of your tests and of your code.

8. Confirming Presence and Absence

Short description:

To confirm presence, use screen.getby to be visible or to be in the document. To be visible is stricter than to be in the document as it checks for display none, visibility hidden, and opacity zero. Confirming absence is done using queryby functions, which return null if the element is not found. The ESLint plugin testing library provides helpful recommendations for testing library best practices. Testing something not in view is useful for cases with conditional rendering. VS Code has ESLint integration for live recommendations. The next topic is testing the input of props.

So confirming presence. Here's what a few people are asking about. You can check that something is there by saying screen dot get by to be visible or to be in the document. So as the React Testing Library docs will show you, and your editor will probably show you inline help, which is great. To be visible is more strict than to be in the document. To be in the document just ensures that it was found. It also makes sure that the DOM node was not removed. That can sometimes catch issues when something briefly flashes up and is removed. But to be visible is more strict because it checks display none. It checks visibility hidden. I think it checks opacity zero as well. So I tend to prefer to be visible just for the extra safety it provides unless I have something that I'm setting to invisible but keeping it in the document.

Now let's talk about confirming absence. Confirmation that something is not there which is especially useful as I said in response to Elena, I believe, when you have something there and then you remove it later. So in addition to the getter functions, there's parallel queryby functions for all of these. The difference is the getby functions will error out and give you that nice JSX output when the thing is not found. But the queryby functions if it's not found it will give you a null back. That allows you to check when something is not there. You can say expect screen queryby not to be in the document. You could say expect it to be null as well. It is a null value so that would work. But not to be in the document just increases the readability of your tests. Because as a developer reading it, oh I see that UI element. I'm making sure that it's not in the document. So thinking about the readability of your tests is a great idea. One of my coworkers has done a great job investing in the readability of our tests. When she puts in a pull request, I'm like, oh wow, these tests are so much more readable. Thank you. Anything you can do to make your tests easier to read and your teammates to read when you pick them up in the future is a big help. The reason we have to use queryby when we're checking not to be in the document is getby will error out if it's not there. So you don't even get to the point that you can do the assertion. Screen.getby and it's not found. You'll get an error. But queryby is used when you're checking that something is not in the document. There's an interesting gotcha with this that I wanted to mention which is that if you're checking for something not to be visible, you have to use ‑‑ it's better to use getby because not to be visible, that matches when something is in the document but not visible. So really the best thing to do is when you're checking that something is there, the most safe way to do it is to say check the element getby to be visible. And then when you're ‑‑ if you're like me, unless you're doing something with performance, you just unrender things. You just don't render a certain component when it doesn't need to be there. Then you'll need to do queryby not to be in the document. And that's the safest most strict to check that is not there at all. If you'd like help with this, like it seems like a lot to remember, I want to recommend the ESLint plugin testing library. You're probably using ESLint on your project. This is a plugin that recommends a lot of testing library best practices. It can help catch errors and help catch things that will be more tedious for you in the future. So there is the prefer presence queries matcher. And actually a coworker and I just in the last couple of months contributed this rule, prefer query matchers. This will check for you. You can configure this and the example shows it to check to make sure that when you're to be visible, you're using get buy instead of query buy to get the optimal output. So that was fun. I've never contributed to an ESLint plugin or created an ESLint rule before. So that was fun to do and to learn all about that. But, yeah, definitely use the ESLint plugin testing library if you're using testing library at all. Those warnings will help you. Let me check the chat real quick because we're at a stopping point here.

Yeah, why to test something which is not in view? That would be good for cases where something is sometimes shown and sometimes not. It would be good to have two tests, one for that case and one for the other case and make sure in this one that it's there and this one that it's not. Because otherwise you could just hard code something to always be there. So if you have a conditional, if you have an if in your production code in your component, or if you have a ternary, or if you have a condition ampersand ampersand render the thing, whenever there's those logic branches it's a good idea to have one test for the true branch and one test for the false branch. So that could be a case where checking that something is not there is a good idea.

What is the name of the VS Code plugin that put the yellow bracket? So I'm using a different editor than VS Code. It's called Sublime Text. I'm not specifically recommending it. I'm just old that I use Sublime Text. I'm also picky, so I don't prefer VS Code. But VS Code has ESLint integration as well. If you just Google VS Code ESLint, you'll get integration in your editor, and I really, really recommend that. It's great for things like getting live recommendations. So like for example here, in my test code, if I said query by alt text to be visible, maybe not. Well, I guess at least, I can't do this live, but if I'm missing that alt there and I save it, we get that feedback that says you should have an alt prep. So if you're not getting live feedback from the ESLint in your editor, look for ESLint plugin, and it should help with that. Cool. Alright, so let's move on. So this has covered rendered UI, as far as testing our component. We'll be testing rendered UI all the way through, because that's how we verify things are happening, but that has laid our sort of initial foundation. Next, we're going to test the input of props, because that's very closely related. And usually you will have a component with props, that's how you end up with conditions where something sometimes happens and sometimes doesn't. So let's jump into props in the code, and this will be a quick one. Next, we have this greeting component that says hello, that's fine, but we want it to be a little more flexible. We want it to be able to say a name, to greet people by name. And maybe we'll say, if we don't pass a name, world is going to be the default. Incidentally, I'm thinking about the fact that I'm adding props here and I don't have prop types, and I don't have TypeScript here. React testing library works great if you're using prop types, and it works great if you're using TypeScript, and so whatever approach you're using for type safety, React testing library is still really excellent. But I'm just showing the basics here. So let's say we have a name here and we use this prop, so we greet hello, name. We'll save this and then we'll test it. So notice that our test still pass. So actually, if we call the hello component and we don't pass in a name, the default of world is used, and so our test that we render out, oh, we were checking out a substring, but let me change that back to hello world. See, we still confirmed that hello world is actually rendered out. This is one of the benefits, you'll see this more and more, one of the benefits of testing the contract. Our test doesn't care whether this is hard-coded or whether it's a prop that's passed in.

9. Testing the Display of Name Prop

Short description:

When rendering the hello component, the test passes. We add a test for when the name prop is provided. We pass in props just like in production and confirm that the expected output is rendered. We encourage participants to take a break or work through the provided exercises. The goal is to add tests to the movie row component, considering the inputs and outputs of the component. We will reconvene after 10 minutes to discuss different testing approaches and answer questions.

Just as long as I get hello world out, when I render the hello component, the test passes. So let's add a test for when we do provide the name prop in this case, though. Renders the passed in name. So in this case, I'm just copying this to be quick. As you might expect, we pass in props just like you would in production. I have a hard-coded string here. If you're passing something else, you could use bracket syntax, of course. It's exactly the same JSX that you're used to. And we can say, if I pass in name Josh, confirm that hello Josh is rendered. It passes. Again, I'm nervous, so I want to see it fail. So if I change this back to using a hello world hard-coded, my test fails. It says, unable to find an element with the text hello Josh, it rendered out hello world instead. So we've confirmed that our test is giving us safety. And that's really as simple as it is to pass in props. It's very easy. And whether you're passing in complex props or anything like that, you can pass them in the way you're used to. And that is all there is to that. We'll be using props all the way through the workshop as well. Props, we're done. We're good to go. We're two out of four types of inputs and outputs done, but the others are more complex, so they'll take longer. But that's rendering and testing them. We are ready for an exercise. So we're going to take a break as well if you need to get something to drink or take a break. But also if you would like, I would really encourage you to do these exercises. The name of the repos RTL exercises, unless I named it wrong. I think I might have named it something else. But in any case, you can get to this repo from here. I'm going to paste this in the Zoom one more time. Repo downloadable from here. But let me show you that, because this is a different repository with different code. So in this exercises repository, you'll see me at read me with instructions. It'll probably install just fine for you. Nice and straightforward. If you want to run the app, you can do it getting an API key. But for our component test, that's not so important. But go into the exercises folder, like I said here, to exercise 1. And this is going to describe what you want to do. This is an app for viewing movie information. And there's a pre-existing movie row component. So, this component has some props and it actually has some logic. So, this is something different to think about. So, when you get a movie object passed in, a movie has a title. And movie has an added today, which is a boolean. So, if the movie was added today, we render out this new icon, this new SVG. And if it wasn't added today, we don't render it. So, this is a case where we want to test is it present in one case? Is it absent in the other case? So, this is what I encourage. The goal here is add all the tests to movie row spec JS. The test file is here. It's just not doing anything yet. We need to add a test, add more tests as necessary. And so, I'm encouraging you to design your tests. Think about the contract of the movie component. What inputs does it take? And what are its outputs in response to those inputs? Which outputs are unconditional and which are conditional? And definitely, feel free to make changes to the component itself if it aids your testing. So, we're at 40 minutes after the hour. So, let's give this 10 minutes. So, at 10 till we'll come back and I'll show you how I decided to test this component. And we'll get input from you if you want to test it, if you decided to test it in a different way. That's totally welcome. As I said, there are tradeoffs. But for the sake of learning, I would encourage you to think through this testing the contract we've described together here. So, if you have any questions, I'll be watching the chat. I'll probably step away at a moment. I'll get something else ready as well. Take 10 minutes to take a break or work through the exercise and then we'll come back together at 10 till. Thanks so much, and we'll see you in a bit. As I said, I would welcome if you chose to test differently, please share your thoughts. If you ran into a challenge, feel free to ask a question as well. Here's how I chose to test this component. Some judgment calls I'll share along the way. Movie Row, it displays the name. So, just checking that the name was outputted, the title, I guess I should say, change that to title. Checking the title was output was some logic that I wanted to make sure happened. It happens unconditionally, but I want to make sure that the title data that comes in comes out to the output. So, therefore, I pass in a movie with the title. Notice here, because I'm using JavaScript, instead of TypeScript, I'm passing only the and I'm just saying I want all the properties needed for this individual test. The component doesn't blow up when I'm missing an AddedToday property, and so, I just do that. That's a different testing approach is you could say I want all the real realistic properties for all the test data I used. It's another option. Render at the Movie Row, and I just check that the title was outputted by GetByText. So, then, I created two separate tests for the two conditions. When the movie is added today, you render out the new SVG. When it was not added today, we don't render it out. So that's two sides of the conditional that I want to test. If I don't test both sides, for example, if I just test that the SVG is present in some cases, then I'm not confirming that it's hidden in the appropriate case and the test would still pass even if that conditional wasn't there. So, to force and make sure that it's there in one case and not in the other, I have to test both sides of the conditional. In this case, I pass in a movie that's added today true to make sure that the element with the title added today is visible. And then when added today is false, I confirm, I query by the title, which will give me a null if it's really missing, and then I make sure that it's not in the document. And there's something else I was going to say.

10. Test Cases for Conditional Rendering in Components

Short description:

I added the title for the SVG so that I could query for it with get by title. I separated the two conditional cases into two different tests. You could organize it differently.

Oh yeah, note that I did change the production code here. I added the title for that SVG so that I could query for it here with the get by title, query by title. One judgment call that I made is, you can say, well, you know, when you rendered this title here, it's either going to be added today or not. So I can add the same one assertion or the other into this test and just have two different tests not three. I thought about that, and it's certainly an approach you can take. For me here, I wasn't sure what the obvious default was. And also, as somebody mentioned in the chat, test names get hard to write when there's a lot of things you're checking. If I had said I'm also checking that added today is not in the document, what title do I give that test? I say it displays the title and not the new icon when it was not added today. That's starting to become a complex test name. And if you have three or ten or 100 props in there, that test name is going to get very verbose. So I kind of liked in this case the idea of, hey, there will always be a title, but then there's two other conditions. There's the new icon and there's the not new icon. So I separated out those two conditional cases into two different tests. You could organize it differently. I'm going to turn my fan off here. It's distracting me a bit.

11. Testing React Component Behavior

Short description:

When testing React components, it's important to focus on the behavior, inputs, and outputs that are significant to the user or the rest of the application. Making assertions on every detail of the JSX is not recommended as it can lead to tests that replicate the production code and don't add much value. Instead, prioritize testing the content that users care about and avoid asserting on implementation details. This approach allows for flexibility in changing the implementation while ensuring that the component's behavior is still tested effectively.

So I'm going to check the chat for any feedback or questions you have. If you have other questions or feedback, go free to share it. Would you test that it's wrapped inside an li element? That is a great question. So some approaches to React testing that I've read have made assertions on every single JSX node that's in there. Make sure that the title is wrapped in a span. And a test driven development mindset can actually lead you to that, depending on how you're thinking. I would consider that an implementation detail. When you think about components are used by your users, and so what do they care about? Do they care that it's a list item? Well, maybe it's good for accessibility or something like that. But apart from that, do they care that the title is a span or a div or some HTML5 thing? They don't really care about that. They care that the content that they want is there. Also, if you find for me, this is a very simple JSX. If you have a very complex JSX with a lot of nesting, and you're making test assertions on every single DOM node, every single JSX element there that it's the right element, those tests aren't adding a lot of value, in my experience, usually. They're just going to replicate what's in your production code. So I do not recommend making assertions on every detail of your JSX. The benefit of this is when you don't assert on this item, for example, I can change this. I can change how this is implemented to put material design or, you know, and design. Is that a name of a design library? Or I can just change the HTML, and my tests of the behavior of the component continue to pass. So I would say in my React component test, I find the most value when I'm asserting on the behavior, the inputs and the outputs in terms of what is significant to the user or the rest of the application. Not in terms of every implementation detail of the JSX, I would say.

QnA

Testing Component Parts and Q&A

Short description:

The speaker addresses a question about testing one part of the component and acknowledges not having a good answer. They mention that the topic of grouping tests by nested describes will be covered in the next section. The speaker encourages participants to ask more questions and offers to continue the conversation via email or Discord.

The question about testing one part of the component. Which test case. I think I answered that. The classic rendered zero bug. I don't actually have a good answer for that. Grouping tests by nested describes. We're going to get to that in the next section on forums, where I'll show through some options. Some folks talking about tradeoffs, splitting up tests. A couple of tradeoffs there. Drive principle and tests. We're going to get to that as well in the testing forum thing. More questions. Cool. Okay. So let's move on from there. I'm sure there's more questions I didn't get to. In the interest of using our time together, let's keep going. Feel free to connect with me, email or Discord later and we can chat more.

Testing with Storybook and Snapshot Tests

Short description:

Storybook is a great tool for visualizing and testing React components. It allows you to configure components in different states and scenarios and quickly visualize their look and feel. Snapshot tests in Jest record the JSON representation of JSX output and compare it to ensure it hasn't changed. However, snapshot tests may not provide much value as they don't encode behavior or expected output. Writing contract tests can yield more valuable and maintainable results. The next section focuses on testing user interaction events.

A few more notes about testing, rendering, and props before we move on.

Appearance. Storybook. A lot of you are familiar with Storybook. A great tool for React and other component libraries. Testing in the sense of visualizing. They do automated tests as well. Storybook allows you to configure components in different states and scenarios and lets you visualize them. This is great for our current client project because our React app runs through a heavyweight Java set up. Reloading the app takes a lot. When we put things in Storybook we can get quick feedback to get a great look and feel for our components. How do I make sure the styles, visuals, look and feel of my component are the way I want it to be? You look at it. You might not expect that answer from someone who is into automated testing but anything we can write in a Jest test to confirm the visuals is not going to be as useful as is the gradients right. Are the sizes of the dots right? Is the shadow the way I want it to look? So setting up Storybook lets you and visual designers, and let's the business to quickly visualize and confirm the way the components look. There is integration with visual regression tools to make sure the images don't change unintentionally. When it comes to styles, not putting that in the React testing test unless it is a condition. I set visibility zero when this is the case. Maybe you have an assertion on that. Or I set red versus green for a different scenario. I would encourage following the React testing library guidelines and make sure there is text you can also assert on. Even if you do assert on red versus green in your React testing library test because that is important for screen readers and people with color blindness. I would encourage story book. They have some integrations that I haven't used before but are worth checking out. What about snapshot tests? If you haven't run across these in Jest before, this could cause confusion. In the iOS world, snapshot tests refers to an image taken. A snapshot of the screen and you make sure the visuals have not changed. In Jest, a snapshot test means something different. In Jest, you render out some JSX. When you convert it to a JSON representation, there are other ways you can use snapshot tests as well. Then you confirm that it matches the snapshot. The snapshot test will record the JSON that was outputted in previous test runs and make sure that it hasn't changed. Which is to say, a representation of the JSX. A snapshot test can make sure that your rendered JSX does not change unintentionally. Folks tend to reach for these sometimes. Let me say this. I don't find a lot of value in just snapshot test most of the time. If you do, if your team does, you should go for it. Like, you are finding value from it. Let me share my experience and you all, please share your experience in the Zoom chat as well. I've seen folks reach for just snapshot tests when they don't already have tests. It's like, well, it's testing something rather than nothing. That seems like a step in the right direction. But it's not encoding the behavior. It's not showing in the test, what is the expected output? It's recording every detail of the JSX that comes out. This becomes a challenge when you say, I do want to change that LI to a div, a material design thing. I have seen a snapshot change when some implementation detail of how I'm moving the components around changes. The user doesn't see anything different. But Jeff says the snapshot doesn't match. When these get long, when the JSX output is long like it is in a lot of production applications, it is so easy for a developer to just say yes, accept the updated snapshot and to not look and see. So when you take the time to write a contract test, a behavioral test, you will get good valuable test output that says, I expected the new icon to show, but the new icon did not show. I think although it takes work up front to write behavioral tests like we're talking about, I think you will find more value. It will make your test more maintainable in the long run. As you go along.

Cool. I'm seeing a lot of test output. Here we go. We're into the section. Let me glance at the output here. Yes, that's a good point. I said that about businesspeople checking Storybook. In most projects and most organizations, businesspeople are not going to check Storybook. Yes, snapshot tests are not needed in all projects I would say. A lot of discussions there. Cool. Cool. Good discussions. Thank you everybody for helping one another out and sharing thoughts. I love that. You all have insights that I don't have. We all learn from each other. We're going to the next big section here. We had a break a little bit ago, so we'll go through this section and we'll take a break during the next exercise as well. There's three exercises over the course of the workshop together today. Actions and mocks is our next section here. As we think about testing the contract, as we've gone through together, we've looked at the input of props and we looked at the output of rendered UI. Next what we have is user interaction events. This is an input to your components. It's how something happens, which is maybe more obvious when a user types in some text, but even just a click on a button is an input in this way of thinking, and we want to test when that happens. So let's go to the code, maybe get the right code up, the lecture sandbox. We're in here, we're going to go to lecture 2. New message form. So this will hit on a few of the different questions you all asked about test organization as we go through here. And get my personal notes up here, and then we'll proceed. So here I'm sorry I didn't set this up to be able to visualize it on the screen, but you'll be able to tell what's going on. This is a very simple form component. We just have a state for a single text field. Think about like a chat application where you type in a message and you send it. So we have a text input to type in the message. We have a send button that sends it out. Our input text is stored in this state.

Testing Clearing of Input Text

Short description:

To test the component, we need to consider its behaviors: when we click send, when we've typed in the text and click send, two things happen. We send the input text to the on send function and clear out the input text. Let's start by testing the clearing of the input text. We'll render the new message form and use the user event library to simulate typing. Then we'll submit the form and check that the message field is cleared by asserting that the value prop of the text input is an empty string.

And then when we submit the form to handle submit, we do the HTML jump through the hoop. But then we call this on send, callback that's passed, passed in an event handler, effectively, we pass it the input text. So the rest of the application handles sending that to the server or the web socket or whatever. Our form component doesn't know, it doesn't care, it has a focused approach of I'm getting the input, and I'm sending it out. So how do we test this component? Let me get this out of the way so you can see it all.

How do we test this component? Well, what are the behaviors? When we click send, when we've typed in the text, and then we click send, two things happen. I didn't mention the second one a second ago. We send that input text out to the on send function, and we also clear out the input text. So if you're thinking about a chat app, you type it, you hit send, and the input text is cleared out. So you're ready to send the next message. So let's test one of these at a time. This will get into this whole idea of how much do we group our test together versus separate them out. Let's do clearing the input text first because that is easier and works better for the presentation. It doesn't matter which one you do first.

We have new message form. I'm going to add a describe block here. I'm going to call it pressing send. Some of you all asked about grouping of tests. I wouldn't nest test too deep because it can get confusing. But when you have a component, when there's multiple things happening, it can be useful to group the scenarios with a describe. Also here, right now, there's only one scenario we're adding, but even just doing this, this allows us to give some context so that individual test names don't have as much repetition in them and they're a bit more readable. And this shows nice output, as we'll see in a minute, in the test runner, as well. So let's say it clears the message field. All right. So let's first render our, sorry for the distracting, the yellow outlines are distracting until we get working code in here. So we'll render our new message form. We'll get back to the on send later. We'll come back to that. So the next thing we need to do is we need to actually do the typing. The way we can do this is with the user event library. I sometimes have trouble with, oh yeah, I pre imported it here. So user event comes from testing library user event. If you've used this in the past, the latest version of user event is really great and they have a different API to increase reliability. The old API still works, but it's recommended to do user event setup. So you're creating this user object, simulating a user interacting with your app. Then what we can do is we can say user.type, let me take the await first. So this is an asynchronous call, so you need to await it in front and to do await, we need a sync up with the start of our test function. But we're gonna type. We're gonna use the screen API as before to find our element, we're gonna get it by label text. The label of this input is message. So we get that element, and then the second argument to user.type is the text that we type will type hello world. So we've rendered the form and we've typed in text to it. Yeah, so next we need to submit it, because we don't actually act until we click the Submit button, which submits the form. And notice, by the way, that I'm using HTML form setups here, where the button is a type Submit, the action is not on the button, the action is on the form itself. That's good for forms, it makes the enter key do what you expect. But React Testing Library works just fine with that. To click on that button, we use another User API, User.Click, Screen, and this time I am gonna use GetByRoll, because with buttons it's very easy to use. So just to give you an example of that, so we're gonna use RollButton, buttons have the roll button. Now there's only one button in my component, so this would actually work. This would find just one button here, but it's good for understandability. It's good for robust test for the future, and it's good for making sure our app is accessible to specify which button we need, and we give it an accessibility name here, we say send. So give me the button that's named send. This is sort of an accessibility concept, the GetByRoll docs get into that. I think I might break this in a second just to make sure that we can see it fail. So if I save this now, we're not doing any assertions yet, but let's just make sure the test runs. It passes, so it's able to find these things, and let's just see it fail, for example. So if we change the label to nonsense, the test would fail and say, unable to find the label with the text of message. This confirms that our message field is really labeled message, and then also if our button had the wrong label, it would say, unable to find an accessible element with the roll button and name of send. And when you're using GetByRoll, React test library does something that's very helpful for learning about accessibility. It lists out all the elements on the page that have accessible roles. So check this out, we learned from this that this input has a role text box and a name of message. It gets the name from the label. So this has taught us, oh, here's how we could use GetByRoll to get this text box, and we're doing that in our current client project. And with the button, it says there is a button, but it has a name that's not what you expect. So that gives us helpful debugging output to find out why our test is failing if we don't expect that. So let's change the name back, and it sends send. Cool, let me check the output here. Someone asks, yeah, is this a different repo? Yes, this is the lecture sandbox, not the exercise repo. So I do something different when I'm doing the demonstrations here. Why is UserEvent better than FireEvent? I think you all are answering with helpful answers in there, but UserEvent better mimics users. In fact, when you do a user.type, it does a number of different events, including like focus and things like that. I think it does blur later and things like that. And so you're more likely to get more realistic behavior. Also, using UserEvent is helpful with asynchrony to make sure that there is time for the typing to happen and stuff like that. Why do you need UserEvent.setup? Can't you just use UserEvent method everywhere? It does still work, but if you check the UserEvent docs, they talk about why they recommend user here. It's something to do with, I haven't dug into the details, but it's something to do with the realism of making sure it's got the latest DOM information. So check the UserEvent.setup docs. This is one of those things where following the recommendations of a library, they give rationale. They know what's happening under the hood and you might be shooting yourself in the foot or run into deprecated behavior in the future. So I like to teach and follow the recommendations from the testing libraries. Is it better to wait for UserEvents or to await at the assertions? So we are gonna see examples of awaiting for assertions where we need to do so. But the API for the UserEvent library recommends or requires awaiting. It may not blow up if you don't await it, but I would check the UserEvent docs to see if it's okay sometimes to wait for those UserEvents to end. Yeah, another question about UserEvent setup. I'd really defer to the UserEvent docs for more information on that. So now we do need to check the results here. So what we're checking, we're confirming the pressing send clears the message field. So we can check that, and we can say expect, and let's get that text field again. We'll just use GetByLabelText for now to have value empty string. So this is checking the value prop of the text input to make sure that empty string is now shown in that text field.

User Interaction Events and Testing the Contract

Short description:

We test the component and verify that it clears the text field correctly. We also discuss the importance of seeing test failures and improving error messages. The user event library is recommended for simulating user interactions. User event 14 provides major improvements in realism and test simplicity. It is recommended to use user event.setup and use asynchronous calls with await. We emphasize the importance of testing the contract and what the user sees, rather than implementation details. Testing the value prop of an input JSX element allows us to confirm what the user sees. This approach focuses on testing the contract and not the implementation details. User interaction events are an essential aspect of testing, and there is more to explore beyond the basics.

We save and the test passes, but again, I don't trust it. I wanna break my production code to make sure it's really keeping me safe. So I comment out the setInputText so that we're no longer clearing out the text box when we submit. I save, and now check out the output.

The other reason to make sure you've seen your test fail is you make sure you have a helpful error message. Well, two things. You make sure it's failing for the right reason because it might be failing for a reason other than what you expect. So pay attention to the error message shown. You also make sure that the error message is helpful. And so if it's giving you something abstract that's not really helpful for the future developers, maybe you can improve that error message output. So here we say expected the element to have value. This is actually hard to see because it is the empty string. But if I said expected to have the value foof, it would say expected the element to have value foof. Because we're checking for empty string, it says expected the element to have the value empty string. But we received hello world instead. So this shows us, okay, yeah, we're not clearing out the text field correctly. We uncomment our production code, and now it's clearing out the text field correct. To have value is provided by the Jest DOM library. And so you need to make sure you have Jest DOM installed, and it's very easy to do so.

Cool, so this is the first step of confirming user interactions here. Confirming the results we see on the screen as a result of those user interactions. Yes, check the message value before clicking on submit to make sure the user input works well. That's a great point. If we weren't having the user input update properly, it's kind of like a precondition. I've seen this referred to here. Let's try that real quick here. Make sure that the input has the value, hello world. And you could say, well, like I expect that. So there is a trade off here. This makes sure that we're not getting a false positive because if maybe the value was empty string from the start, because we weren't correctly taking in the user typed input. So if you find that safety is helpful, you can put it in. On the other hand, you can ask yourself, is this likely to break? Am I likely to break the text input on the text field? Maybe it's not too likely, or maybe you know in using your application, you'll see right away the typing, the text field is not working. And so maybe you don't feel that that detail is necessary. Or maybe if your form of your application has a hundred text fields, and maybe you're running through a form handler library, like React hook form, maybe you say, okay, like it's not adding a lot of value to add that assertion every time. So really, as you kind of go into more advanced testing approaches, it's good to ask yourself, is this assertion adding value? And for some teams on some projects it does, and for other teams and other projects, it won't. And so you will make different choices and we will make different choices from each other, depending on the context. Cool. So let's go on from here. I see more chat. Thank you all for sharing ideas and thoughts and helping each other out. So to put up on this slide here, the code pretty much, what we saw. I see one difference, user event setup. In this case, I did this right at the start of the test. You can do this in like before each blocks as well. I have not settled on something. I feel like every other test I write, I put the user event setup in a different place. So challenges there, but again to walk through what we just saw together, we are rendering at a form, we're typing into a text field, we're clicking the button, and then we're checking the contract of the component. For the sake of this test, checking that we clear the message field, we're checking what we can see on the screen. The user will see that the label text, sorry that this input has the text cleared out of it. So let's talk a bit more about user event 14, the latest major version of user event. So in this version, new in this version is recommended to do user event.setup as we discussed in the chat there, more information in their docs as to why. So to use user event, you call click or type, or clear if you need to clear out the text of a text field. Someone just asked about that in the chat. If you have a drop down select, select options allows you to select from those. And notice in user event 14, all of these are asynchronous calls that you use a wait in front of. I believe in user event 13, asynchrony was a bit different. And I actually, in some other teaching resources I did, there was a lot of hoops I had to jump through in user event 13 to get around React Act errors and stuff like that. I found so much of this just works with user event because it's asynchronous, because it's simulating a user that takes time to do something like typing. So if you're not already on user event 14, I really, really recommend it. There's major improvements to realism and test simplicity. If you're using create React App, it installs user event 13 by default. So there's a takeaway tip for you. If you're not on user event 14, see if you can get to it because your asynchronous test experience will be a lot better in user event 14 and a lot of things are forward compatible as well. Yeah, Bruno, like a lot of things are compatible but going from react user event 13 to 14, but give it a try, update it and see if a lot of the tests fail or not. And if it does take a lot of work, maybe you prioritize it differently. So now at the end of the test to kind of reassert we said, I guess I said that before. We're getting the text field and making sure that it has the text cleared out. To have value is provided by just DOM and you can check that it has that value prop passed to it. So there's something interesting that I wanted to comment on here. We've been talking about testing the contract not testing implementation details. And so the value prop to an input JSX element, you might feel like that's an implementation detail in the testing library approach. And so that's actually really helpful. If you're really discouraged, like don't test props on components. Test what the user sees. And so I totally agree with that. So our goal here is not to test a prop. Our goal is to test what the user sees. We wanna confirm does the user see an empty text input? And the way we do that is HTML Forum inputs have a value attribute, a value prop. And so that's the mechanism that just provides. They might have, or maybe there's an element out there that's a text, like it might actually be a have text. So there might be a higher abstraction way that ensures I'm just checking the text on the text input, or maybe you could add it if it's not already there. But from a functionality standpoint, like we are not digging into the implementation details of the code. We're directly asserting on something the user can see. And so in the spirit of things we are testing the contract, not testing the implementation details. So I would encourage you as you're thinking about, oh, like I'm testing the prop of an input text field. Like is that bad? Someone told me don't test the props, that's the implementation detail. As I said early on, you got to think about it and think about what is really getting at what the user sees. All right, so that's user interaction events. There's much more we could do, but that is the basics of how you go about interacting with things. But we only tested one of the two conditions that I talked about for that form.

Testing External Functions and Function Props

Short description:

We discuss the different types of external functions that might be present in a component, such as function props, functions from hooks, and statically imported functions. Testing the contract of a component by using function props can help decouple components and make them easier to test. Jest provides mock functions, which are functions that record when they are called and the arguments passed to them. These mock functions can be used to make assertions and confirm that certain functions have been called with specific parameters. By using mock functions, we can test that the onSend function is called with the inputted text when the send button is clicked. Our test focuses on the component's responsibility of calling the onSend prop that was passed to it. We can verify this by using the expect function to assert that the onSend function has been called with the expected input text. If the onSend function is not called, the test will fail and provide an error message indicating the expected and actual calls to the function.

So as a result of checking calls to external functions, we're gonna complete our test of that form component. So let's move on from there. So what types of external function might you have in your component? There's a few different types. You might have function props, like in the case of our component, where we're passing in onSend as a prop and then we call it. You might get functions from hooks. Someone mentioned this early on in the workshop. So maybe a hook gives you a function that you can call, maybe that comes from a context and that's provided to you that way. So that's another kind of external function. You might also have a function statically imported from a module, your client's to a backend API. It's a module, first party module, third party module, you import it and you call it. All of these are different types of external functions.

I'll get my slide notes up here. So we're gonna talk about these at various levels of amount of detail but first we're gonna talk about function props because they're the simplest and actually taking the... I'm not saying you will always use function props for your functions in code like this but the more you think about testing the contract, the more it kind of gives you visibility in your code. Are my components tightly coupled to other things? And are there cases where I can decouple them where you get to the point where your form doesn't know if you're using Redux, your form doesn't know if you're using GraphQL, it just knows I'm past an on send function. That kind of decoupling of responsibilities has a lot of benefits. Don't need to do that in every single component. It's hard to fully do that in a React hooks world but test can provide some friction that nudge you in the direction decoupling things so that they're easier to test. And that results in simpler components as well as easier tests. So we're gonna look at function props first.

So Jest provides a function, a functionality called mock functions. Here's the link to the docs. And again, you can get these slides from the workshop web page but we're gonna look at mock functions together because this is a great way to test function props. This time, we're going to look at the API first on a slide before we see it in the code. So creating a new mock function. What is a mock function? A mock function is basically a function that it doesn't do anything itself, but when you call it, it records that it was called and it records the arguments that you pass to it. And it records how many times that was called. So you call Jest.fn to get a mock function. And then on it, you can change this mock name here to give it a name. This is optional, but it makes the error output clearer. And we're going to see how in the lecture example in just a second. Once you have a mock function, what can you do with it? Well, you can make assertions against it. You can say, I expect my mock to have been called. You can say, I expect my mock to have been called with these parameters. This is at as many as you like. You could also, sometimes you don't care about the exact parameter that it was called, but you just want to make sure it was called with this string. My current side project, I use UUIDs. I generate a UUID. So I don't care what the UUID is. I don't think it's going to break. I just need to know that my function was called with a string and that's enough confidence for me. So these are the kinds of things you can do with mock matchers, but let's see it in the context of the actual running app to see how this is useful. Okay.

So before, as we were working together, we tested the first thing that happens when you click send. Well, one of the things that happens is that we clear the input, but there's one other thing we wanna confirm as well. And for right now, I'm gonna write this as a separate test and then we'll look at some trade-offs later. The other thing we wanna happen is make sure it calls the onSend. Let's say it passes the inputted text to the onSend function. One of the things I love about Jest is using strings for test names. It really nudges you towards, let me write this in a way that's understandable to a user and so that in your test output, you can really see what's going on. Some people talk about the ideas of test as documentation, like your test document, the functionality of your app. Some people will actually read through test files to get a sense of code. I haven't found myself doing that. But when I need to change a component or a function or whatever, and I change something and a test breaks, all of a sudden I'm very interested in test as documentation. I say, test, please explain to me what needs to be happening and what is no longer happening after I've broken something. And so expressive, clear tests that help you understand, help future you, help your team members understand what's happening is really good. Our current client project is very complex. It's an existing system we're porting to React. And so having these clear test names, as my teammates are writing things out, and when I'm doing code review, I can see from reading the test, okay, cool, I follow what's happening and what you're trying to accomplish with this component because I don't have the business requirements in front of me. The business requirements or the pre-existing old code. And so these descriptive test names are very helpful. All right, so how do we confirm that pressing send passes the inputted text to the onsend function? I'm gonna first copy paste this setup here and the interaction steps. And again, if that frustrates you or bugs you, hold on, we'll talk about a trade-offs in a minute. So, but there's one other thing I need. I need that onsend function passed in. So what do I pass in? What I'm gonna do is set up a jest mock function. I'm gonna give it the mock name and we'll see a little bit later what happens if that's not present. So I'm passing in this mock function because I need to make an assertion on it later, because after all these steps are done, how can I tell that I've called onsend and passed input text to it? Well, mock functions make that really easy. You say expect onsend to have been called with input text. I'll copy and paste it for now. You could put in a variable as well. Sometimes that's helpful. So I'm confirming that when I click that send button that onsend has been called. This is the output from the component. The component is sending up to the rest of the app, the inputted text, that's what we're confirming. One important thing to note is in our test here, we're not confirming that a call was made to a server. We're not confirming that something is in the Redux store because our component doesn't know about any of those things. Our component just knows I've been given an onsend prop. And so when you think about the contract of this component, what it knows and what it's responsible for, it's responsible for calling the onsend prop that was passed to it. So let's save this and see if it works. It does. You probably know what I'm gonna say next at this point. Don't trust it, let's make sure we break it, that it works. So if I comment out the call of the onsend, I break my production code. I save, and then I get a test failure. It says, expect onsend to have been called with expected. We expected it to be called with hello world, but actually it was called zero times. It wasn't called at all.

Testing the onsend Function and Test Failures

Short description:

We expected onsend to be called with hello world, but it was called zero times. When we removed the mock name, the error message became less clear. However, jest helpfully shows the code output and where the onsend function is called from. It's important to see test failures to evaluate the clarity of the output and make improvements. Forgetting to pass the text to the onsend function resulted in a test failure, indicating that the expected input was not received. Adding the input text resolved the test failure.

We expected it to be called with hello world, but actually it was called zero times. It wasn't called at all. Cool, great. Let's take a look at the effect of this mock name here. So if I remove that, I just say onsend is a jest function, and I save, what happens? Now it says expect jest function to have been called. So when I'm looking at this line, it's a bit less clear what's happening. Now, if I look down, jest helpfully shows me in the code where this is called from. So expect onsend to have been called. So where it shows the code output, the name onsend is there, it's just not present up at the top. So depending on your component, that could be helpful or not helpful, but I've gotten into the habit of adding this mock name just for a bit of extra clarity. But again, the reason it's important to see your tests fail is you can see the output and you can decide, is it clear enough, or should I add extra clarity for someone in the future? The other thing let's do, let's put the onsend call in, but let's say we forget to pass the text to it. What's gonna happen? We save. And now the output says I expected hello world, but I received it was called with zero arguments. And it was in fact called one time. So this is confirming that we didn't pass the right data to it. So if we now add the input text in there and it passes. Cool, let me check the chat here to see.

Testing Helper Functions

Short description:

When testing helper functions that are standalone and don't rely on React, it's recommended to import them into a separate test file and directly test them without using React testing library. This allows for focused tests that check the output based on the input. For example, when dealing with complicated logic like grouping data elements, writing a unit test for the grouping function can provide a clear understanding of how the function works and ensure the desired output is achieved.

How do you describe when testing a helper function, one that returns a boolean based on the inputs? Yeah, so when you're testing helper functions, that's a great question, Tony. I recommend if you've extracted a function that lives outside of your component and it's standalone and it just gets some inputs and outputs and maybe it doesn't even know about React. It just takes in plain JavaScript. I recommend testing those directly. Import that helper function into another test file, call it directly without using React testing library at all and check the output. So on my projects where I have some complicated logic, one great example I come to is I have some data elements and I need to group them in a configurable way. They're grouped together, so they're grouped in the output list and then they're sorted underneath that grouping. That's complicated logic and that doesn't really relate to React at all. And so I write a unit test for that grouping function. I pulled a grouping function out and write a unit test for it so that when I get this flat list of records coming in, I get these groups of records coming out. That is easier for me to conceptualize and it keeps my test focused so that my test doesn't have asynchrony in it and it doesn't have React JSX elements in it. It also runs faster, but it just shows me data in and data out.

Passing Functions as Props vs Using Hooks

Short description:

JavaScript objects in and JavaScript objects out. It's a trade-off. Passing functions as props allows for testing, but using hooks can't be tested in isolation. Hooks have benefits, but lower-level components may use props for more isolated responsibilities.

JavaScript objects in and JavaScript objects out. Is it preferred to pass down functions as props so it can be tested this way? I will say it's a trade-off. When you have a code where it makes sense to set it up in this way, that can be helpful. Now, another thing you might do instead is you might have a hook here, GraphQL hook, custom hook or something that pulls things in directly. But when you do that, you can't test the form in isolation. So I love React hooks. I think there's a lot of benefits to them. I use them all the time, but some of my lower-level components, I don't put the hooks in, and I pass in props instead because it isolates the responsibilities a bit more.

Refactoring Tests and Trade-offs

Short description:

We discuss the trade-offs of removing duplication in tests and present a refactoring approach using a custom render and send function. This function allows us to remove duplication and focus each test on specific assertions. We explain the trade-offs of this approach, such as the indirection and the need to refer to other functions for context. We mention the option of using a beforeEach block in Jest, but note that the ESLint plugin for testing library recommends against rendering in a beforeEach block. Ultimately, the choice of how to structure tests depends on what is helpful for the reader and the test output.

We've tested our call to this external function here, but before we move on, I want to talk about test organization and talk about some trade-offs here. You see there's a lot of duplication between our two tests here. They're both in this situation, pressing send. For those, the rendering out in these three steps with a setup step here, those are duplicated. Those are the same in both of them, and, well, there's a prop in one case and not in the other, so that's a bit of a difference, but it's fairly similar. So this may work best for you, but you may say, you know, I really want to remove that duplication. This is making it hard to see what's happening. I'd really like to see the test in a more focused way. Of course, as someone mentioned, this is a very small, simulated example. Your real test will be bigger and more complex because your real production code is more complex, so you may say, I want to remove that duplication. So what do you do when you want to remove that duplication? Let's take a refactoring approach, which is to say, we're going to make small changes and we're going to let the test run every time to make sure things are still working, and one thing I'm gonna do, I'm gonna pull up this message text because it's actually duplicated in multiple places. It would be nice to actually assert based on the variable. So you can do that sometimes. Not saying you always need to, but you can do that. The message text is, hello, world, because really the details of the text don't matter. What matters is I'm typing in message text. So we're ultimately going to remove a lot of duplication, but let's move in small steps. So I save here and my test still pass confirming that it's still working, I haven't broken anything. So now I'm going to take an approach here, and again, there are trade-offs, but let me show one approach you could do. I'm going to put a user here in a variable. Well, let me, what's the best way to say this. I'm going to do this in larger chunks here cause I haven't written it out for myself in smaller chunks. Let's make a, let's say onsend here. And now what I'm going to do, I'm going to make an async function, render and send. So this is a custom function I'm writing to render the component and send the message. And from here, I'm going to move these steps over. So here, I don't want onsend to be a bit, just a local variable in this render and send function. I'm going to refer to this let variable up here. Also, this user, I want to be available up here. I'm going to maybe move it up here. So this render and send function assigns these two variables that are available up at this level, inside the describe block. And so now, notice I'm passing it onsend. So this is where I've pulled this content from. So I'm going to replace all this with render and send. And we are going to await it because it is asynchronous because we've got these awaits inside of it. Now, how about for this other test? It's not identical. So notice we're calling newMessageForm here. But we're not passing the onsend prop because this test doesn't actually care about it. So that's true. And yet, with the goal of removing this duplication, we're kind of doing some setup here that sets things up for all of our lower level tests, like kind of the superset of all the setup needed. So actually, I can do render and send here as well. And even though the onsend is not needed in this case, it's OK. It doesn't hurt anything. Let me save changes here. The test still passes. Now, if you're worried about your refactorings, you could go back and break your production code again and make sure that the tests still catch it. But this lets it happen. So let's think about the trade-offs of what's happened here. Actually, you can even remove the line if you want. So each of our tests is very, very focused. It says, when I render and send, make sure that the text field is cleared out. When I render and send, make sure that onsend has been called. And because this is an explicit function call, I can use my editor go-to definition to get right up to it to find it there. So even if this was longer, Editor help would get us there. There is another option in Jest. There's a before each block you can use. This is, you say, before each. And you can run setup. And this will automatically run beneath either of these its. So if our setup was in there, you would only have expects. You wouldn't have anything else happening. However, the ESLint plug-in for testing library recommends not doing any rendering in a before each because of the indirection that happens. That's a judgment call. You can set up tests in different ways. But I like to follow the recommendations of the testing library until I have a good reason to go otherwise. So that's why I use an explicit function call to render and send. This doesn't clutter up our tests very much. I mean, they're still extremely short. But it lets you explicitly get to the setup that's happening. Now let's think about other trade-offs. So this has made our individual tests simpler. But also, we can't see everything at once. Like, when I look at this, I see, oh, make sure that getByLabelText has a value of empty string. What does that mean? Like, what does that refer to? I have to go look somewhere else to another function to find out why. And if I had a lot of test cases here, I would have to be jumping up to the render and send function to see it there. So there's a trade-off there with that indirection. In some tests, you may find that it's helpful. In other tests, you may find that it's not helpful. So you may want to explicitly put the render in line each time or repeat these steps. You may even decide, you know what? I just want one test. It's just one big it block. And at the end of that test, I do both of the xbacs. You can totally have multiple xbacs in one test. It all comes down to what's helpful for you as a reader of the code and what's helpful for you looking at the test output. So there's a lot of judgment calls there. Saying to you that one is recommended over the other, they're all options that you could pull from. But if you do like the separation of these individual tests and you don't like the duplication, pulling out some shared setup that you explicitly call is an approach you can take on that. Cool. Andres mentions, to have been called times and to have been called with. So yes, this is something else you can do.

Testing the onsend Function and Test Failures

Short description:

You can add the assertion expect on send to have been called times one to ensure it isn't called twice. The mock name for a mock function can help with test output readability. Giving each mock a name makes it clearer in the test failure which one was expected to be called. Adding semantic feedback to assertion errors can make them more readable and meaningful. Exercise 2 involves testing the newMovieForm component and making judgment calls on how to test its behavior. After the exercise, the participants will regroup to discuss their solutions.

Let me add that in. You could say expect on send to have been called times one. That makes sure it isn't called twice. Because if you say expected to have been called twice, it says expected number of calls, two, but it was actually just called once. So if you find that that's helpful for the extra safety you get from those two pieces, you can definitely add that. I find that that's not a mistake that I will commonly make in the code that I'm working on. And so I find that called with is more often most useful and helpful. But certainly, if you're in some complex code with repeated things happening and you want to confirm that it's only called once or that it's called exactly twice, putting that assertion in can definitely be valuable. And the check, expects to have been enthecalled with. That does help. But note that that one doesn't confirm that it's called only once. You would still need the called times if you wanted to make sure something was called only once. So those are things I just sometimes do and I sometimes don't. Just pull from those when you find this helpful to you. Try them out and see if they add value.

All right, so let's look at slides to look again at what we just did. So for our test that calls the send-handler, this time I called it send-handler instead. The name of that variable doesn't matter so much. The key is you're sending it in the onSend prop. One thing that can be helpful of naming your mock function differently than the prop name is, you're just reminding yourself, it is a mock function that we're checking. It's not checking the prop itself or something like that. But in here, we set the message text. We configure the send-handler and just mock function. Remember, that's the main thing we're learning right now. Before, the test organization was just mock functions. We're doing our typing and clicking as we did before. And at the end, we expect that the send-handler has been called, with the appropriate arguments sent to it. Pick here.

Why do we need mock name for mock function? So I referred to that a bit earlier, with mock name that helps with your test output. So when you see it fail, it more clearly says, it is send-handler that failed. And that is especially useful if you have several mocks. Say you have a component that you pass on complete, and on error, and on cancel. That way, by giving each a name, that makes it clearer in the test failure which one of the three you were expecting to be called. Super not essential. But you can try it out and see if it helps you understand your test failures better. And since two people asked about that, let me show that again, just so we see it here. Because we're making good time here. So let's say we break the calling to onSend. So we have not successfully called onSend. So here, in our test failure, it says, expected onSend to have been called. Called times? Oh, I didn't say it changed the test. Yeah. Expected onSend to have been called with. So by giving this mock a mock name of onSend, Jest can say onSend here. If I take that out, and I say it's just a Jest function, it says, expected Jest function to have been called with. So this line of the test failure output is a bit less readable, is a bit less understandable, especially thinking about you in six months. Thinking about your teammates who haven't seen this code before, and they cause a test failure in the future. Expect Jest function, they have to do a little more looking around. The code output down here does say the onSend variable name there, but if you add the mock name onSend here, it's going to make this line a bit more readable, because it says, expect onSend to have been called. There's maybe other differences, but that's the main difference I've seen with the mock name. So that's why I often tend to reach for it. Yeah. Oh, Andre says, add semantic feedback to your assertion errors. That's a great way to say it. Semantic feedback, it's giving meaning to your assertion errors. It's making the errors more readable to do yourself a favor and your team a favor for the future. So consider it and see if you find it helpful.

So we are ready for another break and ready for another exercise. So this is exercise two. And so let me just show that code just to get it in front of you so it's easy to find. Again, I'm switching over from my lecture sandbox, where I was showing the code, over to the exercisers. Oh, and the answers are here. So let me take my solutions away again. Goodbye. Oops. Back to the main branch. So when you look at your Exercises repo, you'll see exercise two in here. And I won't read through it this time, but I will just briefly say newMovieForm is what we're testing. It is pretty similar to the example we just went through. So it will look familiar too. And you're adding a newMovieForm spec.js file. The file is not there. We're adding a new test file and adding all the tests that you need to fully specify the component's behavior. There's actually more judgment calls in this case, and certainly in TestOrganization as well. So as you go through this, see how you can test this newMovieForm, see what works for you. And yeah, help each other out. Or I'll help you out and I'll keep an eye on the chat for any errors you might run across. It's 38 minutes after the hour now. We'll go for 12 minutes this time. We'll go until 10 till and then we'll check back in and see how you did with the Exercise. So yeah, check out Exercise2. Give each other some help. I'll leave the slide up here with some URLs for help in the docs, if that's helpful. And you can always get the slides from here as well. All right, it's 10 to the hour. So let's come back together and let's take a look at what I did and take a look at what you did. Bruno said, how is this exercise different from the one you just showed us? I'm failing to find differences. It's extremely similar. The difference is that you are doing it. And so putting your hands on the keyboard and actually trying it out can help you ingrain what is learned.

Testing the New Movie Form

Short description:

In this section, we discussed the new movie form and different approaches to testing it. The use of beforeEach and the setup of user events were explained. The importance of isolating tests and creating new mock functions for each test was emphasized. We also addressed questions about clearing components between tests and resetting mock functions. The section concluded with a summary of the topics covered and a discussion on hitting real APIs in component tests versus end-to-end tests. The recommendation was to isolate component tests and mock web service requests. The next section will focus on mocking functions that are statically imported from other modules.

It can help you run across errors, maybe even errors in what I've described and how I've done it. And so that's the purpose of this exercise. It also fits together in a movie-related app and kind of, you can kind of see how the pieces look together, if you look at the other components.

All right, so let's take a look at what I wrote and then we'll hear your feedback and thoughts and questions on how you wrote it. So new movie form. So this is a very similar form. It's just a form that takes the title of the movie and saves it to the server. So in this case, I'm just looking at the output here, looking at the test. It is passing over here. But I did decide to use the beforeEach here, partially just for variety, and I set up the user events setup in the beforeEach because I don't feel the need to see that in front of me. That's not so much explicit setup. It's just, hey, the user event library recommends calling.setup and it recommends calling it before each test. And so I'm setting it up each time. So just to show you, you can put some things in the beforeEach, even if you don't put everything in there. I have a render and save helper function here. And again, just like in the other code we saw before, I'm creating a just mock function and passing it in. I'm filling in the text and I'm clicking the button. I currently have it arranged. So I have two different tests on the two things. We're confirming that I'm clearing the title field and confirming that I'm calling the create handler. So very similar in approach to what I showed before. But as we talked about the different trade-offs in the presentation, you might have taken different approaches. You might have grouped it all together into one test. You might have preferred the duplication in two separate tests of repeating these steps. Or you may be taken a very different approach to testing it, other than what I thought.

So let's take a look at the Zoom chat here. Tony says, Josh, you deleted the beforeEach part. It's not very clear for me. When do we need to clear? What and why? That was in reference to before the break? Yes, okay, so let me answer that. And you correct me in the chat if I haven't followed you correctly. So you, in React, this is a great... Well, this has prompted something important to say about React Testing Library. But tell me if I'm saying the wrong thing and not answering your question. In React with Testing Library, in general in my understanding, it tears everything down in between tests and starts things out. So when you render a component in a test, in the next test, you don't have to like remove that one or like in an after each or the before each. You don't need to clear out the other components. You're getting a fresh virtual web page that the component goes on to automatically in each test. Now for user event, that's not the case. The user event, it recommends doing this setup separately for each test, if I understand correctly. Also, if you have other things like if you share... So here's another thing, an important tip I wanna say, if you set up a mock function, like up here, outside of an individual test or before each, but you just set it up and it's reused in multiple tests, that mock function will remember that it was called before. And so, you could get a false positive or a false negative in another test because it was like, wait a second, I was saying in this test that it should be called or that it shouldn't be called, but it said it was. Oh, it was called because it was called in a previous test run. And in any kind of unit testing approach or testing approach like this with Jest, you want your tests to be able to be run in isolation. That way when something fails and it's hard and you're having trouble figuring out what's going on, you don't need to run a whole long test file to see that failure, you can run just the one test. So this is what, there are ways to reset mocks in between tests, but I actually prefer to assign them to recreate them in every single test. That way I'm just sure, like I'm 100% sure it is a new mock function, nothing else is testing it. I'm good to go. So because of that, you know, each test runs fairly independently and you don't need to do cleanup in a before each or before each one, really all you need to do at the start of an each test is if you have a shared setup that happens that is test specific. And so you can do that in a before each, that you could render in a before each but React Testing Library does not recommend that. They say that for component tests, that's too much interaction and it usually causes confusion because you can't see where, where's the render? I don't see where the render is, but you can create a shared explicit function, set up function that's explicitly called like this, render and save. And that way you can see it. So that's a way that you can kind of remove logic in between different functions to get some repeated setup this needed. Cool, that sounds like that answers your question Tony. Thank you. All right, with that, let's look at some wrap up in this section before we move on to our third and final section of the workshop. So we talked about function props, that's one type of external function when you're passing in functions as a function prop, here's how you can test it. We've looked at that together. Now, the other cases, yeah, so going back to the list, this was part of testing the contract. So we have inputs, we've looked at props and user interaction events coming into component. Outputs, we've looked at rendered UI. We've looked at part of calls to external functions. Now we need to look at a different type of external function and how you might handle it differently, effects and module mocks. So, next, once again, I'm doing this out of order, but I just... Writing that putting this in order that's helpful to talk about. What about functions that are statically imported from other modules? This can be common. I mean, I use a lot of rest APIs. This may be different depending on how GraphQL is set up, I haven't used it a whole lot. But I'm using rest APIs. Usually I'm statically importing some kind of API client from another file. And we'll look at an example in just a second. But before we even talk about the details of that, we'd have to talk about some questions just about APIs in general. Like frontend hitting backend. Is it a problem if you hit the real API? Maybe we don't need to mock it. Maybe our component should hit our real backend server and we're good to go. If testing is all about realism, it's more realistic to hit the real backend. So what I would say is, when it comes to end-to-end tests, you might hit the real backend or you might not. Like the kind of testing like Cypress testing, playwright testing that we're not focusing on in the workshop today. You might test all the way through your frontend and all the way through your backend. Because that way that's maximum realism. There's actually trade-offs there as well. And Cypress's documentation is really great about talking about those trade-offs. And they actually recommend writing some tests in one way and some tests in the other way. So in your end-to-end tests, you might hit the real API or you might not. But in component tests, I would recommend that you would be more isolated. You already have given up some realism in any component tests to focus in on a component. You're rendering out JSX instead of doing what a user does. And so to take that component test and then introduce the flakiness and speed issues and unreliability of hitting a real backend, I don't recommend it. And not hitting a real server that up there. So what are your options for mocking web service requests? In this diagram here, I'm laying out a kind of general architecture that you might have in how your code is set up.

Mocking Web Services with Jest Module Mocks

Short description:

There are different options for mocking at each step of the way when it comes to web services. Jest module mocks is a versatile tool that can mock out requests to web services by cutting things off at the level of JavaScript or TypeScript imports. It is a fallback option that can be used in almost every case for JavaScript or TypeScript projects. Other options include fake modules, Axios mock adapter, fetch mocking libraries, GraphQL-specific mocking packages, Nock, and MockServiceWorker. While Jest module mocks is recommended for its versatility, other options may be more suitable for specific cases. It is important to have Jest module mocks in your toolbox and explore other options as well. The lecture provides a link to the Jest module mocks documentation for further exploration.

Because there's different mocking options you can use at every step along the way. So say this is the rest of your code that's not directly related to web services. But then you have an API client module, maybe you have one module, one JavaScript TypeScript file that is like, oh, here's my API client. Maybe that uses Axios under the hood or maybe it uses Fetch or some other kind of library, but some third party library to make HTTP requests. Ultimately, you're using the browser's HTTP request support. So like even Axios is using the browser ultimately, they didn't sneak anything else in there. And it's ultimately hitting a separate web server that's running somewhere. So at each of these points along the way, you have options for mocking. And it's kind of helpful to know that they're all out there. You don't have to learn all of them, but just knowing there are different options so you're not confused when you hear about other things, you can see the category they fall into. And if you feel like it, if you're looking for something new, you can assess the trade-offs.

So here's the overwhelming list of some of the options here. So when your code is importing an API client module, you can use a Jest module mock. And this is the approach we're gonna look at in the workshop today. You can also use a fake module, which is to say it's a real running code, is just a fake version of it that only just stores the data in your front-end application or something. In Axios, if you're using Axios, for example, you can use Axios mock adapter. It's an Axios specific NPM package that lets you mock out HTTP requests and responses. There's other ones for Axios as well. There's ones for fetch. If you're using GraphQL, there's GraphQL specific mocking packages as well. So this is like mocking at the level of the third-party code that's handling your requests. Also, if you wanna go all the way to the browser support of HTTP requests, you can use libraries like Nock or MockServiceWorker. So these actually work, whether you're using Axios or Fetch or GraphQL or anything else. You can mock them at that level. And then finally, you can go all the way outside your application so that all your running code is exactly the same, but instead of hitting a separate web server, you can hit a local web server. Like say in a continuous integration environment, GitHub Actions or whatever, you can spin up the... Depending on your project setup, maybe you can spin up the backend web server locally on CI. That is helpful. There's some trade-offs there. There's some benefits. Or you can create what's called a fake web server that doesn't run your real backend logic, but it's a real running web server that takes HTTP requests and sends back HTTP responses. And it just does some minimal behavior that's helpful. Maybe it just stores all the requests in memory. Maybe it's a tiny little Node web server or something like that. All these different options. There's different levels of realism. There's different levels of coupling to specific applications or even the structure of your application. So I can't teach all of these. That would be a full day workshop even to scratch the surface of all of these options. I just present them to you to let you know and encourage you, like, if you don't prefer the trade-off if we talk about today in the workshop, you can look in other ones. And if you're already using another one, they are great options.

So let's talk about Just Module mocks. We'll look at the docs. Well, here's a link to the docs, but today I'm gonna teach Just Module mocking. And there's one main reason for that. And it's the reason because of, like whatever API protocol you're using, whatever third party library you're using, whatever backend technology you're using, you can use Just Module mocks to mock out the web services. And this is great because testing is hard enough and we want to remove barriers to testing whenever possible. And something I can see that folks run into is like, oh, I used to use Axios and I learned Axios mock adapter and that let me mock out my back-end request. But now I'm using some GraphQL library. That's not running through Axios. And so now I don't know how to do mocking. I need to figure out, is there a mocking library specifically for this GraphQL library or that, or maybe it's, maybe it's not JSON. Maybe it's XML or some GRPC or something like that or protocol buffers. Like, oh, I can't use the testing libraries I've used before. And I don't want you to get to the point where you are unable to test something. When you use Jest module mocks, that cuts things off at the level of JavaScript or TypeScript imports, so that whatever first-party or third-party code is living behind that, you can mock it out. And so you have and option. These other ones may be better options in many cases, but the Jest module mocks is really a fallback for no matter what, there's probably some exceptions I'm not thinking of, but like if you're in JavaScript or TypeScript, probably just about every case you can use Jest module mocking to mock out these requests to web services. So it's a versatile tool, I wanna make sure you have it in your toolbox. That's why we're focusing on Jest module mocks. We're gonna ask, which level do you recommend us to mock? I recommend learning Jest module mock so you have it in your toolbox and then try others. On my personal side projects, I've been using Knock lately and a mock service worker has a lot of popularity. There are some things about its testing approach that didn't align so much with me. Actually, the maintainer of it was nice enough to respond to one of my videos and we had a good conversation about that that was happy spirited. But yeah, I've been leaning towards Knock for kind of end to end testing. But then for a more isolated component testing, I like Jest module mocks. Well, let's look at Jest module mocks and you'll get to see those trade-offs for yourself. This is a link to the documentation. This is available in the slides and we'll put this in, when we do this in the exercise coming up, that link will be there for you to dig in. This time I wanna look at the code itself before we look at the mock functions in the abstract. So let's go to the code. All right, we're in the lecture sandbox again. I'm gonna pull up lecture three. All right. So we have here an extremely simple data loading component. I'm violating all the latest react recommendations I'm loading that data in a use effect. Incidentally, something that I would like you to know is when you're testing the contract, your code doesn't care if a use effect was used or if react query was used, or if Apollo client was used. It just cares that the right outputs happen for the right inputs. And so in general, there's exceptions depending on how architecture is set up. So in general, when you're testing the contract, you can refactor from use effect to react query or other things like that. So, it's very helpful. So that's why I'm using this old style simple code and you can use the same testing approach whatever currently and whatever architectures you use in the future. This is a data loading component. It starts out with loading widgets, whatever widget it is. We start out with an empty array of widgets, and then when the component loads, we call from this API module that I have. We'll look at that in a second. We're calling get widgets, and then when we get a response, we set them. This could be a sync await. I'm just using promises here for simplicity and use effect. And whatever widgets we do or don't have, we iterate through them and we render them out on the screen.

Mocking API Module with Jest Module Mocks

Short description:

We want to test our front end even if the API is not available. Jest module mocks allow us to mock out the API module and control its behavior in the test. By default, Jest module mocking mocks all functions of the API module as mock functions that don't return anything. We can configure the return value of the mock functions using jest.mock. This allows us to isolate the widget container from the API module and specify the inputs and outputs in the test. We can control the behavior of the API.get function by calling it in the test and configuring its return value. This way, our front end tests are not reliant on a live server and can be run reliably and independently.

We just rent the name on screen. Very simple. The API, in my case, I'm using axios here and I'm configuring it with a base URL. The URL might be gone actually, I'm not sure, but we're mocking it out in the test anyway. No, I think it's there. And I'm just exporting it as is. So my API module here has the same methods on it as axios itself. It's an axios instance. You might have an API module that defines specific functions for your backend. Like load my data, load my ticket sales and load my movies or my events or whatever. So, but whichever kind of API client module you have, this approach will work just the same.

In our case, we're just doing a call and passing in the URL to it there. So how do we test this? Let me get my notes up so I'm not just winging it because I'll miss things if I do. Yeah. So we have a test to start out. I did some of the basics where I render the widget container and I'm checking the results. And so let's go in here to lecture three. I'm checking for the results. I want widget one to be available and widget two to be available. And I'm getting an error here. It says unable to find an element with the text widget one. I actually forget if I have this as a running server or if you need a URL or something like that. So let's actually just check that out and see. So if I go to here to widgets, oh yeah, I undeployed that. Okay. Well, so yeah, so this, I've undeployed this API actually. And so it's not there anymore but we don't want our front end tests to break. We want a way to test in our front end test even if the API is not there anymore. And so how can we do that? And, but there's also problems when we do hit the server it can be slow, it can be unreliable. And so what can we do? We're gonna jump ahead into here. One second here. We're gonna use just module mocks. We want our tests not to care if or whether there's a server there or whether it's up or whether it's down or whether it's slow. We want to reliably be able to say, cause at this point our test has not mocked the inputs and the outputs. We're not specifying the inputs we're getting from that return value from the server. And we want to specify that in the test so it's under control. So that we're not reliant on a server live somewhere that someone like me can undeploy and break all our tests sometime. So the way we can do that is with just module mocks. And let me show you how that works. First, what we want to do is we call jest.mock, and these names aren't the best names honestly. This is remember we use jest.fn to create a new jest mock function. When we're mocking a whole JavaScript imported module, we call jest.mock at the top level of our test file. And we give it the same path that we use in our production code to get to that file. So we're mocking out the API module, which is to say the API file. So let's see what happens when I save that. Well, I expected the test to rerun. Why didn't the test rerun? Oh, actually the test blew up entirely. Usually jest auto rerunning works, but I found something about this example here where I'm failing to hit this web server. It causes that to completely break out of jest. So I had to restart jest again. So in Widget Container, what are we seeing? So now we're getting this error, cannot read properties of undefined reading Venn. So API.get succeeds, apparently, but calling.venn does not work. And it's saying that the return value is undefined. So when we call API.get, that returns undefined. This is the default behavior of jest module mocking before you do anything else. It takes, and there's nuances of like, what if you're exporting an object? What if you're exploring top-level functions, named exports, default exports. I don't have all the details. But what I do know is if you're exporting an object, like the API object, an object that has a get method on it, jest will mock that out so that API still exists and get functions still exist on it. But they are all mock functions. All of those are mocked out as mock functions automatically, but they don't return anything by default. Let me log that out just so we can see it. And actually we're going to need this anyways. But let me log it out in here. Let's say console.log API.get. Let's see what the jest module mocking has turned. Let's log out API. Let's see what it's turned API into. So check it out, we've logged out the API. Let's see, our function wrap, I think that, yeah, so check it out. So we have a delete function. We have a get URI function, we have a get function, head, you know, head and options or HTTP concepts. So jest has inspected, and check it out, is mock function true? Like this is some internal jest mock function. So I don't know all about the internals of mocks, but apparently this is what a jest mock function has inside it, but at least we can see that jest has put all these mock functions on this object that allow us to control what's happening. So we've now isolated our widget container from the API module and we can control it in the test. So let's see what we can do about that. So by default, you know, jest doesn't know what we wanna return from these functions. So by default is returning on, let me go back to where we saw that error message before. It's putting it into a few different, yeah, here we go. Can I rewind properties on defined, reading then? So the fact that my production code, I chained event onto this that, you know, I'm expecting a promise to come back from get that will resolve asynchronously when the web service response comes back. Jest module mocking doesn't know that that needed to be a promise. So I need to configure that. So I can do that in here. So in, when you've mocked at a module, in your tests you can call functions on it. So I say API.get, that's the API.get method. Oh, I need to import it as well. I'm gonna move that import over. So I'm importing from that module the same path that I'm using for the mocking. Syntactically in JavaScript, I think the Jest.mock needs to be further down like this. But like Jest does some magic to make sure that it's mocked out before we get access to it. So by the time we get API.get, it is a Jest mock function.

Mocking Resolved Values with Jest

Short description:

We can use the Jest API mock resolve value to return a promise that resolves to undefined. This approach allows for troubleshooting by making small changes and observing the test output.

So here we can do mock resolved value. We could do a mock return value because this is a Jest API. We gonna do new promise, to return a promise. But actually, you know, returning promises is so common that Jest has an API for it. It says mock resolve value. So that's gonna return a promise. And if I don't pass anything to it, it's just a promise that resolves to undefined. So let's just save this and see what this changes in our test output. This is a good troubleshooting approach incidentally. If you're not sure why things are failing and you think trying to see if you're going the right direction you make one small change at a time. Let your tests rerun to get quick feedback and see what you've changed.

Mocking API Calls and Handling Asynchrony

Short description:

We mock the resolved value of get with our structure of what comes back from Axios. We set the input to test the contract. We wait for the response to come back from the web service using the Find By API. After waiting, we check that the desired elements are rendered on the screen. We discuss the need to give some time in our test to allow the response to asynchronously make it onto the page. We explain the use of Find By to wait for elements to be found on the page. We mention the ESLint warning about unhandled promises returned from Find By. We emphasize the importance of handling the promise by using await and async. We highlight the controlled inputs and checked outputs of our component. We acknowledge a weakness of Jest module mocking when it comes to API calls.

So once I've mocked the result, get with a resolved value, now we get a different error. We get past the.then. So apparently that works. But now in the set widget line, it says cannot read properties of undefined reading data. So this is saying that response is undefined. And that makes sense actually, because we've said we've mocked with the resolved value but we didn't pass the value in. So that's gonna be an undefined in JavaScript by default. So that's why we get the undefined there. What we really wanna do, is wanna pass in a response here. What do we want our response to be? And so we can put that in here. So in our tests, we say we mock the resolved value of get with our structure of what comes back from Axios is there's a data property nested under it. So we say data, we have an array, and then here we put our mock data. We don't have the widgets in front of us, but clearly they have an ID and a name property. So let's just say ID one name widget one, and we need two. So ID two name widget two. Also note, like we were doing before with the movie titles, I'm not mocking out, I'm not putting all of the attributes that are on the response object that comes from Axios because Axios needs all those. I just need response and response data. And so I can just provide the minimal data that I need to get this test to pass. This keeps my test nice and focused. So what I'm saying here is I'm setting the input to test the contract. I'm saying when this component receives the following response back from the API, that's the input. Make sure that this is outputted to the screen and this is rendered to the screen. So let's save this and see what happens next. Oh, I see that Jest crashed again, so let me run that again. Alright, so we get an error now. And so what does it say? It says unable to find an element with the text Widget1. And notice it is giving us the JSX output and look how minimal it is. We've got a body, we've got div UL, we've got our unordered list, but we don't have any list elements rendered out underneath it. What's going on? Well, I can tell you what's going on, but let me see how this explain it. Do I have a console logging here? So, what's happening is there's asynchrony involved. So, we have a, this is returning a promise. And so even though it's not coming from the server, even though we've told that already, this promise is resolving, that promise is still resolving asynchronously. And so it's not, if you know, I guess I'm going to speak not with 100% confidence, but if I understand correctly, you know, this gets called on another tick of the JavaScript event loop. And certainly like this re-rendering of setting the widgets, which caused the widget to re-render, that happens after a delay as well. And so if you call screen.getByText, that expects it to be available immediately, all right. I think that does, that does work with, if you have like some synchronous code that does set state. So, I think a React re-rendering would happen here. It's the fact that we're asynchronously going through a web service call with a promise. That's why widget one is not available immediately. I forgot to put this in my notes here, but let me add a console log here, just to get some insight into what's going on. Sending web requests. I'll put a console log here, receive web response. And let's see the timing of those console logs in our test output. Let me focus this back into lecture three as well. So sending web requests and receive web response. But notice this here, this warning here. You may, if you've done any React testing, you may dread this warning, because this happens all the time. And it's not React's fault and it's not React Testing Library's fault. They're both actually working together to warn you about something. And what they're warning us about is exactly what we're talking about here. So let's check it out. Let's read the error message. It doesn't always work, but it often works. It says, an update to widget container inside a test was not wrapped in Act. When testing code that, so it's not get distracted by the Act, usually actually the response is not, you're not supposed to wrap it in Act yourself. When testing code that causes React state updates should be wrapped into Act. This should your testing the behavior the user would see in the browser. So yeah, now actually, now that I think about this, I wish this error message was phrased a little differently. Kent C. Dodds has a great blog post. He's the original author of React Testing Library. He has a great blog post about why this happens and what to do about it. And it explains it really well. So I've linked that on the workshop web page. You can get to that article. I recommend reading it all the way through because it's very, very valuable. But the short version is we need to wait. We need to give some time in our test to allow the response to come back from the web service, even though it's mocked out, to allow it to asynchronously make it onto the page. So the way we can do that is with another API called Find By. So we looked at Get By and we looked at Query By. Find By returns a promise. And this says wait some amount of time, a couple seconds, up to a couple seconds if necessary, for this to be found on the page and then continue on. ESLint will actually tell us, a promise return from Find By Query must be handled. So this means we need an await right here. And that means we need an async right here. So basically we're saying, hey, render this out, and we know this is not gonna be here right away. It's coming back from a web service. Give it a little time and wait for that to come up and then continue on. So we save and our component actually passes. When I remove these log statements. So after we wait for Widget 1 to be present, both of these are found. Now notice actually that we don't need Find By text on the second one, because we're waiting. Like by the time Widget 1 is present, Widget 2 should be present as well. And so, cause they're both rendered out at the same time. So we just need to Find By on the first one, the first one that needs some time. And then after that, we can see the other one immediately. Cool. So we have now, we've controlled the inputs and we control and check the outputs to our component. There's one other thing, and this is actually a weakness of just module mocking when it comes to API calls like this. So depending on what level you're mocking at.

Confirming Outgoing and Incoming Data

Short description:

We confirm that the component calls the correct endpoint on the server and receives the expected response. By using just module mock functions, we can set expectations on the API calls made by the component. In this case, we ensure that the get function is called with the 'widgets' endpoint. This approach allows us to verify that the component's output is based on the correct input. By confirming both the outgoing request and the incoming response, we can ensure that the component behaves as expected.

So we're just saying, hey, if you call Get, resolve it with here. But we're not just calling Get, we're also like what is the essential in the contract of this component? It's important that we call the widgets endpoint as well. It needs to not be something different. So for example, if I accidentally change this to fidgets, in real life this wouldn't work, but when I save and reload, this does still work because our just module mock has said, hey anytime you call api.get, please resolve with these values. So this is actually, given as a false positive, it would be good for us to tighten down the contract for our test to tell us if we have called the right endpoint on the server that's going to give us these results. Sometimes folks are hesitant to use mocks because it's not realistic and it might not match up with what's real in production. A way you can get around that or mitigate that is to intentionally say, I'm confirming everything in what's outgoing and I'm confirming everything that's incoming as well. So the way we can do this is we can do, api.get is a just mock function so we can do an expectation on it. We can say api.get, expect api.get to have been called with widgets. It's important that we call that right standpoint otherwise this mock return value is not gonna reflect what's gonna happen in reality. And you can do the called number of times, called nth time with, all those just mock function APIs are available here as well. But this confirms for us that the right endpoint was called. So we save and it now fails because of my broken code but when I repair it, I change it back to widgets, the test now passes again. So we've confirmed on that. We've confirmed in this sense we're checking output and input. We're saying this component needs to go out and make a request of this right endpoint. So an outgoing web request is output for the component. And the response data I get back is input back into the component. So we're checking both sides, like assert that the right output is sent and then set up the situation of the right input coming back to make sure this output comes out as well.

Jest Module Mocking and Find By APIs

Short description:

Jest module mocking allows you to intercept functions from other modules and turn them into Jest mock functions. You can mock the result value and do assertions on how they were called. To use module mocking, call Jest.mock at the top level of your test file and pass the path to the module you're mocking. Import the mock functions in your test file and use JestMockFunction APIs to mock return values or resolved/rejected promises. When testing data loading, use find by APIs to ensure the asynchronous speed of promises. It's important to confirm both outgoing requests and incoming responses when connecting to web services. Mock modules contain mock functions that can be controlled using mock return value, mock resolve value, and mock rejected value. The workshop also covers different find by APIs for checking elements on the screen.

All right, I've been talking for awhile. So I'm gonna catch up on the chat. Lucas said this is probably also true for Knock and Mock Serviceworker. But I've been talking for a while since I decided to see what that is in context of. Jorii asked a question about functions from Hooks. Jorii, I will try to catch up with you in the next break cause that's a little bit unrelated. I can give you some detail there. Why would you use Mock Serviceworker from component testing? Super developer experience. Polyus asked, why would you use Mock Serviceworker for component testing? You might do that if you are doing component testing but you're testing a lot of your components together. Now React Testing Library actually encourages, hey, when you have a component, you have a high-level component, maybe it's a whole screen or a whole page component, it will, by default, put all the child components and all the things they integrate within there. And so maybe you wanna test a lot of your components in integration. Maybe you're not able to use something like Cypress or Playwright for end-to-end testing, or maybe you just prefer it. That actually helps me in React Native as well because end-to-end testing is challenging in React Native and so I like to do component testing of a lot of things together. One of the other things though, if you're using Mock Serviceworker or Nock, is that they're APIs because they're HTTP-specific, allowing you to attach this part and this part together. So you can expressively say, when the user hits this endpoint, return this data, and so they're just a bit more targeted for this scenario. So that's some of the benefit. Cool. If you have two get calls, should we do api.get? Yeah, so Mariana asking if you have two get calls, how can you mock different things? Yes, yeah, like and so Rian replied about mocking the implementation, checking what was passed to get and replying with different data, and so that's helpful. And that's actually another case that Nock and Mock Serviceworker can help because they're set up to mock different data for different endpoints, even if you have the same function called to dot get, they make it easier to mock different data for those. Dominic says, how can we delay the promise to test the loading state? So a trick that I use for that is a promise that doesn't resolve, doesn't settle. So if you all, you know, usually we don't actually build promises ourselves. Usually they're given to us by third party APIs. But you could say api.getMockReturnValue. So we're mocking the return promise, you can say new promise. And if you don't, you know, a promise receives a resolve and reject, and you're supposed to call that at some point in here. But if you just don't call it, this is a promise that never settles. And that actually doesn't cause memory leaks, I don't think, or doesn't cause any problems with just tests. But this would just give you an indefinite loading state. And so that way you're sure it's never going to resolve, you're sure you're not going to have timing issues, and you won't get that act warning about something changed later. So yeah, creating promises that don't settle is a great way to test loading states. Does it wait before a screen find by text works similar to waitFor? Yes. I think the find by APIs are newer, and they're recommended. Sometimes you still need a waitFor, or a waitFor element to be removed, which is another API. But if you're just waiting for something to be present, the find by APIs are kind of straightforward. You just type them straight ahead. But yes, as Vlad said, the RTL docs have a lot of detail on that. Cool. All right, let's take it back to the slides, because there's a lot going on with these. So let's recap the information we saw with Jest module mocking. And so let me just to repeat the distinction before, in our last segment, we talked about Jest mock functions, which is when you create a function, like I'm creating a function and I'm passing it in a prop or putting it somewhere. Jest module mock is where you're pulling something in from another module and it's giving you functions. Jest module mocking allows you to intercept that, to turn those into Jest mock functions. Then you can then mock the result value and do assertions on to see how they were called. So to walk through those steps again, the way to do a module mock is you call Jest.mock. This needs, I'm pretty sure this needs to be at the very top level of your test file outside of the describe. So that means for all the tests in this file, that will be mocked out. You pass the path from your test file to get to the module that you're mocking. That does work for third parties as well. So if you're using like Axios directly, you can just pass Axios in there. Just whatever the form you're importing from, the string you're importing from in your production code, in your component, you pass to Jest.mock. Then assuming you probably need access to those mock functions in your test, you import them in your test file using the same import you'd use in the component. And from there, you can call JestMockFunction APIs. You can mock a resolved value, which is what you'll commonly use when you're doing API calls and stuff like that. But if it's a synchronous thing, you can just mock a return value. If you check the JestMockFunction APIs, you'll see all the options available there. And in the case of here where we're testing data loading, or waiting for this to come on the screen, for the first one, we use a wait find by to make sure it has time, to allow for the asynchronous speed that happens for the fact that we're getting a promise back from a web service called. But notice, it was, well, let me show you the speed, just to kind of interrupt myself real quick. Hit return, and this comebacks right away. So it's not waiting five seconds or one second before it even checks to see if it returns. It's coming back very quickly. But just the find by gives it a few seconds if it takes up to that amount of time. And then for the extra safety here, we're doing a call, an assertion on the call that was made to the mock function to make sure we pass the right arguments. This is something I see, no matter what technology you're using, we're actually actually using Axios Mock Adapter in my client project, but it's very tempting for us. You know, when you write your component code first, and then you write your test, and it's big component because it's real project. It's not just my trivial example here. And it's like, oh, I'm gonna do so much work to get this working. This is my first test mocking on HTTP requests, or there's just a ton going on in this component. And so you kind of just want to get it passing. And so once it's passing, you tend to want to move on. But remember, we saw in our test that even though the test was passing when I had mocked this result value, we weren't fully confirming the contract. We weren't confirming that that outgoing request had the right URL. So it's always tempting, I mean, so Axios Mock Adapter, you can say, I think what we run into, you do choose the URLs there, but our temptation is not to put it pass in like the query string parameters or the post body to not assert against that. So then we're not actually confirming that we're sending the right data to the server. It opens us up to false positives. So when you're thinking about, I mean, I didn't make a slide for this, but when you're thinking about connecting to web services, remember to confirm what's going out and provide what's going in. If you just do one side or the other, you might be lacking what's needed to get full confidence in what's going on. Yep, and so mock in mock modules, sorry, let me say this again. When you have a mock module, there's functions within it that you're given, those are just mock functions. So you can mock return value. I don't think we saw it before, but you actually know, I don't think these came up before because when we were doing that on send function, we didn't care about what came back, we ignored the return value. We just needed to confirm that the function was called. But when you do have a mock function and you do care about what's returned, or it's a promise that resolves or rejected, then you can use these mock return value, mock resolve value, mock rejected value that allows you to control what comes back to your code from that mock function. Just to kind of visualize those finders we talked about, first in the workshop, we saw these get buys. Those allow you to check for something on the screen and it errors out with helpful JSX output if it isn't found. We saw query buys, and I will say, I don't know how to name these, it's not immediately obvious from looking at the name which one is which, you just kind of get used to it over using RTL over time. But query buy, what it means is, if it's not found, it gives you a null back. So that allows your tests to succeed when you expect there not to be something present. Then there's find buy. And just like with the others, find buy is a prefix and you have all the same suffixes. You have text, all text label texts, et cetera.

Testing External Functions and Hooks

Short description:

Hooks can provide data or functions from a React context. You can wrap the context in your test and provide the data. If functions are coming through a hook, you can use Jest module mocks. Testing the contract involves testing props, user interaction events, and the outputs of calls to external functions. The workshop also covers testing the data loading behavior of a movie list component using Jest module mocks. Participants are encouraged to test the movie creating functionality as well. They can also explore other mocking libraries like NOC or mock service worker.

Roll, find by roll. Those are all there. Find buys return a promise that wait and give you some time for something to asynchronously appear. And so that's the purpose and the use of find buys. So with this, we have covered at least briefly, at least introductory, how you can handle functions, statically imported from modules. With this, I actually wanna go directly into the last type of external functional listed here, which is function from hooks. And so the reason I save this for last is that hooks is one mechanism to provide data to your component, but what's happening behind the scenes can vary. Hooks, some of the power of custom hooks is you can put whatever you want behind there. So let's think through some different things that can happen with hooks. If hooks give you data or a function from a React context, for example, that's pretty common. That's kind of like a prop value or a function. And so we don't have time in our brief time because we got half an hour left and I want to give you a little buffer time if I can, and we're definitely not running long. But so, you know, if you have data coming in from a context, you can actually wrap with that context wrapper in your test and provide the data there. So that acts a lot like just passing in via props. If you have functions coming in through a hook, those, so say, you know, maybe I have a hook that allows me to hook into my custom API client that goes to the third party. So maybe your component is in one file and your custom hook is in another file, but then you still have that static API client that's statically imported as a module. Well, you could actually do the Jest module mock, and so that way your component uses the hook and it's only at the point that the Jest module mock comes in that that happens. So, yeah, so you know, basically it is a bit of a fiddly answer in that it depends when it comes to hooks. But if you think about hooks as just taking some code that was in a component and pulling it out in a reusable way, if you think about the techniques we applied to all the things happening in your component, those same techniques apply to hooks as well. But context is kind of different, so maybe next time I do this workshop, I'll actually add an example with context. But really, it's, you know, one of the great things about React Testing Library and the fact that your JSX looks just the same is, hey, you're wrapping with a context wrapper, a provider in your production code, wrap it with a provider in the test as well. This is big in my current client project. We have a lot of different contexts, probably your projects do as well. And so when we set that up, it's like, cool, like, let's just make these available in the same way in our tests so that the data that is needed and material UI configuration is needed and things like that. So I don't expect my verbal explanation there to fully answer all your questions about context, but just take the encouragement that the techniques we've provided often work for hooks as well. And so with that last middling answer, we have covered the last type of external function we've listed here. And to go back up to our list of testing the contract, we've covered an overview, a survey of the inputs and the outputs for components. You're now equipped and you'll have the recording later and you have the slides right now to test props and user interaction events coming in. And I really should update this because response data coming from a web service request or any responses from an external function is input to your component and you're able to test the outputs of the rendered UI confirming that's there, including just to call back to it, the note that I said where I would not recommend testing every single detail of the JSX structure of your rendered UI, but tests the crucial things that apply to users. And if you follow the react testing library recommendations and dig into that, it'll guide you in that direction. And we're testing the outputs of calls to external functions. Call to an on send prop that was passed in. Call to a get call to a server, making sure we hit the right URL. So with this mental model, you are equipped for thinking about how you test components. We have another exercise and I'm glad we have buffer time cause this is good, cause we're gonna have time for some wrap up at the end before we go. So I wanna take this break and let this happen. Exercise three is very similar to the others. If you felt like exercise two is very similar to the example that I showed, exercise three would be very similar as well. So let's pull that up and let me show you that. Where is that? In exercise three, we have a movie lists and our movie list loads movies from the server. And actually, if you follow the README, you should actually have, unlike my example code, you actually should have a running app if you want to, if you get this API key to get a real data from the server and be able to save data to the server, but that's not essential for the testing. Movie list is written and functioning, there are no tests for it. Create a movie list spec and add the tests to specify the data loading and display behavior. So one important note, so this component, let me pull it up, just cause of the way the application is structured, we are loading the movies from the server, but we also have a post to create a movie on the server. So here we have our new movie form and we're passing in that prop that handles creating. So here's where it actually goes over to the server. So what I'm requesting for the exercise is to start out, test the data loading behavior. If you get extra time, or if you want to do this after the workshop or while we're wrapping up, you can go further and test the movie creating functionality as well. And what that will let you do is, that will let you see the difference of testing new movie form, which did not have the responsibility of doing the data saving itself versus here. Like if you're testing movie list and you're testing the create functionality through this component, you will need to mock out the API post. And so you'll actually see the data being sent over to the server and you'll be confirming that. But that's going further, that's extra, you may not have time for that. But yeah, the key is designing tests to confirm the data loading behavior using just module mocks. Another thing you could do if you want to go further is you could try another library for mocking approach. I really like NOC, mock service worker is really great as well. So you could try one of those, write tests in both ways and see what you think. And you can decide for yourselves what the pros and the cons are of each. Cool, so I'm gonna stop babbling now. It's 34 minutes after the hour. Let's go for 11 minutes. So let's take a break and do the exercises if you like until 15 till the hour. That'll give us time for wrap up and to end a little early. Cool, so let's go with that. Here's the help links for mocking modules and I'm gonna keep an eye on the chat as usual, including responding to the questions that have already been posted. Let's get this discussion going. So if you all have any questions, feedback, alternate approaches, you can share those. It looks like, oh, looks like I do have my deep integration tests as well. So that'll be fun to share. All right, so let's make sure we have the list passing. This is passing. All right, so I'm testing my MovieList, which again, to get in front of us, very similar to the example that I showed before, starts out with an empty MovieList and loads it from the server and then renders it out. Interestingly, they're just sort of a note here. This renders out using the MovieRow component that we tested before. So we tested the MovieRow at a low level. Now we're testing the MovieList at a higher level. So let's see the judgment calls I made in testing that. I confirmed it loads movies upon first render. So I have used jest module mocks to mock the API module. I am calling mock resolve value to return the data from there, render the MovieList. This time I don't know if I had any particular reason why, but I put the call to api.get, sorry, the assertion about the URL that we use to call api.get. I put that above the await. And to me that kind of helped me to see as I was visualizing this. Like, oh, I rendered the MovieList, the call to the server is made, and then after that's done, when we await, we'll see this on the screen. So conceptually, it kind of like the way it walked through made sense to me. So that confirmed that. So note a judgment call that I made here. I decided what was useful for the MovieList test is to make sure that the title showed. That was a way for me to see that the data from the server was in fact coming back. What I did not test was the new badge. Now I could have done that.

Testing Component Logic and Best Practices

Short description:

When testing components, it's beneficial to test at both higher and lower levels. Testing lower-level components individually provides value, while testing higher-level components that assemble other components together ensures their correct functionality. The MovieRow component is tested directly with synchronous props, which adds value. By combining testing approaches, component tests can effectively cover different levels of logic. When testing complex forms, it's advisable to test the entire form at the lower level and focus on specific inputs at the higher level. Mocking child components can be useful in React Native testing. Get-by-Test ID is less preferred than other methods, such as Get-by-Role and Get-by-Text, which are more accessible to everyone. However, it can be used when other methods are not applicable. The choice of testing method depends on the specific use case and the need to ensure accessibility and maintainability. Cypress, an end-to-end testing tool, does recommend using test IDs in its documentation. The decision to use test IDs or other methods ultimately depends on the specific requirements and context of the project.

I could have added a new, added today property to one of these movies and then check for that to be present. And for two things, that's not too much work. If there was 10 fields in MovieRow or a hundred fields in MovieRow or a ton of different interlocking conditions in MovieRow, then fully testing all of that through MovieList would be very complex. So I don't recommend that. One of the benefits of component tests is you can test at higher levels and at lower levels. And so I like to think about it is in terms of like, what are the unique things? What's the unique logic that each component at each level has. MovieList doesn't really care about what happens inside MovieRow. When I make sure that MovieList works correctly I just need to make sure that some representative part of MovieRow is rendered out. Now, does my test confirm that it's actually MovieRow is rendered out? No, I could replace this with just a div here that rendered the title. And so my component isn't confirming what is the exact right child component that I'm using. But I don't think that's needed. I don't think that is necessary. If I didn't have the MovieRow component at all I could just try to fully test all of it through the MovieList. But if MovieRow got more and more complex it would be harder and harder to see that indirectly. So having a MovieRow test that passes in props directly synchronously, no async involved, no findBy weighting involved or anything like that that adds a lot of value. So I think that with component test using a combination of testing lower level small components and higher level components that assemble other components together provides a lot of value. I wanna look at the chat here before I go on to the other section. How do you structure the describes and it for the create functionality without getting too specific about new MovieForm? Cool that's a good question Jory. Let me take a look here and see how I did it and then see what I think about it if I like or don't like how I did it. So it can add a movie to the list. So I'm confirming the through here, the new MovieForm, the adding works. And that's important because I have not tested the handle create function yet. The new MovieForm test did not use the handle create function cause that was passed in from here. So if I wanna cover this code I need to test it through MovieList unless I did some other kind of indirect approach. So how did I do that? This is that bonus section. So I rendered the MovieList, but I mocked out the get. So actually for this test, I didn't actually care about any movies starting out in the list. So just for simplicity, I mocked the get to return and empty array. So I'm a mocked out the post cause we need an actual successful post to be able to happen here and to come back, to set the movies. So let's walk through this in the order that the code actually runs. I render the MovieList. I do actually type in the text and click on the save button. And then I confirm the post was called. This is even extra important I feel like for calls that go to the server that save data to the server, cause you have to make sure that the right data is passed along and it's actually sent out to the server. So I think confirming that is very important. And then the call of the post returns my mock data. So that is, you know, the way my endpoint is set up, I return an object that actually has the title it's sent back to me and I actually get an ID assigned by the server for that record. So I confirm that once that comes back, the production code saves that into the state, I can confirm that I can see that new movie title on the page. So to Jory's point, this is kind of pretty specific about the new movie form. Like this test knows that I'm typing in the text field and it knows that I'm typing a save button. So something that could be different though, is so my current client project, we have some very complex forms. And when we're testing the forms directly, we test to make sure we fill out all the fields and that when we click send, all the fields are sent back out to the passed in function prompt. So that's thoroughly covering every detail of the form. Now, if I had a parent component like this and we test those components as well I might just fill in the minimum. Maybe only one field is necessary. Maybe just a name field, a title field. And so that is like a deep test where I say, hey yeah fill in the movie title but don't fill in all 100 other fields about directors and years and all the casts and all the one billion people in the credits that moved in the movie. Don't test those at this level. Test those at the new movie form level. So the new movie form is broad where it broadly covers all the form. And then this parent component test is deep, it's vertical, it's focused. It's just doing the minimum needed to get into the form and get back out to get this code called. If that doesn't work for you in a certain case, some other kind of mocking might be needed. In React Testing Library you can mock child components. In React Native you actually need to do that if any of you have used React Native because your JavaScript code calls native code. So that's another whole mess of things. But yeah, so it can be messy, it can be tough, and there is some duplication of testing logic for sure. But that's a few options that come to mind. Peter D., how are you sure the title element you find is not the input text itself? That's a great question. I was thinking that Peter as I was thinking through this. I don't think the get by text, find by text will find text inside inputs, but I'm not sure. Something you could do, and if you felt like it would be good to test that to verify it. Something you could do is you could do the assertion here to make sure that this text field is actually cleared out. That it has an empty string in it so that way where you find it on the page is not from the input. Another thing on our client project test, we've been using, I think the API is called within, this is an API call by React Testing Library, but you can find one element and say, okay, look for this within this other thing. And when you have are your roles and things like that, you can find like sections and things like that in columns and you find data within them. So in our complicated app with like modal forms and stuff like that, we found that that's been helpful. So that can be a way to narrow down the text that you find as well. Coney asks, is Get-by-Test ID less preferred than the presented methods? It is. So if you check the, let me go back in the slides real quick because this is a great point to go back to as we're getting ready to summarize. Somewhere way back in here, we have the link. Luckily these slides are available to you afterwards. In this documentation and the Tesserant library website, which query should I use? I'm gonna pull it up in here. As part of the screenshot that I didn't show, they order these in priority order and Get-by-Role is the number one recommended followed by these others because they're accessible to everyone. Test IDs is listed at the bottom and they say the user cannot see or hear these. So this is only recommended for cases where you can't match by role or text or it doesn't make sense to do so. So I would not say never use Get-by-Test ID but on our client project and on my side projects I try whenever I see it, I try to find another way to do it. For example, it could be assigned to a component or you're starting on something that is not accessible to screen readers at all. And so a lot of component testing libraries have found that the, you know, even when you're coupling the text by using Get-by-Role and Get-by-Text it's like, okay. Well, yes, the copy could change. Marketing could say, please change the name of this thing and that could require a test change. That doesn't usually cause me a lot of pain in component tests. One interesting thing to note if you use end-to-end testing tools like Cypress, you'll actually see that Cypress' docs do recommend using test IDs. And I had a conversation with a friend of mine named Mark who works at Cypress about this to get his thoughts when we did a version of this workshop live. And he's a very, he's got like a consulting type mindset. It depends. And it actually does depend. Like I said, there's not just one answer when it comes to testing. But he's, as we were talking, something that came to mind was that it seemed like when you're testing a component, you kind of have the code of the component in front of you. Like you sort of know all of what's involved and like there's child components as well.

Final Remarks and Q&A

Short description:

Component tests are more narrow in scope, allowing for precise targeting of elements. End-to-end tests may be more prone to breaking due to changes in text or layout. Performance can be slower in end-to-end tests due to the complexity of the app. There is a trade-off between speed and robustness when choosing between text-based or element-based testing. Component tests often prioritize testing the accessible text. The workshop on Designing Effective Tests with REAC Testing Library covered the importance of testing the contract, the inputs, and outputs of a component. Participants were encouraged to provide feedback through a survey. The workshop materials and resources are available for further learning. Questions were addressed in the chat, and participants were thanked for their time and engagement.

But components tests often are kind of more narrow in scope. And so when you say, I'm looking for the text field with the placeholder, new movie title, I know is the author of the component that there's only gonna be one of those. Now, if you're writing an end to end test and you say find title, find author, well, who knows? Like desktop computers have a lot of space on the screen. Maybe we put movie titles all over the place. And so maybe finding something by text could be more likely to break in the future for end to end test.

There's also the performance issue. When you have a very complex web app with a lot on the screen, really even a non-trivial web app, and then tests, well, end to end tests are slower necessarily, and the queries to look things up can be slower when you're running a whole app. When you're just running a component, it's faster to find things cause there's not so many DOM elements. And so really there's a trade off between speed and robustness to text change versus the realism of actually looking for text and making sure it's accessible. And what a lot of us have found is that in component tests, the trade off makes more sense to go with the text, the text that's shown, the text that it's accessible. If you find otherwise in your project, you are absolutely welcome to try something else. But I definitely try to learn from these recommendations from the community and give them a try. But try one thing now and try something else later and see how it works out for you.

So this was, this has been Designing Effective Tests with REAC Testing Library. And I hope it's been helpful. Over our time together and refer back to the slides and the recording later. But we've talked about what does it mean to test the contract? Why test the contract? Why is this a helpful testing approach? And what are the inputs and outputs of a component? And just to put back in front of you, testing contract here. Inputs are pops in user interaction events, outputs are rendered UI and calls to external functions. And I'm sure there are some other inputs and outputs as well. But as you get into this mindset, you will start to think in terms of inputs and outputs and detect them.

Tor asked if we can get a copy of the final version of the slides. The updated link version is almost, almost finalized. I will check and see what are the latest changes that I made. But I will update what is linked in there to have the final changes. But it is 99%,.9% there already. Oh and a copy of the final version of the code that is in the solution branch as Amal said. Yes, yeah the exercise repo has a publicly available solution branch where you can see those. Thanks for asking. So I have a survey, this is in addition to get Nations survey. And so this is also, you don't need to write this down. This is linked from the conference web page. I would ask if you have time today, maybe even before you head onto your next thing, it will take two minutes. It is three questions. And I would really, really love input from as many of you as possible. I wanna know what was helpful. I wanna know what I could do better cause I do this talk repeatedly and I would love to make better use of everyone's time and better equip people. So if you can, I would much appreciate two minutes of your time to fill out that survey. I don't know about get nations one is probably short as well, but if you could fill out this one, if you could fill out both, that would be really great. The conference workshop link will stay up indefinitely. You can get to the Discord community there to my book, if you'd like to kind of learn more from both this testing approach. TestDouble has a newsletter also linked from the workshop page. If you'd like to hear more about software engineering, testing and quality like this, we'd be happy to share thoughts with you. We do not have time for any many questions synchronously. I will stay on the call for a bit if anyone wants to ask questions in the chat. And so let me rush by this slide, but I just wanna say thank you to all of you. Thank you for your time. Thanks for joining in. I really hope it's been helpful. Be in touch if I can help with anything else. So thank you so much. And I will be here. Feel free to ask more questions in the chat and I'll be here for the next little while. I think first I will put up that solution branch link just so that's very easy to get to. Thanks so much, folks, chiming in there with thanks. I appreciate it. Yeah, branches solution branch, I don't hide it. I figure no one wants to see it. Solutions for the exercises. There it is. Laslo asked about it's.each for looping through a table of values for tests. So very interestingly, I have never used, I was aware of that concept. I had not used it until my current client projects. I was feeling like, again, there's a trade off. I was feeling like, well, let me write out the test more explicitly to make the trade-offs clear because I can give them descriptive names. But in this large existing code base that we're porting over to React, there's just some cases that there's just a bunch of conditions. And someone earlier in the workshop said, what do you do when you have a bunch of different conditions and it clutters up the names of tests? So in Jest, it.each or test.each allows you to set up a table of, Hey, here's a bunch of different values. And when I have all these combinations, here's the result. One thing that's really good for is what's called truth tables. Where when you have two or three or more sets of conditions, it can be hard in your brain to remember, have I tested all the combinations? And so using it.each, it makes it very clear to write it out. So you can see it's false, false, false results. True false, false results. True false, true false result. True, true, false results. And even if it's not Booleans, but it's like empty or not empty or things like that. So yeah, so when you find that you're really working with a whole combination of a bunch of different independently variables, it.each can be very helpful. Toni says, could you please give a quick example of input testing a prop in a user event? Yeah, let me prop that up. Holly says, how can we get in touch with you? So all my contact info is listed on codingatwrong.com. Email address is on there. I'm not on Twitter, but I am on Mastodon and LinkedIn as well. So feel free to get in touch there. All right, let me answer Tony's questions now. Example of input testing a prop in a user event. I have three hours of workshopping my head of what I've done. So let me try to think back. Input testing a prop in a user event refers to.

Testing Props and User Input

Short description:

Testing a prop doesn't necessarily mean testing if it was passed in correctly. It's about what happens when a certain prop is passed in. For example, when we pass in a movie prop, what happens? The same applies to testing user input. We simulate props and user events in our tests and then test the expected output. The solution to the wrap and act error is often to wait with FindBy, but there can be edge cases and complexities involved. It's important to understand that rich front-end applications can be complex to test.

All right, let me answer Tony's questions now. Example of input testing a prop in a user event. I have three hours of workshopping my head of what I've done. So let me try to think back. Input testing a prop in a user event refers to. Let me pull these slides up here. Yeah, I wanna attach those general concepts to the specifics that we saw. So like testing a prop. So testing a prop doesn't necessarily mean I am testing that I... Testing a prop doesn't necessarily mean I test that a prop was passed in. That doesn't necessarily matter. Like the rest of the app doesn't care that the app passed in a prop appropriately. The question is when I pass in a certain prop does the right thing happen as a result? So example of testing the effects of a prop is when I pass in this movie, what happens? When I pass in this movie as a prop, what happens? When I pass in this movie as a prop, what happens? So that's the example of testing a prop. Testing that input. Example of testing user input. That'll be like our new movie form where we were typing into the text field and clicking on the button. And so those are provided as inputs, but in both of those cases, it's like props and user events come into the component. We don't test that they happen. In our test we simulate that happening. And then we test what output do we expect as a result. Output will probably be something shown on the screen or it'll be a call to another function to something else going out. Kuba says, I'm really surprised that the solution to this wrap and act error is just to wait with FineBy. I am too. That's why I kind of wish that the error message, the warning that was shown by React was different. Kent C. Dodds blog post on this is really excellent. And so let me show you where that link is on the page. Fix the not wrapped in act warning. He walks through it really well. So if you go to the workshop link and click on that and read through it, like you will follow it. And it's not a hundred percent of the time. There are times where functions are passed to other code and then they're called by something else and they come back. So there are a few times in my client work that I've had to wrap inact. But generally it's waiting for something to happen on the screen. I've found. But it is, I did not say that the act thing is just simple, like just do fine and you'll be easy. Like there will be edge cases or there may be things where some state is changing that you're not aware of. And so digging into exactly what's causing, it can be hard. It's not React or React testing libraries fault. It's rich front end applications are complex. So, no.

Watch more workshops on topic

React Summit 2023React Summit 2023
170 min
React Performance Debugging Masterclass
Featured WorkshopFree
Ivan’s first attempts at performance debugging were chaotic. He would see a slow interaction, try a random optimization, see that it didn't help, and keep trying other optimizations until he found the right one (or gave up).
Back then, Ivan didn’t know how to use performance devtools well. He would do a recording in Chrome DevTools or React Profiler, poke around it, try clicking random things, and then close it in frustration a few minutes later. Now, Ivan knows exactly where and what to look for. And in this workshop, Ivan will teach you that too.
Here’s how this is going to work. We’ll take a slow app → debug it (using tools like Chrome DevTools, React Profiler, and why-did-you-render) → pinpoint the bottleneck → and then repeat, several times more. We won’t talk about the solutions (in 90% of the cases, it’s just the ol’ regular useMemo() or memo()). But we’ll talk about everything that comes before – and learn how to analyze any React performance problem, step by step.
(Note: This workshop is best suited for engineers who are already familiar with how useMemo() and memo() work – but want to get better at using the performance tools around React. Also, we’ll be covering interaction performance, not load speed, so you won’t hear a word about Lighthouse 🤐)
React Advanced Conference 2021React Advanced Conference 2021
132 min
Concurrent Rendering Adventures in React 18
Featured WorkshopFree
With the release of React 18 we finally get the long awaited concurrent rendering. But how is that going to affect your application? What are the benefits of concurrent rendering in React? What do you need to do to switch to concurrent rendering when you upgrade to React 18? And what if you don’t want or can’t use concurrent rendering yet?
There are some behavior changes you need to be aware of! In this workshop we will cover all of those subjects and more.
Join me with your laptop in this interactive workshop. You will see how easy it is to switch to concurrent rendering in your React application. You will learn all about concurrent rendering, SuspenseList, the startTransition API and more.
React Summit Remote Edition 2021React Summit Remote Edition 2021
177 min
React Hooks Tips Only the Pros Know
Featured Workshop
The addition of the hooks API to React was quite a major change. Before hooks most components had to be class based. Now, with hooks, these are often much simpler functional components. Hooks can be really simple to use. Almost deceptively simple. Because there are still plenty of ways you can mess up with hooks. And it often turns out there are many ways where you can improve your components a better understanding of how each React hook can be used.
You will learn all about the pros and cons of the various hooks. You will learn when to use useState() versus useReducer(). We will look at using useContext() efficiently. You will see when to use useLayoutEffect() and when useEffect() is better.


React Advanced Conference 2021React Advanced Conference 2021
174 min
React, TypeScript, and TDD
Featured WorkshopFree
ReactJS is wildly popular and thus wildly supported. TypeScript is increasingly popular, and thus increasingly supported.
The two together? Not as much. Given that they both change quickly, it's hard to find accurate learning materials.
React+TypeScript, with JetBrains IDEs? That three-part combination is the topic of this series. We'll show a little about a lot. Meaning, the key steps to getting productive, in the IDE, for React projects using TypeScript. Along the way we'll show test-driven development and emphasize tips-and-tricks in the IDE.


React Advanced Conference 2021React Advanced Conference 2021
145 min
Web3 Workshop - Building Your First Dapp
Featured WorkshopFree
In this workshop, you'll learn how to build your first full stack dapp on the Ethereum blockchain, reading and writing data to the network, and connecting a front end application to the contract you've deployed. By the end of the workshop, you'll understand how to set up a full stack development environment, run a local node, and interact with any smart contract using React, HardHat, and Ethers.js.


React Summit 2020React Summit 2020
96 min
Rethinking Server State with React Query
Featured Workshop
The distinction between server state and client state in our applications might be a new concept for some, but it is very important to understand when delivering a top-notch user experience. Server state comes with unique problems that often sneak into our applications surprise like:
- Sharing Data across apps
- Caching
&
Persistence
- Deduping Requests
- Background Updates
- Managing “Stale” Data
- Pagination
&
Incremental fetching
- Memory
&
Garbage Collection
- Optimistic Updates
Traditional “Global State” managers pretend these challenges don’t exist and this ultimately results in developers building their own on-the-fly attempts to mitigate them.
In this workshop, we will build an application that exposes these issues, allows us to understand them better, and finally turn them from challenges into features using a library designed for managing server-state called React Query.
By the end of the workshop, you will have a better understanding of server state, client state, syncing asynchronous data (mouthful, I know), and React Query.


Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

React Advanced Conference 2022React Advanced Conference 2022
25 min
A Guide to React Rendering Behavior
React is a library for "rendering" UI from components, but many users find themselves confused about how React rendering actually works. What do terms like "rendering", "reconciliation", "Fibers", and "committing" actually mean? When do renders happen? How does Context affect rendering, and how do libraries like Redux cause updates? In this talk, we'll clear up the confusion and provide a solid foundation for understanding when, why, and how React renders. We'll look at: - What "rendering" actually is - How React queues renders and the standard rendering behavior - How keys and component types are used in rendering - Techniques for optimizing render performance - How context usage affects rendering behavior| - How external libraries tie into React rendering
React Summit Remote Edition 2021React Summit Remote Edition 2021
33 min
Building Better Websites with Remix
Remix is a new web framework from the creators of React Router that helps you build better, faster websites through a solid understanding of web fundamentals. Remix takes care of the heavy lifting like server rendering, code splitting, prefetching, and navigation and leaves you with the fun part: building something awesome!
React Advanced Conference 2021React Advanced Conference 2021
39 min
Don't Solve Problems, Eliminate Them
Humans are natural problem solvers and we're good enough at it that we've survived over the centuries and become the dominant species of the planet. Because we're so good at it, we sometimes become problem seekers too–looking for problems we can solve. Those who most successfully accomplish their goals are the problem eliminators. Let's talk about the distinction between solving and eliminating problems with examples from inside and outside the coding world.


React Advanced Conference 2022React Advanced Conference 2022
30 min
Using useEffect Effectively
Can useEffect affect your codebase negatively? From fetching data to fighting with imperative APIs, side effects are one of the biggest sources of frustration in web app development. And let’s be honest, putting everything in useEffect hooks doesn’t help much. In this talk, we'll demystify the useEffect hook and get a better understanding of when (and when not) to use it, as well as discover how declarative effects can make effect management more maintainable in even the most complex React apps.
React Summit 2022React Summit 2022
20 min
Routing in React 18 and Beyond
Concurrent React and Server Components are changing the way we think about routing, rendering, and fetching in web applications. Next.js recently shared part of its vision to help developers adopt these new React features and take advantage of the benefits they unlock.
In this talk, we’ll explore the past, present and future of routing in front-end applications and discuss how new features in React and Next.js can help us architect more performant and feature-rich applications.
React Advanced Conference 2021React Advanced Conference 2021
47 min
Design Systems: Walking the Line Between Flexibility and Consistency
Design systems aim to bring consistency to a brand's design and make the UI development productive. Component libraries with well-thought API can make this a breeze. But, sometimes an API choice can accidentally overstep and slow the team down! There's a balance there... somewhere. Let's explore some of the problems and possible creative solutions.