Introduction to React Native Testing Library


Are you satisfied with your test suites? If you said no, you’re not alone—most developers aren’t. And testing in React Native is harder than on most platforms. How can you write JavaScript tests when the JS and native code are so intertwined? And what in the world are you supposed to do about that persistent act() warning? Faced with these challenges, some teams are never able to make any progress testing their React Native app, and others end up with tests that don’t seem to help and only take extra time to maintain.

But it doesn’t have to be this way. React Native Testing Library (RNTL) is a great library for component testing, and with the right mental model you can use it to implement tests that are low-cost and high-value. In this three-hour workshop you’ll learn the tools, techniques, and principles you need to implement tests that will help you ship your React Native app with confidence. You’ll walk away with a clear vision for the goal of your component tests and with techniques that will help you address any obstacle that gets in the way of that goal.

you will know:

- The different kinds React Native 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 text, image, and native code elements to verify and interact with them

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

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

- Options for handling native functions and components in your JavaScript tests


- Familiarity with building applications with React Native

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

- You do not need any experience with React Native Testing Library

- Machine setup: Node 16.x or 18.x, Yarn, be able to successfully create and run a new Expo app following the instructions on


This is intro to react native testing library and I'm Josh Justice. I'm super excited. This is one of my favorite topics to talk about is react native testing. And so we're going to dig in together on this today. I shared the the URL for the repo in the chat just now. It's in Zoom chat. It's in Discord chat. But if you go to this URL rnte dot St. Our end test slash London 22, you'll get the link to the get repo and this link will stay active in the recording in the future. So you'll be able to get this in the future the git repo of exercises you're going to be working through or I invite you to work through as well as other resources the slides and the recording will be up afterwards. There's also a link to the get Nation Discord chat or we can discuss these things together. So yes for anybody listening, please go ahead and download the git repo that's listed from there. If you would like to code along in the exercise sections that we do together. So let me introduce myself. I saw a few names in the chat there that I recognized from yesterday's workshop on Expo. So hello again. Glad you're back that I'm Josh Justice I go by coding it wrong on the internet. My personal homepage is coding it And here's some of the things that I've shared before on react native. Um, I spoke at react native EU this year about test driven development. I gave a workshop on extended workshop on react native testing kind of in a full day version of this workshop at chain reacts 2019 and I'm giving an updated version of that Workshop again in 2023. So you are looking to go to chain react you can join us there. I also live stream on Twitch and react native testing has been my topic of choice recently. And so from my web page you could get there to stay in touch if you want to talk about things like this on a weekly basis or catch the recordings afterwards. So you can see a theme of being excited about talking about react native. I also maintain a website react native where there's just a lot of information similar to what's in this Workshop to get you equipped to test components with react native testing Library end-to-end tests. We especially focus on the detox library for end-to-end testing on there and I try to keep it up to date with all the latest apis and changes and improvements in the react native testing world because things are really changing and improving. I work at a consultancy called testdouble. I want to thank them for supporting me and giving me a chance to be here giving you this Workshop through the conference to test double as a company that focuses on improving the world's software. And so if learning about testing is gets you excited, if you feel like you get something valuable out of this, we love to help teams with testing Agile development practices maintainable code upgrading focusing on end user needs. And so we would love to help you out. So check out test double on social media or If you think that we could help you as a consultancy or with custom corporate training or something like that. So today what we'll cover in three hours is react native testing library and just native which is a helper library for making assertions against react native code. But we're not going to cover is just Basics. I mean, you'll see some of just testing Basics as we go but it's not mainly an introduction to jest. And also we're not going to cover end-to-end testing today with either detox or appium or anything like that and we'll kind of explain the difference as we go along. But really it's specifically on react native testing Library. Afterwards this URL this is the same URL that's in the footer down here. So you can see it on any slides on the slides are up. You can go there from I'll have links for more resources. You can follow and also links to I have a Discord Community where with a bunch of folks that join on the live stream and talk about react testing react native testing. I love the field questions for you there afterwards. If you have any more questions about testing anytime please reach out. Okay, so we're gonna start that was the intro session one. This is session two, which is component tests focusing on render. So let's dive straight in and maybe about halfway through the the three hours. We'll try to take a break. Maybe that'll coincide with some exercise time as well. So people get dual time for that. All right. Let me make sure I see the chat on here. I'm going to keep as we go. I'm gonna keep an eye on the zoom chat and on the Discord chat as much as I can actually, you know, I have my my notes when we're in the code exercise. Those are gonna be up on my phone. Um, so any is anyone is welcome to come off mute to ask a question. Um anytime but whenever I'm back on the slides, I'm gonna pop back over to Discord. So I'll mainly watch Discord, but I'll try to keep the zoom chat in front of me as well. Basically, what I'm saying is please interject and ask questions because I'm happy to just help with whatever would be helpful to you. All right. So let's talk about rendering and really the basics of getting started with component tests. So what is a component test when you think about react or react native your application is organized into components and in the component test you are testing a component directly. You're not testing a whole application altogether in the component itself. You actually write jsx to render out a component in the context of the test independently of the rest of the application. So it lets you isolate the compost by default all the children like the child components of the component are rendered out and included as well. But the rest of the application you're separated out and so you can focus on does this component do its job with regard to the rest of the application. On the library we're gonna be using is called react native testing Library the npm packages. It's under the @testing library organization. And if you've used react testing library on the web, it has the very similar philosophy the codebase is totally independent because it emerged separately and because there's so many differences about the native environment, but they have exactly the same philosophy and are trying to converge on the apis. So here's the URL for it. But also I mean these slides will be up later. But basically Google react native testing Library, you will get their docs and from when we do get to the exercises together. I have a link to my testing website with more information and it in turn has links to the react native testing Library docs. So from there you're going to be able to get to whatever you need in the exercises today or in the future. So what do you test when you're testing a component some of these questions come to mind and especially kind of a few years ago before the testing tooling had evolved you started to say well I my component is a function and it's got other functions in it. Can I call them? Can I test a hook? Can I test a memoized property? Can I check State values that are set to see if they have the appropriate value that I would expect and so these are the questions that people tend to ask a common phrases. How do I test this line of code? And in some senses like yes, you want the test to run through there you want the test to make sure this line of code works, but the focus when it comes to writing a test, I have found that focused on how do I test this line of code can tend to not be the most productive it can leave you confused. How do I how do I test the line of code instead? I'd like to argue for a different way of thinking about tests and none other than Dan abrav of that core team has a great quote that I think is very helpful in this regards in a tweet in 2019 in the before. Times he said we don't encourage reading implementation details like State variables themselves. Instead test observable Behavior IE what your component renders or does test from outside the component? And I think that's exactly right. That's exactly the kind of test philosophy that leads to robust maintainable helpful useful tests. There's another way you can think about this concept and it's called testing the contract. This term maybe comes from elsewhere, but I know of it from a book called testing vuejs applications a different front end framework actually, but Ed yerber wrote the book and he said a component contract is the agreement between a component and the rest of the applications. It's not something concreting code. It's just the concept it's what is the concept of the agreement between a component and the rest of the application? He goes on other components can assume the component will fulfill its contractual agreement and produce the agreed output if it's provided the correct input, so that's what the rest of your application thinks about when it thinks about a single component or what it's built in light up. It's assuming and relying on a given component doing what it guarantees doing what it was built to do and that's what we can focus our tests on if the component gets the right inputs or for a given set of inputs. What are the outputs that the component produces? So I wanted to go to a question now, um before I tell you what I think the inputs and outputs of a component are I have four main ones that I want to talk through together, but I'm sure I haven't thought of every and so I would love to hear from your perspective if you're willing to share in the chat what are some of the kinds of inputs and outputs that components have and there's no wrong answers. I just want to get your understanding. I'm pulling up the two different chants now so I can see your thoughts. But let's just take a minute or two to think about it. What are the inputs and outputs of components? Force you but I encourage you to be bold share your thoughts on what the inputs and outputs of the component are and in just a minute or so. We'll continue All right. Salvo says input props and context data. Great that totally makes sense. I wonder if you might have output queda. So I'll give it just a second in case you want to share some output. Elsa says props input output snapshot It makes sense. It's almost as output rendered component on the screen makes sense. Cool. Yeah, I mean the way you are thinking about this is the spot on. So let's go and look at the way that I kind of structured it. You'll see a lot of familiarity. I kind of break it down to as far as the things that I teach in this Workshop inputs are props. And I I in this Workshop currently, I don't call out context separately in a okay. This is a Content values from contacts are not props. They're coming from a hook. So yeah, I think it could be helpful for me to call that separately in the future. But yeah data coming from a context apps absolutely applies as well. I actually you might not intuitively have thought of this but I list user interaction events as inputs as well. The user is inputting a click here a tap here or typing texts there and that that results in yeah changes the quantum when the user does this and puts this in something comes out. I'll put include the rendered UI and also calls to function props. So if a profits passed sorry, if a function is passed in as a prop or from a contact or from a hook or something like that if the component calls that function that's a call a method call function call going out into the rest of the application and as we go through testing these you'll see how we can assert that when certain input comes out a function call. It comes up the other side potentially with arguments that go along with it. Yeah, it occurs to me to actually web service return values should go in here as well. So we'll we'll look at that as we go. But yeah these so these couple of inputs and outputs are going to form the structure of what we focus on for most of the workshop together. So let's go ahead and start diving in and seeing how we can use react native testing library to test inputs and outputs like this. First we're going to start with rendered UI kind of surprisingly. It's the outputs down at the bottom of my list, but that's the easiest thing to get because we need a component before we can do anything with this. So let's go to the code. Let me get in here. We got this sandbox working test. We're gonna start the server. Excuse me for just a second while I get the right windows up here. Yeah, we're going to lecture one. So this part is not what's in your code. This is a unique to me, but you're gonna be doing an exercise with similar types of things as we're going to be doing together here in the workshop. So in the lecture examples, basically, All right. So let's get we get some very trivial components here. But let me just get them up in a simulators so you can visualize them. It's taking a little long to open. So maybe we'll come back and visualize it I bet when you see the component you'll be able to follow along. So this is a Hello World component. This is an extremely simple component here. We do have an image and an SVG we're going to get to in just a moment, but for the moment focus on the Hello World message here. um A genie asked about gitlink. Yeah, let me give that to you. There you go. There's there's the link I've been yeah, you can pull down and we're not to the exercise yet. This is just what I'm demoing, but in a few minutes, we're gonna start exercise one and you'll be able to pull that down. You're welcome. All right. So in lecture one we have I love this picture. I found it a couple weeks ago and then forgot about it. It's so great and Walter Brunner on Splash good job with this picture of a waving squirrel. I love it. So yeah, this is a component. That's just rendering out some simple stuff some simple text a PNG jpeg image and an SVG graphic. And so this is output the component is outputting these things and we want to test them, you know, it's it's, you know, unconditionally rendering it. So like I don't know if it's the most valuable to test but just as an example to show how can you confirm that a component is showing a given thing on a screen? So we're going to start with the text. Oh, yeah, and I got to get my notes up here. one second Yes, so in the component, you can see it's pretty straightforward if you use react native before and if you haven't used react native before you're gonna get a taste as we go but you know and react native. We use view components and text components. So we have some text showing hello world very straightforward. So how can we confirm that that text is shown in here? Well the API to render a component and react native testing library is render. Looks like my language server protocol is not importing it so I need to do it myself. We import render from testing Library react native and then we render out the hello component. This was jsx just like we do in the rest of the application. Let me save this and run it just to see the test output. um lecture sandbox. Hello this oh, yeah this no this needs to be in a test. Sorry. I mean not thinking so in it, you need a an it or you can always use the keyword test but test or it you say here. You say renders a Hello message just a nice description in your spoken a natural language of choice of what you're testing. We're testing that it renders a Hello message. And so now in the test runs it passes. Now just by rendering the component here all that we're confirming is that it doesn't blow it exists and it doesn't blow up or have some kind of error as a part of the render. But we want to test more than we want to test. The text is actually shown and so we can do that with Expect so expect is a just API for you to check that something is the case. So you wrap that in expect you say screen Dot. That's like an Auto Import either for some reason but we bring the screen API from testing Library AC native and we can say screen.get by text. And then we can actually type in the text that shows let me check the capital of capitalization. It's a capital W for world. So we can say expect screen.get by text and what this will do is this will give you an element on the screen that contains that text. You can say to be visible. So this will check that it exists and also does some checking around visibility that has it hasn't been set to display none or zero opacity or shrunk down or something like that. I mean so it does it's best to confirm. Hey, yeah a user should be able to see that text. So let's say and see. so the test passes so one testing tip that I would give is when you have some code written and you add a test to make sure it works and it passes right away. Don't trust it be worried. Make sure you want to make sure that the test will actually fail if something is broken. And so when you get it to Green go and break your functionality to make sure it fails afterwards. So what I'm going to do is temporarily go in and just delete this text and save my component. Just automatically reruns and now we can see the error unable to find an element with text. Hello world. So now we've confirmed that this is not a false positive. This test will really fail if the message is not there and when we put it back and save we get green. So this test is really confirming the functionality. It's really confirming that that content is present. So if you notice about this, I forget if this is case sensitive, so let's try to find out I'm gonna make lowercase w. Yes, okay. So it looks like it is actually case sensitive. Okay. So that's good to know. Another thing I was going to say is it matches full strings by default so a full text element. So if you just include part of the string It's going to say I know unable to find the element. You can get around that by using a regular expression. So if you want to say I want to match some text that contains hello somewhere in it. You can use a JavaScript regular expression by using slashes. We're not going to get into regular Expressions too much, but you can Google those or let me know and I can send you a link with reference, but those let you match more flexibly. So we see that when we put in a regular expression it says yes, I found text that matches that regular expression in this case the substring hello. Now what about matching things that aren't text confirming that the image shows the photo or confirming this SVG shows? So it turns out that if you write your tests in a way that react native testing Library recommends a testable component is also going to be an accessible component which is to say is component that's usable by people with different abilities in particular on computers and phones visual impairment is something that there's a lot of facilities for you may have heard of the concept of screen readers or maybe some of you have actually used them for develop. I hope so we're gearing up to get into accessibility focus on the project that I'm on right now and my consultant and consulting job and so we're going to be using a screen readers to test that when somebody's visually impaired or blind and they're using a screen reader that will actually verbally you read out the contents of the screen we test to make sure that the app is actually usable and interactable. If you haven't learned about accessibility like that, I would highly encourage you to dig in I should add a link to that to the web page because I love pointing people to this because I only learn about accessibility later in my career and I wish I'd made a focus on learning sooner because it lets you build apps that are usable by more people So but the point of all that is if you set up this image and this SVG so that it reads a description of it out loud to a screen reader. That's also testable and so, you know, testing automated testing and accessibility can work hand in. So to get the image of the squirrel to be testable, you get the zoom thing out of the way. What we need to do is add an accessibility label to The accessibility label we can just say squirrel waving. So now there's some text attached to that image that can be used for accessibility and then we can test for it here. Let's say it displays the squirrel. Just use the words that are the hardest to spell in a workshop. So when I render hello, I expect. I have genius says that that they are at the point that I would mention where I do nothing about accessibility. So yes, I will share that link about accessibility afterwards. There's a conference talk about react native accessibility in particular. That was really good. And actually there was one at react Advance this year. And so I will get the name of that so that you know, y'all attended to conference so you'll be able to watch that video and there's also one from a few years ago to conference. So I'll share those. So here's your early taste of it. So when we have an accessibility label on the element where we can say is expect screen get by label text. That is to say accessibility label. Oh, let me get by label text. Let me see if my language server will tell us about it. It looks like. Not so much. I guess my winter is getting the way but so let's just fill this in so we say get an element by the accessibility labeled text squirrel waving and then expect it to be visible. We're going to save it passes again. We've I talked a moment ago about how we don't trust it. That's not good enough for us. We need more confidence. So let's actually break this again. We'll remove that accessibility label save and we see that the test fails so that confirms that we really it's passing and it is really confirming that an element with that accessibility label is there It doesn't confirm which jpeg is being shown. I'm not actually sure. I haven't checked to see if you can confirm which images being shown there so I could be something to look into but really here if the point is like, oh sometimes I show this girl image and sometimes I don't you can check that the image with this accessibility label is present. For an SVG, it works the same way if you are specifically if you're using the package called react native SVG Transformer, this is very common. I think every time I've seen svgs included a build time and a react native app. This is the way it's done. So when you're using this package you basically can import directly from an SVG file directly into your components and you get a component that you can use as a reactive. So here's the waving here and we want to do is exactly the same you want to give it an accessibility label and call it waving hand. Actually this time you know Let's do let's do this in test-driven development. We'll do this in the opposite order. So in test driven development that is not the focus of this Workshop, but in that approach is you to follow in a process called red green refactor. We're first red you write a test for the new functionality you want and you watch it fail. And then once that test is failing then you do green you implement the functionality and make that test pass and one of the benefits of test driven development is you've actually confirmed that it is really testing something because you have seen the red you don't need to remember to go back to the right. You see it red from the start. It's actually fewer steps. If you're testing to make sure your tests really fail in the appropriate way. So let's do this test driven by writing the test first we're gonna say it displays a waving and icon we're gonna render hello, and we're gonna expect screen get by label text. waving hand to be visible So now we're going to save and I expect this test to fail because we haven't added that accessibility. I say And it fails unable to find an element that's accessibility wave label waving hand. So that's the red step now. We can go to the green step by implementing this And it's very easy to implement. We just add an accessibility label and with language server you get auto complete there. So that's nice. Waving hand we save and the test passes. So now we're confirming the present presence of an SVG as well. All right. Let's go back to the slides. And talk about what we just saw on the code. So when you're trying to find an element with react native testing Library, there are series of getter functions. They're available on the screen API and you call get by text or get by label text or get by placeholder. We're going to show you an example of it then. Yet by text will let you find a text element which in react native always I think always always are almost always is in a text element a text component even when you have some text as being displayed by a third party Library under the hood ultimately there's a text element there. So if you see text on the screen get by text should be able to get it for you. If you have a text input, this is a very common case, of course because you're typing into it placeholder text is a great way to pull it up. If you have a placeholder in that text input you can get by placeholder text and that is the case whether that's it's findable by that whether the placeholder is visible or if you've typed into it and so the placeholder is Now hidden you can still get the input by that placeholder text. As we saw if you have an image using the react native image component with some kind of jpeg or ping or something like that. You can add an accessibility label prop and then you can call screen.get by label text. And with an SVG is the same way as we saw accessibility label and get it by label text. And then your your components are now more accessible to screen readers as well as added. So which query should I use there are actually other options as well and you might even be choosing between the ones that we listed here. So there's a page and again the slides will be up. So you'll be able to get back to these a page on call Stacks website for react native testing library that says how should I how should I query what should I use and they have a quote this philosophy comes straight out of react testing library and the rest of the testing Library ecosystem your test sugar resemble how users interact with your code components or page as much as possible and the implications of that are here when they list the queries in order they start at the top and they say that highest priority are quite query successful to everyone that is queries that reflect the experience of visual users as well as those that use assistive technology. So basically these queries are confirming if you use them, it's something that both people will be able to see with their eyes or they'll be able to hear through a screen reader or another technology like that. So get by text does that because text is on the screen? There's get by display value, which is shows you the text entered into a text input placeholder text and get by label text. Every which allows you to query every element that is exposed in the accessibility tree. So a lot of good options there, there's other options for the down on the list. One important note and some of the folks who helped me out on my live stream and in my Discord Community to have pointed me to this. There's a screen.get by role as well. And this is something that allows you to specify the accessibility role the accessibility role gives more information to screen readers as you go through that lets them know. Hey, this this is a button. This is a text input. This is a header or a navigation menu things like that. And so that can be a really clear way. You can see here as we read this it just kind of makes sense get the button that is named save changes that can be helpful. If you have maybe save changes as the title of a modal as well. So this really makes it clear get me the button that has the name say changes. So there is an issue open on react native testing libraries repo where they're discussing making get by roles of recommended way to query and that's the way it is on react testing library on the web. But there's at least one feature needed first. They fixed a contributor has fixed one of the issues needed but there's one remaining is implicit role. This is basically the idea that when you have a pressible or some other kind of touchable input touchable. Opacity all those weird kind of names for button type things and react natives. They if you just use a pressable that should be considered a button by default but it's not currently you have to explicitly say in your code. I forget the prop accessibility role equals button. And so that actually is not the most realistic like it does work as a button it's fine for accessibility but react native testing library is not yet recognizing is it is such so there's some hoops. You have to go through to get get by roll work, but they're hoping to have someone to contribute this in these implicit role soon. And at that point get by role will be the top recommendation. And as a result of using it like you will need to learn a bit about accessibility on the platform and I did that on a stream recently. I was learning some about it. So I'm not recommending yet this as the top because it's not yet officially recommended in the docs, but keep an eye on the reaction Library docs or check me out on social media. I'll be posting about these things in the future and this might be coming soon. But that's why this is not the main thing I teach in the course as of all right, so we have the ways to get elements on the screen screen get by whatever. So how do you confirm the presence of it? Well, as of the latest minor release of just native, which is 5.1 just native provides these matchers which is to say the things that you add on the end of expect. And they've recently added to be visible. And so this is now the recommended way. At least my recommended way. I think he recommended way to confirm the presence of elements. And the reason why is when you call get by and then to be visible, it's going to confirm that is really present there. If the element is not there at all. You're going to get a nice clear test failure message and the visibility checks as well to make sure it's not displaying none or height zero or opacity offering like that. There are a few alternative ways to confirm the presence of elements up until just I was just a couple weeks ago and to be visible was at it the way to do it was screen.get by expected to be truth which is to say, you know, is it a real element not no. Another way to do it was expect screen query by to be truth. So query Bible act. So this is kind of complicated. I should have put it made it clear slide. Sorry about this get by if it fails if you can't find the only looking for it will error out. Query buy instead will return a null and so then if query buy does not find the element you'll get a null just will say expect null to be truthy and just will tell you. Oh, I expected truthy, but actually it's no instead and that's all the information you get. You have to look at the code to see what it was looking for. By contrast get by gives you a much clearer error message that says here's the element that I was looking for that I did find. Now actually because get by errors out on its own you can just say screen.get by and admit the expect altogether. But in the testing Library family it's recommended that you do wrap it in and expect because that makes it clear that you're intending to check the element. So it was kind of weird before like do I wrap screen dot get by and expect I don't really need to but it's kind of recommended and maybe more helpful, but it is a lot clearer now because now we have to be visible. And so now we have a very specific reason that we want to wrap it in an expect to get those extra visibility checks. So I was really my friend recommend this for confirming something is present expect screen dot get by to be visible. Confirming absence is some a different and there's really only one main way to do that. You do want to use expect screen.query by in this case because query by returns a null and so in that case it won't blow up if you you know, you can't check that the get by returns. No because it'll just blow up but if you say I want to make sure that the query by here is null that is to say it's not found and then if it is if it is something if there is an element present an element will be returned and the test will fail because it will say I expected it to be null but it was not I got an element. So that's the way to confirm that something is not present. So that's rendered UI that's kind of the basics of confirming what you see rendered out in the component. We are briefly going to go to props just because props is pretty simple and just a slight tweak here and what we check. You know, how can you check how can you account for props in your tests? So let's do that quick and then we're going to go to our first exercise. so to the code and in the meantime of going to the code, I'm just going to check and see has chatted anything else us. Okay still has a question. My project is using an older version of the testing library and query stuff on the return from render. Myth. I'm not familiar with the screen. So it's wanting if there's a difference between the two that's a great question Stella and I should have pointed out the screen was newer. Um, yeah, so it was just the last couple of versions of react native testing library that the screen API was added and there's not a difference the difference is just instead of well. Let me let me get it up on in the docs in front of you so that the others on the call and on the workshop can see this and see the two options but the short version is that either way works just fine. So when you have the render function, there's a render result that is returned. and to yeah Yeah, they might not show examples anymore. But basically yes. So latest render result is kept in screen variable that can be imported from testing libraries react native. So previously, let me just show in the code here, um previously until a few minor versions of reacting to testing library before what you would do is instead of screen. You'd say const get by text equals. Render hello, and then you say expect get by text to be visible. Let's just make sure this passes. It does. Yeah, so basically the render result it would return these values that would have all the Getters and the query functions on it and you would just de-structure it typically to be able to get the different methods, you know, I'm getting a linter warning here And it says avoid the structuring render results use screen.get by text instead. So basically screen was added as a convenience following the approach where it was available on the website. One of the nice things about it is instead of having to like change the import statements query by label text like this in my applications. I was doing this all the time. Oh, I got a query or get by something else. So I need to add another destructuring here and it just kind of kind of got tedious to maintain this line. And also passing it around if you have separate parts of your test can be can be hard but when you just have the screen API, you just say screen dot get by text and you're good to go. If you're is better for language server as well whether you're using JavaScript or typescript autocomplete Works a little bit better. Let's see if it's working in. I think there's something wrong with my language server right now. But yeah, you can basically just type in screen it'll import it from the package and then you can type in get by text and autocompletes and gives you all the options there. So that was a long way to say. No, there's no difference screen is just a shorthand API. You don't need to migrate your code over, but it's recommended going forward. Oh, yeah, you still has used constitutils equals render then use utils like screen, right? So that would actually have the benefit of the autocomplete as well. Let me put that on. Put that on the screen here. We save that to make sure that works. Yeah, so that that works as well that probably has a lot of the autocomplete benefits. No the cases where you're having passing it. If you have like helper functions that set up your rendering or before each or something. Well before each it's not recommended in there, but you know this utils you might need to pass it around whereas screen is a standard API. It always has the same name. So just you know slight consistency across the ecosystem there. But yes cool. Great questions, though. Thank you. All right, where we coming back? I think we were coming back from the code. No, no, we had not gone to the code yet. Let's go to the code. We got to talk about props. Okay, so Props Nope, this is the wrong thing one second. We'll have it here. All right, so let's change our hello component. To take a name. We want to greet more personally. We want to say greet someone by name but by default we greet world if there's no name provide, so we're gonna make name. Interpolated here. So I'm going to save this change all of my existing tests actually pass because when I render the component without a name provided World Is Still the default, but let now let's test the case where this prop is actually provided we can say it's Greets the name provides good name. render Hello. Oh great, Josh. Get an expecting here and we'll say hello Josh. a save and it passes once again, let's not believe it. Let's not trust it. So let's take this out and make sure we can see the test fail. It does. And now we save again in his passing. So now we're confirming that in the case where certain props are provided certain output happens this input results in this output. You could also check if you wanted to check the hello world is not visible. There's you know a lot more you depending on how much confidence how much Precision you want in a given test. um So um, and I wanted to say something about the concept thinking about the idea of testing the contract you could say, how do we test this prop? I want to test this prop. How can I test that? So that mental model like what is that mean like a prop itself doesn't do anything a prop is just passed into the component. So if you want to test that it will accept the prop, you know, you could just type in the prop and see that nothing blows up. Am I supposed to write a component that will blow up or maybe if you're using typescript you get a typescript there and you know, oh, yeah not supposed to have that problem. But really like, why does the component have the prop? What is the contract the component asserts the rest of the application? What does it guarantee to do as an output if a given prop is passed as an input and then you test the contract So really the presence of something like a name is really kind of the scenario or situation. And so we write a test for that. We arrange that scenario and we see what happens as an output from it. So that's that's the something that we're testing coming up. And that's kind of I mean, you know a lot of ways to use props, but that's sort of the starting points as far as how to test props. And so we're good props as an input and rendered UI is an output. We have covered in a basic level. So with that I'd like to go to exercise one and send you over there. I'm going to show you the readme real quick. But this is an intro to RN TL exercises. That's that's the the git repo and it's under the exercises folder one exercise one which is written funny because I just wanted to store in numeric order. I guess I could just hit exercise whatever. I'm weird. Um, so one exercise one markdown file is where the exercise is described. And as this file says if you want help you can go to this page on rack native It covers the same material that we've talked through in this first segment. So let me show you that and you familiar with the exercise. so we want to I'm going to start it up and Boot It Up in expo here. You don't need to run the app in a simulator or emulator, but you absolutely can if you want to visualize it so our exercises we're going to be gradually adding more and more tests a couple different tests to an app a very simple application. And this is the application it is a movie list and so vertigo and The Sound of Music show up on there. Oh there there is a read the instruction though. So let me let me do this in order. So in the exercises repo, you'll see the readme we'll go through here. It's got the basic requirements for doing react native development. It says, please install the dependencies. And so then here's another step get an API if you haven't done this before, so just so that each of you has your own set of movies and nobody's sharing inappropriate movies for a list that we can all see we all have we're gonna have separate API keys. This is totally free and there's no personal information collected from you. All you do is go to API And click on create an API key. This is used for a book of mine that I self-published on testing. But it also worked for this just click create an API key and it will show I will show it here and then I will hide this quickly so you don't all use the same API key. If you just click on that you'll get a unique key and then you'll be able to paste it in to source api.js so you can just paste it in there. Again, don't use my key. Please use your own. So this will allow you to have your own list of movies. So you'll get vertigo and The Sound of Music showing up by default. And then you can add in another movie as well. So you can say Rango a classic. And we get auto corrected. Apparently, it's the name of the movie right Rango. Click on Save there's a bit of a delay intentionally so that you can make sure your test will handle delays, but Rango will appear. And it will actually show this little indicator indicating. This is a new movie you've added today into your list. So that is the extraordinarily basic functionality of this app. And that's where we're going to be adding tests to Yeah, so, um, I will be available in the chat once the exercise starts in just a minute. So if anybody's having trouble getting this running, please let me know. I'd be happy to help out that but now let's go to the exercise. Exercise one says we're gonna add tests for the movie row component. This component is already written in functioning and there's an empty test file for it. And so your your mission if you choose to accept it is to add all the tests to movie row spec that you need to fully specify the components behavior and feel free to modify the component as necessary to help you write better tests for it. The movie row again. I really have kept this just so extremely simple to not clutter It Up movie row takes in a movie and it renders out of view. There's some styling going on to get my beautiful look and feel over here, but the view shows up. There's text that's shown and then if movie is added today, that's a problem just a property that comes in from the server. Then this new SVG is rendered out and you get the orange SVG on the right hand side. Um, yeah, so that's your mission is to write a test. The test is just empty. It says if that to do maybe I should have you do need to delete that to make sure that it actually runs so when you run these tests mmm You run the test. It's gonna say to do exercise one. So if you delete the to do you add an arrow function there? Then it runs this test pass is even though nothing has happened in there. So if you want to actually test something but yeah, so and you can rename it as well. You can have multiple tests. So yeah, that is the exercise and there's some notes here about designing your test. Just some suggestions to remind you of things we talked about and then here's the link feel free to ask questions in the workshops Discord chat Zoom chat is fine as well. But Discord chat is going to be more permanent for viewers later. And then here's the link to the page. I'm react native testing IO component testing you can pull up that page and then there's similar material to went through just now. So yes, let's get started on that. Let's um Let's let's shoot pretend minutes. Um, maybe you'll end up getting a break there. Maybe most folks will be done by that time. But in case anybody has a challenge of getting set up this will give everybody a time but work on testing the movie row component. You can try different if you finish you can try different options. Try different get query methods. You can try the recognitive testing Library docs to try different methods. But yes, so go ahead with exercise one is 350 right now. So at four clock in 10 minutes, we'll reconvene and take a look at what you got. And in the meantime, I'm going to be keeping an eye on the chat to see if I can help so yeah, enjoy the exercise. Sorry, let's reconvene. I think what I'd like to do here is I'll show you how I wrote the test for this component and I would love as I do that for you to be thinking about how yours may have differed something that I want to emphasize is that I really try to just be open-handed to different approaches. There are different ways to approach testing with different trade-offs. And so my way of testing this is not necessarily the right way you may have ways that make more sense to you personally or to your team or to your context. And so that's totally valid as well. So I just want to encourage anyone if you'd be willing to share in the chat afterwards how you tested things differently. Maybe this is pretty simple case. So maybe we all test a very similarly, but if you chose something different or if you tried something different as an experiment, I'd love to hear about it. And you know, I will acknowledge it as totally valid alternate option. Let me talk about pros and cons trade-offs costs and benefits. So here's the solution that I did and I'm going to run the test. So for the movie Row first, I had a test that said display is the name. So I set up a movie with a title Spider-Man no way home and I am noticed here that I set up an object. That only has that one property. I don't know and actually you maybe don't know from just looking at that class what the other properties of this object are but for the sake of this test all the movie wrote cares about is title and added today and actually it won't error out if the added today prop is absent and so I just passed in the minimal to for this test scenario. I rendered at the movie row component with that movie. And then I checked to see I checked for the text for the movie title. And I decided to look that up using the variable instead of duplicating the string down there, but I confirmed that the text of the movie title was visible on the screen. After that, I had two different tests for the new icon. If you remember in here, there's this added today icon that sometimes show and sometimes doesn't depending on the case of added today. So that's two different scenarios. And so I had added today true and added today false and passed those in and I separated out these three different tests. We'll talk more about that in just a second. So when I'm added today was true. I said screen get by label text added today. And this is the important note. I added the accessibility label to this SVG so that it could be queried in that way. Then in here I say get by label text added today expected to be visible. And then down here where it does not render. I did query by label text and I expected it to be no I expected it to be abs. ENT something I'll say about the separation here. You could combine two of these, you know, these two like, you know in the situation where it was added today, make sure that the name is there and the added today icon is also there and then in the false case that kind of well, you can maybe do two or two renders in one test, but it's probably a good idea to separate those out in the tests. But in this one you get a cert on the title again as well if you like. Let me assert on everything about the scenario when added today is false and that can be in approach. Um, but I kind of like to really keep my individual tests small and focused around one behavior of the component and so like the fact that it always displays the name and this fact that sometimes displays a new icon and the fact that sometimes does not display a new icons are three different behaviors. I would say or yeah behaviors slash scenarios. So I find a lot of benefits splitting out my tests in those ways. But yeah, if anybody would be willing to share how did you write your test in any kind of a different way was something you chose to do differently or just happened to do differently because it's just what came to mind for you. I would love to throw it to you. If you have any input on differences you might have had in your Solutions. All right. Let's continue on in the slides. So a few more notes about testing rendering and props. Number one the test that we've been writing here are have been focused on testing content not appearance. So we have an asserted like, you know, which SVG shows or which color it has or whether it appears to the right of the other thing. You can try to assert on that by starting on like style props, but that's hard to do and I've found in my experience that that tends to not all provide a lot of value. It doesn't actually confirm the things look the way you expect it just confirms and you put the style prop on that you expected to it's kind of like double checking at that point which doesn't add a lot of height instead to confirm the components. Look the way you expect in a very effective way. I recommend storybook. So storybook is a really popular tool for presenting kind components in different states different UI States and they had a presentation. I believe that reactive Advanced talking about ways to do that or if someone using storybook I forget if they work for a storybook or not. So storybook is a great tool for testing up here. Um using react native tests in library. I really recommend that for testing content and testing Behavior or functionality. Another option is Snapshot tests. Those are raised earlier in the chat. So in a snapshot chat test this this snippet may be out of date. But basically you do use react test renderer. You pass it some jsx. You convert it to Json and then you say expect tree to match snapshot. This is basically confirming that the Json output by the component has not changed since before so that that is output of the component and that checks all the details of the render jsx. So you can make changes inside the component to reorganize where logic is and things like that. But as long as the rendered jsx that comes out is the same this test will still pass and if it changes you can review it and see if that was intentional or not. I tend to agree when it comes to Snapchat tests with Ken C Dodds has written about them and years past and said that he feels like it tent they tend to be very large and kind of brittle and it's very tempting to not review the changes and it tends to couple you to every single aspect of the output of the component which is not what you tend to care about can't see dogs with recommend like oh, you know don't assert on all of the rendered Json like focusing on a specific part of it and just to start on individual Parts you care about and if you focus in all the way you get to the point where you're not focusing on jsx at all. You're just checking some text or checking in elements presence and at that point snapshots are not needed one important note if you haven't used snapshots Snapchat here does not mean it image of a visuals. It means a save state of the jsx data structure. So this actually is not confirming the look and feel either. There's no image to review So I have not found a ton of value in snapshot tests because of that I have occasionally there is a code generation project that I did where I wanted to check the read me those outputted by it. And so I use snapshots to record the state of the readme because I was simpler than writing out the whole read I could confirm that it looked the way I expected it to but generally I don't reach for it if it works for you great, but I'm hoping in this Workshop. We'll equip you with some behavioral testing tools you can use and maybe you will prefer those for your tests as I do for mine. Let me get the zoom shot back up on here. Yes, okay. So now we're moving on to our next topic actions and mocks. So intestine to contract so far we've looked at props for input and rendered UI for output. Next let's look at user interaction events. This is not so intuitive as an input that I would assert that this is a way that data gets into your component and causes changes that so let's look at testing user interaction events. You know switch back to my lecture sandbox here. We're going to go to. lecture 2 Alright, let's jump in. And I pull up my notes on here. Alright, so here new message for we have a straightforward form component. Let me show it to you in the app so you can visualize it. So for lecture two, we have a straightforward format. I haven't even styled it. But you just have you can type in some text and then you can click Send and it clears out the message as though it's a message that's been sent via text messaging or a chat app or something like that. So it's about as simple as components you can expect we've got a view with a text input and a pressible we can press to click Send. And when you click that if there is an on-sand prop passed in for that kind of an event handler it is called with the input text. And then either way we clear out the input text. We said it's the empty string afterwards so that it's cleared out and ready for users. So, how can we test this? So thinking about the outputs, what are the effects of interacting with this form? Well typing into it doesn't make too much of a difference that's typing into a text input. Like we probably can assume that that works but the the real action happens we click on the send button and this handle sends. And there's actually two behaviors two outputs. You could say or effects of clicking on handle send one is the onsend prop is called as a function and two is the input text is clear. So let's handle clearing of the input text first because that's going to be a simpler step forward as far as new testing apis. So we want to say describe new message form and I like to this kind of feels like one scenario under here. So I like to add another describe block. And I might say pressing send. And then I'm going to say it. Clears the message field. No render new message form. It doesn't need any props. It's pretty straightforward. Then we're going to use. There we go. There's my language server. So we import render and then we're going to call fire events. You use react native test to react testing library on the web. You may be wondering about fire event. I'll talk about that in a moment. Fire event changed text that's the name of the event in react native and we're going to get the element first. We're going to do screen Dot. Get by placeholder text message. And then we're going to provide the text that we want to type in hello world. So we can save this. the test will run and so this is going to render the component and then type in that text. And so instead of get by text we're using get by placeholder text to get an input by its placeholder message. If you use the react testing library on the web, you may be familiar with the user events Library, which is now the recommendation for interacting especially with react in particular and user event is really great. You absolutely need to be using user event on the web instead of fire event. Whenever possible user event is not available on react native and so interact native fire event is what we have. So that's what if you would be interested in implementing user event for reacting to testing Library. I'm sure maintainers would love you to contribute but fire event is what we use in our ntl. So we change the text there and now we need to press the button and that's very similar. We say fire event dot click. Oh, sorry that press it's a press on react native and then we get the element. Screen and in this case we can do get by text again. Send the send button. Now we need to check the result. So how can we confirm that the message field was clear what we can do it like this. expect screen get by placeholder text message again. to have prop value of empty string We save and it passes. You may remember by now. We don't trust it when it passes right away. We want to break it first and the way we can break it is to break the behavior. It's we're testing that it clears the message field. So let's change the components. So it doesn't clear the message field. We save reruns and now the tests fails another thing about making sure you see the test fail as you can see the failure output to see if it's failing for the reason you expect and to see if you get good helpful error messages. If not, you may be able to tweak the test to get better failure output. So the test said we expected the element to have prop value equals empty strings, but instead it had value equals hello world. So the text was not clear. When we enable the functionality again and save the tests. So to have prop is provided by the just native Library which provides some of these matters like to be visible. And so it confirms that this component has a prop with the given name the given value. Now if you've been in testing circles for a while, you may ask yourself like isn't a prop and implementation detail aren't we testing implementation details by testing this and I would argue that in this case, you know, it is implemented as a prop but what we're testing is what something is absolutely user visible. What is the text in the test input that is our goal. Our goal is to focus on something the user can see we're confirming a user behavior. And how do we get the value that's shown to the user in the text input. The value prop is the way we can get that. So even though we're accessing a prop here. I wouldn't recommend testing every single prop in every single child component in your apps, but this prop is allowing us to test part of the contract the external Behavior. Stella says love the point about checking if the error message on test failures are good enough. This one so I've heard about that for years and it didn't sink in for a long long time. But thankfully reactive react native testing is challenging and sometimes things fail or succeed and you don't know why and so finally I got it ingrained like okay. Let me make sure the test message that the failure message is good and if I miss it and then I see it fail and I'm confused. It's like okay, let me get the message better as well as fixing the thing that broke as well. All right. So, let's go back to the slides. So here is a probably fairly accurate unless I've changed something form of the oh, yeah, I'm missing the screen in the import. That's when detail that's different but more or less. This is our test. So let's look at a few parts of it again. So we have two calls to fire event methods fire event change text and fire event dot press. So fire event is something you import from our ntl there's three of the most common actions or user interactions that are available as methods on it, press change text and scroll scroll. I tend to use a lot less often, but that may very well be useful for you. There's also a general form where you call fire event as a function. Can you pass it The Element and then it's the second argument event name that can you can pass press or change text or scroll or any other event even custom events that your components might have and then there's event data you can pass along with whatever arguments are really passed by that event. You can pass them in your test. So the Press change text and scroll are just convenience methods for calling fire event this way because these three are the most common some coworkers in mine at a hackathon recently. We're working on making it contribution to react native testing library and we saw in the code the I would recommend you to check out the react native testing Library source code. It's pretty straightforward as far as source code goes and you can very clearly see in there that these methods are just Alias or they go to calls they call straight through to fire event and just populate the event name. So whichever way you get access to it. Basically you're firing event on the react native react native elements in the same way. Then once we fire the events, we are checking what's in the text field. And in this case we get the text field by get by placeholder text as we did above and we used to have prompt to check the value as the empty string. Just provided by just native. You can just say expect some element to have prompt prop name prop value. I will say that checking the value prop of a text input is the only thing that I've needed this for if you were testing a native component and you wanted to see what props were passed to it before you went into native land that can be another reason to call to have problems. And with that we have user interactions are complete. So we've got three of our four types of inputs and outputs that are covered. And we're actually going to do the fourth one. Now. I haven't the third part the third part of our talk and the third exercise kind of go beyond this testimony contract framework. So we'll kind of move on from there. But we're gonna go to calls to function props now and that's gonna allow us to test the other half of our forms functionality. So in order to test this we're going to use just mock functions you may have used these if you've worked with just before but here's a link to the docs. And again, it will be it's available on the the Workshop web page to get to this on react native So to create a new mock box function, I want to explain it a bit first before we jump in the code to see it. So you call Jess dot f and to create a new mock function. That's all you need to do. But I've gotten into the habit of when I remember always calling Mach name and that's gonna you can give the mock function a name oftentimes. I'll make that correspond to the name of the variable. I assign it to but that's gonna give you actually slightly more clear error messages and we'll see that in a minute decode it. When you have a mock function, you can say expect my mock to have been called so that confirms that that you know you when you pass into a component ultimately that function was called so it doesn't have any functionality automatically in itself, but it just to confirms. Hey, did somebody call me? It's a it's a function that allows you to inspect the call history of it. More frequently you can call to have been called with and you can pass the parameters or arguments that were passed. So that function you can actually check the values of this called with and there's actually a linter that recommends always using to have been called with because usually you care about the data that's past these functions. Sometimes you don't care about a certain value though. Maybe it's coming getting called from a third party. And so you can say expected to have been called with expect dot any strain or expect that any date. And so that's ways to say I expect there to be a certain argument here, but I don't care about exactly what the value so let's go to the code and see just mock functions in action because they're going to be very helpful to test this output the output of which is even more abstract than user interaction. The output that is I call the function. I called out to a function and I sent data to as well. So we're still on our new message form. And you can't see it in the UI, but you know, we saw in the code that one of the things that happens when there's an input of tapping sand having typed in text. The Onsen function is called so that's what we want to test. So, let me get my notes up. All right, so I'm going to create another test for this as well. For the reasons that I gave before I like to have small focused tests that just test one behavior of the functions whenever I can one Behavior the component. It calls the send Handler. So that's the behavior. We're wanting to confirm. These first parts, we can actually copy and paste. Render fire event fire event press so change the text and then press it and then we can say expect send Handler. Oh, actually I forgot to put in the Sandhill. So we need to create that mock function. Sometimes it actually write in in this order actually, like I'll write the assertion first and then I'll figure out the code that does I need some kind of send Handler. I want to check that it has. been called with and I want to be called with Hello World the text that we passed in you can put that in a variable as well expect Santa Handler to have been called with this. So sinland Handler is not defined. So I need to Define it. So let's do that. Just functions and let's leave it without the mock name now, so you can see in the test output what happens you'll see the benefit that comes from giving it a name. So this actually at this one we could do test-driven develop. Well now this is not test over development, but we can save and confirm the output here when it hasn't been called. We say expect just function to have been called with expected it to be called hello world, but it was called zero times instead. It wasn't called one or more times with this argument. It wasn't even called at all. So from this output here expect just function to have been called. That's not the clearest. If you look down at the code here we can see that in the code is called send him. So that's helpful, but it would be nice if this line should send Handler as well. And that's what we can do by saying Mach name. Send Handler we put in a name there and save we says expect send Handler to have been called with expected. So that's just a little bit more extra Clarity. And I tend to like that sometimes in test a lot of multiple box going on. There's some complex code being handled. And so this is name is helpful to have clear air up. But now the reason it's not being called is because we're not passing it into new message form. There's nothing to call it. So we'll pass it in we've got the Onsen prop on Sand call the send him. And again, the mental model here is that with new message form? We're not connected up to the rest of the app, but it's not sent back to a server or anything like that. The responsibilities the contract of new message form is simply to call whatever Onsen handler was passed in and so we're using a mock function here that does nothing. We don't want to simulate the behavior of the larger application. We just want to simulate there is a function here that can be called and so that's why I'm mock function with no implementation is very helpful. All of this test of new message form cares about is that sin Handler has been called. That's the contract of new message. Let's save and see if it passes. It does don't trust it. Let's see if it fails. So if we comment this out, we don't call on send. The test fails it says expect send the Handler to have been called with hello world, but it was called zero times. Now, let's try to break the arguments. Let's say on Sand is called. But we pass in bad argument. Very capacity no hard. We save and now it says it was expected to be called with hello world, but instead it was called with bad argument. So we're confirming that we're the the right arguments were not passed along with it. Now when we switch back to Onsen with input text. Test passes and by seeing the test fail we've now confirmed that the test really is covering and ensuring our component behaves the way. Started to them so something I want to point out here as well. Um, you know, if you follow this approach of one test per Behavior you end up with this duplication where you have this setup that happens here, that's this duplicated. And so there are ways to actually remove the duplication. um So and my advice approach has changed over the years to follow testing Library recommendations. And so the way this recommended now is to use a custom function here to do the setup and you could say you might call it give it a name like render and send a message. So what we can do is in this setup function, we could copy this shared part the shared part is we render and send the message. Copy that up here. Let's just replace the first one to start. Render and send message. Save and let's make sure the test still passes it does. So now it's not exact duplication though. Because in this test we have a mock as well and that's passed in so that is not used for this test. But actually it doesn't hurt for it to be present. It actually kind of makes it more consistent for depressed. So it doesn't hurt us at all to add the sin hand low to this shared setup function and then replace it down here. We are going to get an eslint error though that send Handler is not defined. So there's a few ways you can handle this. I think actually this is not what I had in my example code, but I think here it's common to return it. This is kind of the most explicit ways explicitly call a function and explicitly return of values and then you can say constant Handler equals render and send message. So this first test doesn't care about any this value and so we don't do anything with the return value, but this test does care and so we extract the send Handler so we can check it. So let's now save. Our test still passes and I guess we could try to break it if we wanted to be super paranoid you can trust me, but briefly if we break all that one of the test breaks if we comment that out the other test breaks, but if both of those are present the test passes so we've now done this duplicate setup. So in this in this point, we're basically saying in the pressing sense scenario, here's how to do it. And then here's the two things that were confirming one assertion per test or confirming that they value is clear and we're confirming that the sin Handler is called and ingest in particular. One of the benefits of one assertion per test is that you get this nice descriptive outline of the functionality. You can see in new message form and pressing send it clears the message and it calls the same Handler. And you can see if one of those breaks and the other doesn't you can see very quickly in the output exactly what's going on. So that's why I prefer this one assertion per test setup as another alternative. You can just combine it together and have one test that checks all the things but I find that that makes it you tend to gloss over details and you do that. It's very tempting to do so, so I've really encourage you to try this one Behavior per test one assertion per test approach to testing and if you do it, this is a way you can remove these locations. All right. Let's go back to the slides. So here's our test again. It calls the sin Handler. This is before the removing of the duplication. We set up that send Handler. It looks like in this example code here. I actually had message texts a variable. So let's see the differences there, but I set up the send Handler as a just function. I pass it in as a prop to the new message form. And then I change the text and press the button as usual this time when I'm checking is expecting to send Handler to have been called. And in this case actually use the message text variable. One of the impacts of that is you make sure there's not a typo between when you type it in and you bring it out on the other side. Oh, look at that though. I didn't I didn't use the variable there. So it's actually not adding a lot. Um, yeah, in this case what I'd recommend is saying putting message text in there and in there so you can see when message checks goes in message test comes out input and output. I want to go back to this point our mocks testing implementation details. This is something you can hear you can hear blanket statements that you should avoid mocking or you should never mock because if you're using any just locks, you're testing implementation details. Your user doesn't care about mocks your user cares about how your application works. I disagree with this and let me tell you why certainly mocks can be overused. If you're mocking everything you can create tests that are highly coupled and hard to interact with. In the testing philosophy that I'm talking about right here. We're talking about testing the contract. And so when you're testing component by component, you're not focused on what the user sees and cares about and expects your focus on what the rest of the applications code cares about and expects with regards to your component you're care about like when when the rest of the application or your user give certain inputs, what are the outputs to the rest of the application? And so if you want to confirm if you're looking at the contract and you're looking at the you know, this component this component does not know about API calls or whatever or calls to a context or Redux or whatever. This component knows about I call the prop function passed in that's not an implementation detail of the component. That's the contract. And so if you're just end testing you just test what the user season cares about, but if you're testing component, you should test the components contract and so mocks are not testing implementation detail when you're using it to test the contract. It's part of testing. It's part of saying what this component contract with. The rest of the application is is that this function prop is called that's precisely what a mosque is. If you didn't use a mock you would use some other kind of hand implemented way to test that or else you wouldn't test components at all. You just test the whole application integration. So I think component testing is valuable. I think it helps to make sure your components are reusable and mocks are not an implementation detail in that case. They're an essential part of testing the contracts. You can make your own decisions on that. You should think about it. Testing is not testing. Unfortunately takes thinking. There's no easy answers when it comes to testing or I'm trying to give you helpful starting points, but it's like testing takes thought. So think about these things think about them in your application code and see but I would say when people say blanket statements like if you use tests you are always testing implementation details, That's an over simple but oversimplification. I would say think about it for yourself. So with this now that we've tested calls to function props our tests of the four things that I included in testing the contractor now complete we've seen what to do with props and user interaction events coming into your components and rendered UI coming out to the screen and calls the function props going out to elsewhere in your application. So we've now covered all these inputs and outputs. And now it's time to do another exercise. So this is in the same repo intro to rntl exercises exercise 2 and in that markdown file again, there's this link to help the interaction section of this page on react native Let me show it in front of us. I know you all can read the exercise, but just to get it in front of you. It's exercise to and in this exercise. We're going to add tests for the new movie form component. Again, this is a fully integrated app where it's our movie list app. And this is a place where in an app. Yeah. I've got this new movie form. I would like to test the form as a component. In this case, the component is already written in functioning, but there's not yet any tests for it. Not even a test file. So create a file new movie form.spec add all the tests. You need to fully specify the components Behavior. And again, I kind of describe the component. It is a I do have some more little more styling tiny bit more styling, but it's still a text input and a pressible. That you're you're interacting with in a similar handle. Send. Yeah, so be sure to test the component in isolation from the rest of the app. The component is not directly wired up to the API and we don't want to wire it up to the API in the test. We want the limit the test just the responsibilities of new moves. All right. So let's take that away. I'm gonna go for eight minutes this time that's convenient. We're at 4:32. Let's go into the 440 to do exercise to here for a new movie form. And again, I especially if I said something and you're like, oh, I don't know about that. I think it would be better to test this in different way. Please do please try it and I would love for you to share your thoughts as we go when we look at the way I did it we can talk about the way you did it with love any input if you would like to share so with that I'm going to go on mute and let's take eight minutes to do exercise two. It's one more minute and we will take a look at a solution. All right, let's jump in. We'll take a look at the way that I wrote this test. And then again, I would encourage you if you would like share your thoughts on if you approach something differently or if you have questions or concerns or things like that with the way I approached it. new movieform.spec DOT, Js Yes, okay. So again, I have pressing send as the basic aspect of the approach here. I did pull out Mass the message checks as a variable. Oh, that's actually this is copied over from the widget hello world is maybe there's a movie called that because of computers, but I think let's get it more of a realistic name. Some incidentally when it comes to naming test data, some folks would say things like fake. Fake movie title, even the variable name is not correct in the world. Let's let's improve this test and we'll be right better for the next time. This is movie title So yeah, when naming test data sometimes folks would say fake movie titles something like that obviously fake value, but sometimes it's more useful to have something realistic to say like new Star Wars or something like that. So you can go either way. I'm gonna go fake movie title for now. I've been leaning that direction lately. I don't know why. Um, so here in render and saved. I took a bit of a different approach here. So instead of returning to create Handler I set a let variable here out in the context of the describe block. So that means when I assign to create Handler in this function, I can then access it down in the test. That's a bit more indirect as far as you reading the test. It's like where's the create Handler come from? But when your test is very small and focused it can be pretty easy to see it, but you could also return that values. So we create create Handler as a just mock function. We passed that in a new movie form the oncreate. Then we change the text enter the movie title. And we press send press save not sending we're saving the movie here. The first it clears the new movie title field. So we're confirming that it has prop value of empty string. It's an interesting line breaks here due to prettier, but that's all. We ensure that it calls to create him expects create Handler to have been called with movie title. So yeah, that is a pretty similar. Let me Let me show you the alternative of what it looks like. If you have one test that has multiple assertions in it, and you can see. What you think of that so let me save these changes. So I have these to improve this the next time I do this Workshop. Yes. I say if instead of one test for assertion you wanted multiple you could say it. I'm gonna name the test. You know, if so, here's some way you know what you might ask. Why does just have it as an option. I just want to say test. I might say test pressing send. So let's let's do that for now and coming back to it. Testing it work just the same. It's just a matter of conceptually how it works. So you could say let's put the movie title in there that create Handler we go ahead and assign to the create Handler there. Maybe we say can't say to a very, you know, it's not going to change we can just say const. And we render and fire events. And then we do the assertions we expect this. We expect that. Let's just delete out these separate version. Actually, let's let's keep this upper version. We'll skip it though. Save and format it. So yeah movie form pressing send it is a test and it works we do the setup and then we do two expectations one after the other so that's totally valid. And I mean, I absolutely do I'm not saying that I never do this absolutely have tests where I assert on multiple things. Sometimes very related sometimes not simulated. So the benefits of this is you can kind of read it from top to bottom you see some things happen and then some things get checked. So what are the downsides downsides are you don't see these two? Let me take off the skip because that makes it kind of hard to read you don't see these two descriptions of the two things that happens. And so you have to read code to see you have to say Okay expect screen not get placed by placeholder text to have that prop value empty strings. It's not that hard to read when you're used to react native testing library, but it's a lot easier to read clears the new movie title field. And so I think it's helpful to have descriptive tests names like this. So in this case and if you said it, how would you title this? If you wanted to provide more information in the test tile you say it? It sends the so movie title to the Create Handler when pressing send. Then you'd say and clears the text field and at that point that's the same is very long. And so that our line breaking is even kind of off but it's like it's hard to visualize. Um, so it can work. So the slippery slope you end up going down is you say, oh it clears the text field like we're gonna test that but but we don't need to put that in a test title. That's not important. But then you're like, oh well, what are all the assertions like, you're just kind of fuzzier on what and all your assertive. You just have a big massive code. That's asserting things and I tend to find that can be less precise. I tend to focus Less on the test as I maintain and change things I tend to lose track. So that's why I really prefer one assertion protest when I can to give me these focused tests scenarios. All right, so that's all yeah, just reviewing again. We finished testing the contract. We've tested the inputs of props and user interaction events and the outputs of rendered UI and calls to function props and that's really good progress. So next time next time this is not a live stream. We're continuing on this is a one-time Workshop. We're gonna take a five minute break at this point. I'm just in case people have been working through the exercises and need time for a bit of a rest. And after this we're gonna be talking through is effects and module mocks. How do you test the results of effects and hooks actually in general and how can module mocks help with this? All right, we're back. Let's get going. Effects and module mocks are third and final section here. So how can we test effects? No use use effect or really any other kind of side effects that happen as a part of our components? Well, really test the effect test the results. You don't need to check that he uses effect ran or a used query from react query or whatever from Apollo you check the effector result if data came in is the data display if a function is called is that function called out into so that's that's what you test not the internals of whether something is implemented as a hook or implemented in use a fact or react query or some other apis, you're testing the the end result or the contract. So specifically when you think about data loading effects that hit the API web service requests. It is a if in a test, you know, unless you change things if it's wired up to, you know, statically import your code that makes the call. It's really going to hit the real server API. So is that a problem? So here's here's what I'd say on that. There's all kinds of different options. You can use so think about this stack that I showed in the diagram here you have on the rest of the code in your app and then It ultimately calls into an API client module. I'm assuming you have some kind of code in your app that wraps up where the web server requests go that's not always the case, but that's just for the sake of our communities, then it might call to a network request Library like axis axios that goes through to underlying platform HTTP request support in our case in react native that in turn goes out to Native iOS or Android or web elsewhere HTTP request support and that goes out to a real Webster to make that call. So should you mark this out? I will say here that there is value in testing that you're react native app actually works with the real backhand server, but in general what I found and I think I might have a slide later that gets into more detail. For automated testing that tends to not be that useful. I'm certainly, you know, record of testing Library tests often. You'll want to run these on continuous integration. When you put up the pull request you run your rncl test Suite to make sure nothing's broken. So you want this to be reliable, but if those tests are hitting an external server it tends to not be reliable internet connection can flake out like just happened to me just a few minutes ago, um data can change on that server. It affects your test the URL can change for the server and so that makes things flaky. So I recommend with rntl tests to test your app application in isolation from your backend. So, how can so you need to mock out at some point. How can you do that? There's actually a lot of different options and I want to lay them out to you on the diagram to show the differences they make I'm in Doom all at once. I didn't animate this. It's just all one big slide. So if the rest of your code is calling into a module a Javascript file that you've written you can use what's called just module mocking to say. Oh don't use the real module use a fake one that I provide and then you use my functions. Or if you're calling out to an HTTP Library like axios there may be a library specific mocking setup like moxio's which is a axio-specific mocking setup. Or regardless of the HTTP Library you're using if you're you know, you can you can mock things out before the underlying HTTP request support by using a generic Library like knock or mock service worker. They can mock all your HTTP requests or intercept any of so that mocks out regardless of whether you're using axios or something else or if you change in the future. And then from there another option is actually have a mock web server. So instead of having an actual running web server. There's a real HTTP process, but maybe you just build a light weight with no maybe it or maybe there's tools I don't know the names of them but tools that will just serve up static Json files, but it's an actual running real Webster. So you're not intercepting. The requests requests really is going out to a real server, but maybe you boot it up on CI and it's running locally there and then that way you aren't risking the network being down elsewhere. These are all different options with different trade-offs. But the way that I want to teach you right now is actually the very first one just module Market. Is not because the others are bad. I actually use knock on my open source react native apps. And so there's a lot of value. The reason I want to teach you just module mocking is if you're using JavaScript or typescript like you are if you're using react native, you can use just module mocking no matter what no matter what library you're using if you're HTTP graphql couch TV Firebase, whatever it is. You can mock out a module using jazz. And that gives you more power one of the ways you can get stuck in testing is if you're like, oh, I don't know how to test this Library. We The Architects are the lead developers chose this library and I don't know how to test it or somebody two years ago shows us Library. They didn't write any tests and I don't know how to test it and you Google around and you hope that somebody has written a way to mock out that library. And if you don't you're stuck you say I guess I can't write tests for this and that part of your app is on tested. I don't want you to be stuck. Like I don't want you to have to find a new testing mocking Solutions every time you do something else. I want you to have a generic solution and just module mocking is a generic solution. It's not the best for everything and maybe for your HTTP stuff. You will use not your mock service worker, but just module MOX is a portable solution that I want to put and so let's do that together. Just martial marks are documented on the mock functions page. Basically, it's instead of just instantiating the mod function in line. You have another module that you're importing from and you say I want to mark that and we'll see how in just a second which is right now to the code. All right. So the functionality we're going to look at here in lecture. Three is when we click into here these widgets load on the page here. So this is loaded from a web server. There's a bit of a delay. It's a little faster now actually, um, but this is loading from a web server. So let's see the code that handles that you can probably guess how it's gonna look it's very simple. So in this widget container I'm using use effect the old school way the pre-react query way, but this testing approach will work for react query or anything else since Emily, but I'm getting this widget from the server and I'm using this API module that I've created in this module. I'm creating an axios instance hitting a backend server and then I'm passing it out. So because the axios instance is returned when module has the same API as axios, but I can change that in the future if I wanted to just use factors. So import that API call api.get widgets and then if I get a successful response, I take the and I set that as the widgets here and then those are rendered out in a flat list because we're in react native. It's not a flash list. That's another option that's out there now, but I think that would work as well. I haven't tried it. But yeah, so we have a test here. Whoa, and we have some language server protocol here. We don't want the hats. Let's take that away. You have a test already written. This is a widget container. Look we're testing that we load the widgets upon first renders. So we render the widget container and then we check for which one to be visible and which two to be visible. So let's run this test. We run it and it says unable to find an element with text widget one. So that's unfortunate. That's we were hoping to see that and we do see that we run the real applications. This test is not realistic. What are we gonna do? Well, we got to dig in a little further. And I just remembered that I don't have my notes in front of me. So let me pull those up. Yeah. So, um, the reason why in this case is because we're not actually waiting for this to return. Um, I I made this intentionally have a bit of a delay when you pull it up, but even if that was not the case, um, it's an asynchronous call and so immediately when the widget container renders, it does not yet have the date. There's still loading to happen. And so we can expect what's happening. Like what's the state of the of the Dom of the jsx tree at this point? You see an API called screen.bug. We add this and say you don't want to keep this in your tests. And that's why there's an eslint that says remove that when you're done, but it outputs what we see. So we see as a view with the react scroll view. That's what a flat list is on the hood and then there's a view underneath that but there's no children. There's no contents. So by the time we get here to be checking for these widgets, they are not there. They're not loaded. All right. So, how can we fix this? I'm going to show you some approaches. I don't recommend first that involve actually hitting the server and then we're going to see some of the downsides of that and then we'll show the approach that I would recommend instead. So one way is to make the test wait for some time before it checks and so way you could do this would be it's kind of cumbersome because it's not recommended, but you could say return a new promise. So we're going to make our own promise. And then we're gonna tell it when to be done. So In This Promise we're going to set a timeout Callback hell here. Wait for two seconds. I think should be enough. Then after waiting for two seconds, then check that these elements are present and then call resolve which is going to resolve the promise which in turn tells it test that it's fully done and Jess when it gets a promise back, it's gonna wait for that promise to resolve before it treats. The test is finished. So let's save and see. we save takes a little while because waiting for two seconds. Up. Actually we'd even longer. So this looks like this didn't still didn't actually succeeds this succeeded time out of 500 millisecond for a test. This is not supposed to happen. How would I what am I doing wrong here? Is it not? That's the API the same API that's being called here could be because of my internet here where I'm presenting it from. Try again. Oh, yeah, I guess it was spotty. I did not mean to illustrate that but check it out one run failed the next run succeeded. So that's a non-determinism that is not good to have tests and so here it did pass because ultimately that widget did show those widgets did show up but note that I have a warning here an update to which container inside of test was not wrapped. In act Let's ignore that warning for now. We are going to come back to it because this can be painful and react and react native testing. Let's look at a few other downsides. So maybe the requests would return but it just would take longer. Maybe that's what happened in the previous month. So that could cause the test to fail sometimes you could get around that by increasing this timeout even longer to 10 seconds. But then at that point you're waiting you're always waiting 10 seconds. So your whole test Suite slows way down when you have more and more of these I also if the remote server goes down or it's just not reachable your test will fail. So as an alternative, let's use just module marks to replace the API call with one that we create. Let's return the test the state it was in before we made these changes. I'm going to save. And see again too many characters here save and we just get a failure right away. Now we're gonna mock the API module. So the way do we do this is first we say just not Mock and then we pass the path to the module the same path. We would in Imports in this case. It's in the same folder API. That's going to Mark out that module. Didn't actually that's all we need for right now. So let's save this and see what happens. Just we just mock the API module again. That's the module that's imported in the component itself. Be safe. It runs it says the above error occurred. Sometimes the above error is below you. So let's go look down to look below us to find the air and it says type error cannot read properties of undefined reading events. So what this is saying is Now API does have a get it's able to call it. But what gets returned is not a promise. It doesn't have a DOT then. So this is because when just mocks a module like this, I saw them fully been able to get into my head just because models can be set up in so many ways with the fall Tech Sports and named exports. But in this case what's happening is the API magic module is getting locked. It actually sees that there's a get on it, but it doesn't know that get returns of Promise because that's too much interest infection for it. And it's maybe more than a testing live mocking Library should be so instead. We want to tell it that api.get should return a promise. The way we can do that is to just import API in the normal way in our test here. Now, we have the API object and then down in our test. We say API dot gets and then we use this API called mock this funk this method called mock resolved value. This basically says API to get is ingest mock function that's automatically created for it. And what we're doing is looks like that hint there is not correct. We're calling mock resolved value to say when API that get is called return a promise that will result and it just resolves in undefined at this point because we haven't passed argument. So this should cause API to get to return a promise that does have events and in fact will result. Let's save it and see what happens. All right. Now our tests continues it doesn't blow up anymore. Now, we're back to the same error unable to find an element text widget one. And so this is because API get is now returning a promise that resolves but it doesn't we don't have any data that's provided with it. And so we want to provide that so we're gonna in this mock resolve value we can pass the value we're gonna pass an object. It's gonna have a data key because that's the API that actually is uses. It returns an object that has a data key and we don't need to provide a full axios response object that's integration thing. You've connected everything together. We're mocking it out. We're gonna mock it out with only the API of what's needed here response needs response that data. That's all. Data has some objects we're gonna give them IDs so that the flat list will work directly about Keys call it name widget one. And then here ID 2 name widget two. Let's see if I've got this right. Let's save. We've got an act. All right, so we've got the ax warning again. The promise is no longer rejecting but we're getting null output at Y and we can try and we're getting this. Yeah, we're still getting unable to find element texts. Let's do screen down debug again. So we saw the same results, even though we're mocking this out and returning the correct values. We're not waiting long enough for to show on the screen. So, how can we wait long enough? So the way we can do this is using a different screen API called find by text. We're gonna update just the first one of these we're gonna make this an async test and we're gonna say, oh wait screen DOT fine by text which it won. But this will do is it's going to wait until what wait until this element is actually available until it's actually found so it won't be found right away. It'll keep retrying and reacting in testing Library will keep retrying over a period of time until it is And actually I should update this for the new to be visible. We can wrap this with expect to be visible to get that extra checking as well this await in the middle of a statement you may not have seen that before but this will just wait right here. And then once a value is present then the rest of the statement will evaluate so that actually works I'm going to talk about why we don't update the second one in just a second. Let's save and see what we got. Get now passes. Let's get rid of screen debug. And again, let's not trust it. But let's test it to make sure let's see what happens if I don't return which it won in the response. Can we get unable to find an element text widget one? Cool? Okay, so we're confirming that actually comes in what if I hide widget two and don't include it. And we'll Define text with element with text widget two cool. So it's confirming that both of them are present. Now, why did I await the first one and not the second one? That would be more parallel to do that. So reason why gets to asynchrony in react native testing Library, it tends to throw warnings up if you're awaiting something but that thing is already true. Let me let me try it here and see maybe that in this case it would pass but I expect we'll probably get a warning. Let's try Oh, it does pass. Well, I guess I could have tested that before. Um, so yeah. So in this case waiting to find both of them will work. I will say in react native in and react I have seen cases though where we get warnings in that scenario where it's like, hey, you're waiting for something. You don't need to be waiting for it. And it's kind of a unclear confusing one. Actually plus when you read this this kind of suggests the reader we're waiting for this and then we're waiting longer for this but that's not actually the case as soon as widget one is found widget two will be available as well. So there's some benefits to writing it this way to make that clear. But in any case I'm just a warning to you about extra async. On to teach. Yeah, we remove our debug statement there. So that helps. Um, so there's one more thing to test as well though. And this is something important to keep in mind when you're using just module marks or if you're using another test Library, it's good to think about another HTTP masking Library. What happens if I go in here? I get the HTTP call wrong. What if I call fidgets instead of widgets they save. So the test still passes the test is not ensuring that I'm calling the right endpoint and the reason why is because this just modulemon doesn't know anything about HTTP. It just knows that I said when API did I get is called mock the resolved value and it doesn't care if if any arguments or Pastor the correct ones. I want to set the test up to actually fail now that I have the wrong call on there. How can I do that? Well, apa.get is a just mock function and so we can use the apis. We already know about and here we can say expect API to get to have been called with. widgets And actually let's add Stella's note in there times. One so I didn't show this earlier. But this is what Stella was getting at. You can check that API that get was called one time and it was called with these are that's the safest to check both the quantity of calls and the arguments that were passed. The number of times was called should succeed. But call with widgets is what should make this test fail now. I say and it says yes expected to call with fidgets with widgets and got fidgets instead. So let me change that back. Now the test is passing. So this is important check because this is important output to our components when we call and I mean, I guess it is. I mean we're calling this API call. We're calling that function. We need to call it with the correct arguments. We need to make sure that the correct endpoint is being called over there. That wouldn't be the case. If your module didn't have any arguments called in if it was it was like my API dot get widgets. There's no arguments. And so there's nothing to assert there. But when you do have arguments that need to be correct that are passed you want to assert on those. One of the downsides about just module mock API is that I can't combine this up here. It would be nice to say api.get if it's called with widgets return resolve with this about but I'm not aware of a way to do that in just mocking API. The upside of this though. Is that whether this API has graphql or couchdb or anything else under the hood you can use just module mocks to test it. Alright, let's go back to the slides and process what we see. Here is a the version of this code that I wrote the last time when I was making this slide. See how similar it is as we go through again. You can see here. We're importing the API so we can have access to it. And then we're mocking it out and Jess actually runs these in the inverse order. It's hoist it up for the top such that the mocking happens. So this API object I have is the mocked version of it. And what do we do is this we call mock resolve value to set the value that should be called with if and when API to get is called. We're trying to promise that resolves to this response state that comes from the server or wherever. And we call a weight screened out fine by text to wait for the first one and then oh, I've got a query by text there. That should be a get by text a screenshot of that. Remember. Um, yeah expect screen.get by text to be visible confirm that both widgets are showing up. And then make sure that we call and we called API deck yet. It was called with the right arguments because otherwise our tests will fail our test will succeed. But the real call will fail. This is one of the concerns books have with MOX is like, oh it's unrealistic you're getting your test is passing. But in reality, it's failing. It's like Well, yeah, if we want to isolate from the server, we're not really gonna hit the server. We want that reliability. We need to make sure we set up the mocks in a way that they're tests thoroughly testing the contract. They're confirming that the outputs and they're sending back the right inputs. So, um to review what we saw in when you have a mock module, you can call that module dot a function on it like iPhones. You can call mock return value. And so that will that that's um that will just return a value immediately. It's not a promise. It's just a value synchronously returned. If you want a promise, you can call mock resolved value or mock rejected values and mock rejected value is really useful for testing error scenarios, when it's kind of hard or tedious to simulate errors coming from your server. It can be really thorough. I'm one of my favorite things about writing tests from my code. My front end code is to be able to handle all the edge cases like error scenarios. Because I just hate doing that manually repeatedly, I'll do it once but I don't want to do it every time it makes a change to code like there's no way I'm gonna have the discipline to remember to always retest all the error scenarios The Waiting scenario. If the request takes too long like gonna take like I'm gonna automate it test for that because I'm not gonna have the discipline to do that by hands. Pull up the chat here to make sure you have access to it. So we've seen get our functions before get by text get by level text and get by placeholder. Here we saw find functions. And so there's a fine version. Basically, you can change the prefix get or query or find and you can change the suffix by text by label text by placeholder. All the combinations are there. You can and these find functions allow you to wait until something is present some amount of time. I think we saw that the default timeout was five seconds, which should be enough time. Usually, especially if you're mocking these things, but that will allow your test to wait for something asynchronous to happen. And this is often very important. We're loading data server as is commonly the case. So now we're there with exercise three and this is our final exercise after this exercise. We just have some wrap-up thoughts and some big picture thoughts about a component testing and how it fits in but let's review these exercises real quick and see The lecture here's the exercise three effects and module monks. So this exercise we're going to add tests for the movie list component found in Source movie list. So here this this is our parent component. Let me actually run this app so you can see it. I should have run it before I found a nice we're gonna open it up. reload now we have our movie titles. It loads of vertigo The Sound of Music. So movie list is the overall screen component that includes all this stuff. So if you take a look we have an array of movies. Where have we have a use effect to load them? And so this is the main part we're going to be testing like are we loading from the server successfully? We actually have a handle create here as well. So that's a stretch we don't need to do that right now. But but and then we're rendering it out. So here we call through the low level components. We have the new movie form that's included. It's a part of it. And in the flat list, we have a movie row that's rendered out. So this is the parent component that's using these child components that are already tested. So we want to write a test for movie list. Um, the component is already written in functioning. Add all the tests, you need to specify the components data loading and display behavior. Only now note that the component also has data creation Behavior because the new movie form is embedded in but I would say hold off on testing that behavior for now we'll save that for the going further section. You can do that on your own if you like really basically as I was setting up this stand alone app, it kind of made sense to include the loading and the creation in one component that I didn't want to ask you to component test everything all at once you really want to focus on the data loading to start. So add all the tests, you need to specify the component's data loading and display Behavior works correctly. This component is wired up to the real API. So we statically import API and we call it that's different from the new movie Forum new movie forms took an on-created prop passed in the wiring and happen outside. The new movie test is statically wired up to the API module to get the movies. We don't want to make a real API request in our tests. Maybe you do and that is okay if you do but I'm asking you for the sake of testing out this functionality in this testing approach to not make a real API request in their tests. There are several ways you can do it but to start out I would encourage you to use just module marks the way we've done here. To them because movie lists displays the movies using movie row, which you've already tested directly because of that. You don't need to test every detail of movie row and the test for movie list instead test just enough to ensure that the behavior of the movie list component itself is working correctly. the yeah, and then just make sure that if your API to get is going to the wrong place, make sure that your tests fails. Here's the link here effects and external Services the page on react native that has helped if you would like to do it and if you get done early, here's some going further steps. You can test out movie creation or you can try out using knock or another approach to test the data loading functionality and you can think about the trade-offs there. So let's stop there. Um, I think I will leave it for let's do six minutes this time because it's 5:19. Let's reconvene at 5:25. Um, and then we'll see I'll share with you how I approached it. Um, and we can see if you have any input on the test. So, all right, give it a try and if you like and we'll see you at 5:25. Take a look at the exercise. All right. So here is my movie list test. So movie list, it loads movies on first render. So that's what I wanted to confirm. You see it running it does in fact pass. So in here, I'm in a similar way as we saw in the lecture notes. I imported API I mock the resolved value was one and movie two. This is actually not the names that come back from the real server. And so that's helpful that I can if I was accidentally hitting a real server the test would fail because it's not the same names. I render it I checked that API get has been called. I actually can put this assertion right away after the render because even though the response is asynchronous like it's it's a promise resolving. It's I got to learn more about the JavaScript event Loop, but it's the next tick or the next microtask that the response comes back on. But immediately api.get has been called and so you can make that assertion right away here. Then I wait for movie one to appear and then I check that movie too is visible as well. That's how I tested it fairly straightforward. Um, I did I went ahead I did a bonus a deep integration test as far as what I do in there. I'm checking that I can add a movie to the list. So let me show this to you since we have a little time just to get a sense for it. So when we tested new movie form directly, we were checking and we submitted it the the create handler was called so that that's what happens when you're scoping the test of new movie forms, but in the movie list, which includes having the create hooked up to the server, if we test this component movie list the creation there we need to test that API that post is called. So, let's see how that looks. new movie form that spec no Movie list us back. Yeah, there we go. It can add a movie to the list is what I said. Um, oh one other note going back up here in my test. I chose to assert that the movie title showed up that I decided not to check the the new batch showing because I already know that at the movie road test level. I'm confirming those new badges showing and that would be more tedious to test it through here at some point. If you test all of your app through those high level tests, they get extremely extensive or you just end up giving up and not actually you test somewhere in the middle of it. Not all the functionality or not. Just that Focus functionality. So really on testing here is just what happens in movie lists itself. Do I get the movies and do I render them out in some way that the movie title is gonna show up? So I'm done here, but I'm testing out in the movie to the list. This is in a sense repetitive because I'm testing the form again. But really I'm testing the wiring up that new moving form is wired up to send to the server correctly. So here I still need to mock the result value of the get because I do need to first load the form but because I don't care about any of those records here. I can just have it have an empty array as the data to keep it clean. But then I Mark and I say hey when I post to the server return this value, I just need some ID and I passed back a new movie title. The reason I need to do that is because we're actually using the post response here. I get the movie back and then I added into the list with sent movies sometimes in my in my open source apps. I actually take the opposite approach where I posted a server discard the return value just reload the full list. So that's another way you might code the app in which case your test would be different. But in this case I ran to the movie list I changed the text. I press saved and then I confirm right away that has been called. I can confirm that I've called it with the right URL and I confirm that the right data is sent to the server. That's an important part of testing the outgoing message as well. Am I sending to the server what's needed to really save it? And then I wait for that new movie title to show on the screen when that shows on the screen. I guess it does not confirming that I'm getting that data back from the server. I could be just putting it in optimistically right away, but I am converting confirming the data makes the server and that it makes them screens incidentally this approach would allow me to change between optimistic and pessimistic approaches where I either wait for the server to come back to put it on the screen or I show it right away. And if you wanted to see the difference between optimistic and pests in the stick, you'd want to test the error scenario as well to see or maybe even test the waiting State. Hey before I hear back from the server do I see the new movie title already or not? That's some of the more advanced places you could take that so yeah, that is our movie list spec. And again, I would just go back and say again, I love knock. I love these other options for testing marketing. So there's a lot of benefits to them. One of the benefits of knock is that you can combine the checking what is called and confirming what is returned. That's the nice thing about the API but I like to test jet teach debt just module mocking so you're equipped with the general solution. So that whatever apis you're integrating with, whatever libraries you're integrating with. You can mock them. You can test your components because this is a general solution. Real quick any questions or feedback on this testing approach anything you would do differently or wonder if you would or if I would do it differently any questions or input are welcome. And I will I'm going to pull up the slides while I'm waiting. distracting image for you Stella we do the loading test quite a lot for Spinners disabling an element like a submit button. Absolutely. Yeah, I do the same Stella. Um, I try to get those because I want to test thoroughly. I want to test all the scenarios and also because those are another case where it's it can be tedious to manually test those to confirm, you know, you might break them without um, and so, you know doing you want us you want to see it really once and so you might want to slow down your request or put in a timeout in your code to see that loading State temporarily or slow down your server, but it's nice to have the automated test covering that so you make sure you're loading State you're finished State your error estate. Even your first state when the screen first comes up before the load. Maybe you have a state before the Lotus kicked off instantly when it renders it's covering. All those tests gives you increase assurance. So let's talk about this crazy photo. I have this in here from before. It's an act error. I I ever initially blamed hooks. This is when react hooks was first came out several years ago and we started getting these act errors that we never got with a class components. And so I and we were like, oh hooks what have they done? It is a horror for us. This is around Halloween time. Actually, it's Halloween time when we're recording this that this is my Halloween costume that year. Um, and we blame hooks not really facetiously, at least I blame hooks. Um, but really, I mean reacts core team made it very clear like hey, there were problems already like we are we didn't want to break the API of class components, but when we're introducing hooks here, we want to take the opportunity to raise These Warnings to let people know you might be testing in a way that something is coming out. So let's take a look at this act warning because you will absolutely get this act warning in tests. I I you are the best tester in the world if you never get this act warning and I will be very impressed and want to learn from you. or maybe I just have more to grow but what I'm saying what I'm saying is you'll probably see. Let's find this in the notes five minutes. You think I could pull up these notes? Okay. So let's see this act warning. We saw this earlier on but let me replicate the ACT warnings in a scenario like you might run into. So we have we're back to our widget container now where we load the widgets upon first renders. Let's say for this test that we didn't actually care about was shown on the screen or maybe there was nothing shown on the screen. Let's say we just wanted to confirm that when we mounted this component. The right request was made to the server. Maybe it's fire and forget. So let's save this test and say render the widget container and confirm that API was called once with these are s save so the test does still pass because it's a valid test and it is doing what we're saying, but we get this warning up here. It says and I'm gonna read it to you. I know you can read but I need to process it out loud warning and update to which you container inside a test was not wrapped in Act. When testing code that causes react State updates should be wrapped into act and it shows you this act function fire events that updates State and then I start on the output. This ensures you're testing the behavior. The user would see in the browser and there's a link to a helpful web page. I hopefully I link to Kensi Dodd's article on the website. If not, I need to because it's a really good one to explain. This more thoroughly Kent is the creator of the react testing library and this originally creative the testing library suite. Um, you didn't work on the react native one. I imagine there's other maintainers now, but he kicked us off and set the philosophy emotion, which is very helpful. He writes about this to make clearly and remembering now that there are some things about this warning message that are not totally clear there the way it's written. It says like hey you fired an event in your test. You didn't wrap it in act a solution is to wrap it and act. That's not what actually happened here. And that's not what commonly happens more often. What's happening is state is changing inside your component like in response to a data load or something like that. And we can see it here. The the code output here is actually very helpful. It says inside this use effect after we get the widgets. We set the widgets and response that data and what this is actually getting at least in this scenario is after the test is done. State is changing in the components. And what that means is the reason is warning is raised is like oh like you might think that everything's fine. But then State changes after the end and your component ends up in a situation that you didn't expect. Maybe we were expecting them to not be widget one on the screen. And so our I mean, let's let's do that. Let's actually assert that real quick. expect screen dot get by text a query by text to be no we're saying hey we get we just let's make sure that widget one is not. So that passes yep widget one is no we're good to go. But widget one comes in later. It's sneaking in after the fact and so that's why this warning is here to warn you like there is a state change you are not waiting for and it might be causing a problem. Generally the solution in this scenario at least when you know, when you have like a load from an effect or something like that. The solution is not to put an act around something that doesn't actually um, you know, you're not firing an event that updates the state. It's happening automatically the component the solution instead is to do the waiting for doing before wait for something on the screen that's going to change because that that is this is waiting for the state change and that's but then we phrase this in terms of the contract you're waiting for the externally visible result that comes from the final State change. So we save and the warning goes away because after we've waited for widget one to appear there are no more State changes. There's no more surprises and react can see. Oh, there's no more surprises coming in. So you can be confident of your test is really testing the final state of the component. So generally and you know going from a react expert that I used to work with. She was really helpful to me in learning about these things. She was like, you know, probably there's a weight like even if you're not sure what's happening like probably there's a state change sometimes the test output. I find usually lately the test output the warning output has been showing me where the state change happens, but maybe it's mysterious or maybe it's not outputting correctly, but she really encouraged me like Josh like there's probably something to wait for and the other thing to think about is maybe you do have a fire and forget thing that happens and you don't have a user visible response that shows them that it's completed and if that's the case, um, maybe you could benefit from that. Maybe you would help the user to see a loading State a Stella was mentioning and then a success baby and even something as simple as a little spinner with accessibility props that blind folks or folks of visual impairments can tell what's going on, but maybe just a little visual indication can actually improve the user experience because if the test can tell that everything is done your user can as well and that can That might not always be the case. We have a lot of things under the hood going and so you in some of my code. I can't get rid of all those warnings, but it's good to try. It's good to hear the warning to see if you can make your test more reliable certainly see if there's any bugs that are slipping through. So that's the ACT warning what's going on there? With this, let's wrap up the workshop where any a little early. So we have time for some questions if folks have it, but let's talk about the final things here. What do we learn and I'll go ahead and answer these questions. What does it mean to test the contract testing the contract means thinking about your components in terms of the inputs and outputs and what the rest of the application code expects not necessarily the user because the user only sees the outside of your entire application, but the other components that are using this component what what are they going to give this component is input or the user is going to give some Corners input and what outputs do we see? We saw the contract in terms of inputs as props and inputs as user interactions and the outputs in terms of rendered elements to the screen and in terms of functions that are called to send data elsewhere or just a call. Why test the contract that's something we talked about as well, and I maybe if I didn't give as much detail before let me give a little bit more. If you're testing just your whole application that is the most realistic from a user standpoint, but that will a interactive is a bit harder because native testing facilities for full application are harder than on the web. And also you're probably not going to get down to all the edge cases to test every loading State and every error State and then test and if you do your test are probably going to be very slow. Instead it can be beneficial to have those high level and end test cover just the main Pathways and have component tests cover a more focused places. I have one react component that I'm building on my client project right now that has dozens and dozens of different states. I do not want to run through the whole application to test all of those. I want to test that component directly give it the data it needs and check the output. It's much more Focus much clearer and easier to understand. So those are recent test the contract another reason is that your tests can be more robust thinking in the flip side if you're going in and just testing all the details of the component, you know, if you're getting into the internal state or internal function calls, which I would agree are implementation details or I would say even if you're testing as Snapchat output, I would say that generally is getting any implementation details because it's checking every little detail of jsx that's outputted not just the parts that you care about that the application cares about in the contract. So testing the contract tensor result in component tests that are more durable. They tend to only change from the contract changes. They support you refactoring the component rearranging it even changing the look and feel of this and those end up being tests that add more value and have less cost over time. And then I already said whether the inputs and outputs the component just a moment ago. So that has been the focus of our workshop and I this is an approach to testing to serve me really well and served folks that I've been on teams with well and I passed along to you and encourage you to encourage to check it out as well. As I said, um, we all need to make our own decisions as developers and different situations are different. And so I would encourage you to try these things see what works for you. See what you think differently about and let me know I would love for you to get in touch and reach out and tell me what you do differently. That would be really great. Um, let me come back to remaining questions in just a second. I want to for sure. I'll keep an eye on the chat. and also Yeah, um come back to that. I want to share these links and I will leave these up on the screen and put these in the Discord channel. So continuing the learning this is just an introduction to react native testing library and to learn this library and the react native ecosystem and just test design in general. There's always more to learn. So places you can do that are go to the workshop landing page on our end tests slash London 22. This page will be up indefinitely with lots of different resources of things. You can learn links to the react native testing Library docs. I'm going to add those links about accessibility there and the links to Kensi Dodd's article about the ACT warning it. I don't think it's already on there. So I'll add those resources as well. You can also continue learning in my Discord community. So that's linked from that page. It's Community people to talk about react and react native especially about testing them and if you join in on my live stream, this is a place where people who are on there have been on there. We'll chat as well. So check out that link. Would love to have you continue the conversation. Again a test double would love to talk to you as well. I want to thank my employer for giving me a chance to come and do a workshop for you and to come and visit England. It's been so cool to be here. So test I would love to talk to you if you want someone to think about testing in this way or to challenge this they know that way of testing doesn't work. Here's what we're trying but here's what we're struggling with. We would love to join your team understand your specific pain points testing or just application design or anything and work on improving it together. We love to join teams and work on Solutions together. So reach out to test double if we can help you. I would love to join or some of my co-workers who are really great and I learn from would love to join you sometime soon. So thanks so much. Um, yeah, I will keep this slide up so you can get in touch. There's the workshop landing page there. There's my test double email address. You can reach me there with any questions. That's also listed on the workshop page. But yes, um anyone is free to go because we're just gonna be discussing questions here for a few minutes if anybody has any but um, yeah what questions or feedback do you have about what we covered anything you wanted to get to about testing that we didn't get to today. I'll hang out for a few minutes if anybody has any questions. But if you don't thanks so much for joining and I hope to talk to you online.
131 min
28 Oct, 2022

Watch more workshops on topic

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