React + TDD === ♥️

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
uh react and tdd is what i'm going to be talking about first of all a little bit about me who am i my name is siri i am a full-stack developer i work for a company called cygni so i am a consultant or a contractor and these are some of the clients that i've been with for the last couple of years and what is tdd well most of you probably know already that it stands for test driven development and it's something that even though you've heard about it it's not actually quite as new as you might think it's been around since like the early 2000s there was a guy called ken beck an american software engineer who wrote a book about this in 2002 called test driven development by example and in that book he describes cdd as a way of managing fear during programming he also goes on to say that tdd is not really so much of a testing method as it is a method of designing and developing and thinking about our code and he talks about something called the tdd cycle which is the process that we work with when we work tdd so we want to start off on the red dot with um a failing test and we want it from there on move with the smallest or perhaps like the the easiest implementation possible to get to a green passing test and once we're there we're not quite happy but then we want to refactor our code and go back and look at how we can improve readability and how we can remove any duplication and basically make it easier for ourselves and for our fellow developers to read and then we write another test which is of course going to fail i'm turning it green refactoring going around this tdd cycle in small very small increments so how many tests should you write well there's no one answer to this question of course it completely depends on the code it completely depends on you and but he also mentions there's a quote in this book that i really like which is saying that right enough tests until fear is transformed formed into boredom and i think what he means to say is that we want to be so confident that our code does what we are testing it to do that we just get completely bored basically so why do we develop our code in this way using tdd well first of all it really inspires confidence because we don't focus on multiple things at once we just worry or focusing about getting that particular test to go green and then we move on to the next thing so we keep like our focus like to a small scope basically and we can be confident that the code only does what is tested because we are starting with the test and then we implement like the smallest possible change to make the code run which obviously leads to cleaner code as well because um we only write enough code needed for the test to pass and sometimes it's surprising how little code you actually need to make a test go green and all this means we have an architecture and we have a design that's based on these test scenarios so we get a really clean design as well and of course everything is at the end about finding defects before your user does so the user is essentially the ultimate tester of your application so if we don't test our code then eventually the user is going to trust me and it's of course better if we find our defects because before the user does because it's better for the users but it's also generally cheaper to find them before they go into production so what about react and tdd um if you'd asked me like a couple of years ago if i thought it would be easy to reuse the test driven approach in react i probably would have said maybe and then kind of looked at all my snapshot tests that were failing because i changed the name one css class and i probably would just be like i don't really know but now like this year and like with the tools that we have available now i say definitely it is possible and it is quite straightforward actually which we're going to see in a couple of minutes and it is mostly thanks to the thanks to the tools that have sort of emerged in the last couple of years so we're going to look at a couple of libraries today that you may or may not have heard of one is react testing library and we had a really good um session here i think it was like sometime before the summer and where i learned a lot about react testing library because it is like relatively new um but the good news is that if you're using create react app like i do in most of my projects then recreates react app now comes bundled with react testing library automatically so you don't need to install this if you're using create react app which i think is great the other tool we're going to look at is mock service worker that we're going to use to mock our api course and i use both of these tools today in my production applications and i think they're really good because they are super flexible and they don't care so much about how you implement the code just like a real user doesn't care how you implement the code they just want the code that you are claiming that you uh the functionality that you're claiming to be working basically and so i think they're both really good tools to use with react okay so what are we doing today well we're going to implement using tdd this kind of recipe finder um react application of course this is the mobile design that i mocked up in about 10 seconds with images from unsplash um but it's going to look something like this so we have a recipe finder as the heading we have some kind of an input field with a submit button to find recipes and then also we are going to render a list of recipes that we're going to fetch from an external api of some sort so something like this and i'll come back to this so don't worry if there's a lot happening in this sketch um it could be overwhelming to look at it like that but we're going to follow the rules of tdd so we're going to take things in small steps so we're going to start with like a super small test and i'm going to switch over to my code editor so you see i have um two parts of the screen here where i have on the left hand side i'm really bad with left and right for some reason but this is definitely the left we're gonna have a recipes component where which is obviously our react component and on the right hand side we have our recipes.spec.js which is the test file and of course because this is tdd we're going to start writing in the test file so we're going to start with a very simple test probably like yeah the easiest that i could think of coming up with for this design so i'm going to assume that you know how to like write code in react and that like you perhaps have seen some of react testing library before but if you haven't um then basically what you need to know is this render method that we're importing from react testing library is going to render our component or react component inside this test and it's not shallow rendering so it's going to render any child components that it would have as well and then we also have this object called screen from react testing library which holds a number of queries um i'm not going to go into like in too much detail which query is best to use when because there's like some good practices really good documentation on the testing library website and so i recommend going in and checking that out they have some really good documentation and best practices and but basically what this means is that we can query things in the rendered components so we can query elements basically so this line here is basically saying that i'm expecting there to be an element with the role of heading to have the text content recipe finder just like we saw in our design and because of course i haven't even written anything in my component file so we know already this is of course going to fail um but that's absolutely fine that is the tdd approach that we're taking so we expect this test to be read now it is and it's a bit of a weird error message but basically it's saying that we're not rendering anything here this is not like a valid react component so how do we go and fix this issue like how what's like the easiest or simplest way that we can make this test green well there's like multiple ways of writing this in react and i'm not going to spend a lot of time explaining like the implementation because that's not the important part here and like i said react testing library is super flexible and doesn't really care about how you implement stuff so i'm just going to start writing like a simple class component and if you're wondering why i'm writing a class component in 2020 then hold out um but basically this is like a way to make the test pass writing an h1 tag which maps to the role of heading and including the text content that we're expecting so if we run this test again hopefully you can see the output here and now the test passes so it's green and then we have a final step in this td cycle we're now going to go back and refactor our code and this might not be that much that we can refactor like the only thing i can think of is perhaps to like remove this unnecessary div and but it's so worth going back and looking at our code and thinking how we can make this read better or how we can make like remove any duplication maybe this text is coming in as a prop i don't know we still want to go back and and take that refactoring and doing that step so now once we have refactored we're going to run the test again just to make sure we didn't break anything and we didn't so we're fine okay so now we've kind of uh we're going to focus on this top part of the mobile design still so we've looked at the um heading and we're going to have to check that there's some kind of input field that the user will see and it's got a placeholder text enter an ingredient to find recipes and we also need a button and with the text find inside it so there's multiple ways again you can implement this but i'm going to of course start with the test because this is tdd so i'm going to extend this test because it's um the same we're still in the same case when it's rendering so i'm just going to update this and i just wanted to say as well if you like i know i'm not going to go and talk too much about these different queries um in from react testing library um but what i try to do in my examples and what i'm going to show you now is that um the kind of philosophy of react testing library is to test as close to how the user would experience or interact with your code as possible and that means um making these um queries uh using selectors uh that are like available both for people who use screen readers but also those users that can see the screen so things like um checking for the get by the roles getting by label text get by text and so on things that we can actually interact with as users rather than like how i used to write my tests with css classes and data attributes um but those are things that the user won't actually be able to interact with so it kind of goes it's more um the idea with brick testing library i think more and more is getting to um being as close to how the user would make this test or would test this in real life as possible so we're going to make a couple of more expectations in this test where i'm going to look for the input and i'm choosing choosing the get by placeholder text query here just to show you a different one um and then checking that that's in the document the button has a role of his own so we're going to check that that has the correct text content so again let's run this test and of course we expect this to fail because we haven't implemented the form or the button and now we get a really nice error message from react testing library telling us that it's unable to find an element with the placeholder text of enter an ingredient to find recipes dot dot and we also get a nice printout here of our rendered and dom in the test and we can see that we of course just have this h1 tag we don't have a button we don't have this input field so let's implement that let's go and just write like the easiest implementation or the simplest way we can get that just adding an input field with the type text and the correct placeholder and a button with the text content find and if we run the test again it should hopefully pass now and it does so now in the refactor step again there's not much that i can do but perhaps like the most semantically correct thing would be to just wrap this in a form since it is a form field and maybe adding like a type submit on the button and then we run the test again and it should still pause okay great so we've just written the first react component using tdd and that wasn't that difficult but let's keep moving there's a lot of things that we need to test for so we've focused on this top part of the mobile screen but how do we go about testing that we are rendering these elements that are coming as a result from calling an api of recipes well this is where mock service worker comes in the other library um and this library we're going to use because we want to mock the server-side data in our application because we want to be able to control the data that's returned from our mock api and so we have an endpoint here that we are going to use to fetch these recipes it's basically using get method to url which is slash api slash recipes so let's mock that inside our test and to do that there's a little bit of setup we need to do and we need to import two more things one is the setup server from the node environment of mock service worker and the other one is rest from moxo's worker so we're going to declare um array here of all the the recipes that we're going to be mocking as a response and they each have an id and a title just like they would coming from the real api but we're of course going to hard code these three values here so just chosen burger french toast and someone and here's kind of where um their magic happens with the mocking where we're going to set up the server and the server is going to listen to any get request to this url api recipes and we're going to instead of returning the real data we're going to return a mock response with a json body where the recipes property is set to this all recipes that we just declared about and if you're used to working with um for example um node.js and express then you can see that there's like some similarities here in the syntax you might recognize the way that this is written and these three lines um are really important as well we're going to before all the tests um have started to run we're going to make sure the server is listening and starting to intercept these http requests um the next line line 22 we're going to make sure we reset any handlers that are reset in runtime it's a bit like difficult to explain but when we get to testing for error handling i'm going to explain i think it's going to make sense what that means um and finally we want to make sure that after all of these tests have run uh we need to close the connection with the server basically we don't want that running when our tests are finished okay so now that we have done that set up we're going to make some further expectations in our test and we should probably update this again so here we're going to use um again finding these list items by a roll which is list item and that will map to um li tag in html and react testing library has a special queries for when we want to find something in the tested component that is rendered asynchronously so then we can use this find query so basically that means that we can uh wait for a number of um i don't know retries until this actually appears on the screen because it's not going to appear on the first the first time the component renders if it's being fetched asynchronously so we can use a sync await here and don't do what i always do and forget to put async there and so we can then wait the appearance of these elements and then once we have them we can check that they have a length of three because we have three recipes in our mock data and we want to make sure the first one has a text content of burger the second one french toast third one salmon exactly like we defined in our mock um response so let's run this test now that we have made those expectations and we obviously know this going to fail but now once that fails we have something to work towards and we have something to fix and my computer is not usually this slow i think okay so of course this test fails because we haven't implemented this list it's not in the dom yet um so we get this error message saying it's unable to find an accessible element with the role list items and it actually gives us also the accessible roles which is quite nice and then again we see here in the printout of the rendered component that we don't have these list items we've not basically haven't implemented that yet so probably the easiest way to um make this test green now would be to just like hard code these data just make sure i spell it correctly and uh this is absolutely fine like in tdd uh like it's fine to hard code data or faking things until you know like how you were going to implement um the real implementation there are no rules like about how many times you're allowed to go around the tdd cycle before you get the test to go um completely green after like all your refactoring so this is like one step that we can take and a lot of the time you might not know how to implement something um in your first try and you will have to like watch the test fail many many times before you can get it to go green and that's absolutely fine so now with this hard-coded data the test is obviously green but we see here that we have of course this duplication now between the test and the code where we have hard-coded data here and the same here and the minute we write another test returning different mock data this is not going to work anymore and so of course we need to fetch this um from the real api so i'm going to go ahead and implement that in my refactoring step so i'm going to refactor this now and i'm going to fetch this using the bedroom of course again there's multiple ways we could do this um i'm just going to show you one example and again if you're wondering why i'm using a class component i will get to that very soon um but i don't want to spend too much time explaining the implementation here but what's important to see is that we're fetching data from the same endpoint as we are mocking in our test and then i want to set some kind of state with the recipes perhaps and then finally going to get rid of that hard-coded data renderer um this dynamic data instead where each of these recipes get an li tag each and the title is the text content so now we run the test again after we've done that refactoring it should still be green and it is okay great so now we have um test driven the implementation of fetching these recipes from the api and we've checked for these like various elements that we are expecting in our component and some a common thing to do is like testing that we are handling server areas scenarios in our code of course we're working with apis so we expect them to fail from time to time so we should probably have some kind of error handling and this is again like a really good case for tdd so what i'm gonna do now is i'm going to write a second test because this is no longer like the happy path of rendering everything is fine um but now we're going to check that it displays an error message to the user when we're fetching these recipes and that that call is unsuccessful so again just like the previous test i'm going to render the recipes component but this time i'm not going to wait to see these list items i'm going to find a way to see an error message with the text fail to fetch recipes and i also want to make sure we don't see any of these list items because we don't want to render them if the http request fails so if we run this test we of course expect that to fail actually we should run both of the tests that was more bad let's run both of them so we can see the first one is going to pass and the second one is going to try and find this for a number of retries and then finally it's going to fail and we can see that we actually get the same um list in the dom in the failed test here because if you look at a mock we have told the test that every time at a countess this endpoint we're going to return this list of recipes but now we want the mock to behave differently for the purpose of this test because we're testing a server error scenario and so we're going to override the previously defined mock with the server.use method from weka so what we can do here is for the scope of this test we can actually override this previously declared mock with a different response for example setting a status of 500 and a json body with the message internal server error of course i could mock any http status and message but this is the one that i chose for this example um and this is where i should mention this line 22 becomes important is because we want to make sure that we reset any of these handlers that we have now overridden um in a specific test so that it doesn't leak onto subsequent tests that we might have so this one is quite important now so let's run that now that we have um overridden a mock and we will see that we get a different error message we still haven't implemented anything in our component so we're still going to get a failing test but now we get a different type of failure where we're it's still looking for some recipes in the states and we don't have them of course so to fix this and make the test go green let's get rid of that and then uh we're going to do some error handling in our factual recipes method and so we're just basically only setting the recipe state if the response is fine if not we're setting this error message state and again there's like like multiple ways you could do this um i'm not gonna go into like yeah the um specific implementation as much but we're going to render this error message and as text as well in our render method and then once we've done that we want to run all these tests again and now they both pass so for the refactoring step here i'm going to make like quite a big refactorization and this is where i'm going to show you why i started off writing a class component because a common thing that we do refactor in react is we usually or is like i find it's quite common is to turn these like kind of legacy classes components into functional components instead so we usually replace this dot state with the use um the state hook and we replace like component and mount and doing our side effects we do that now in the effect hook instead so we're going to refactor this to a function component whilst keeping all the um functionality that we still have and before using react testing library i would have been a bit hesitant perhaps doing this all the time because i would just expect making such a big refactorization would mean a lot of my tests would fail but like i said before react testing library is really clever so it doesn't really care how you implement your code just like the end user doesn't care if you're rendering a class component or a functioning component or if you're using you state or a set state um it shouldn't matter to the tests either so we're just going to like get rid of all of this class component stuff and instead we're going to render a function component um and and this is where yeah i keep saying that how you implement the code it doesn't matter because it really doesn't and we now have use date and we're going to use the effect took to fetch all these recipes and we're going to render the same content so when we run both the tests again they will still pass because we haven't changed anything that actually matters to the end user so i think that's a really really good advantage with both these tools and another thing like the final thing i'm going to show you is something else that i've done some refactoring on in the past is to change the module that is making these http requests so if you've been paying attention to the test code on the right hand side you can see that there's no mention of the fetch api here we're not mocking a specific module if we were using jest to make our mocks then we would have to mock a specific module but we're not with mock service worker we're just intercepting these http requests so meaning that i can replace this use effect with using a third-party library such as axios instead to make the http call and of course because it is third-party module i have to import it and and because mock service worker is so flexible it doesn't care who who's making the http requests if it's axios or if it's fetch so the test is still passing and they're fine and i think both of these tools really show their strength when it comes to how flexible they are because refactoring is such an important step you don't want to be hesitant making these things you should still trust that what matters to the user is still intact basically when you do these refactorizations so of course there's like a lot of things that we could test for in this application we should probably do something to simulate the user interaction when they enter something into their filtering and pressing the button and we should probably test for some like maybe form validation and there's like a lot of things that i can think of but i'm not going to show you that now i'm not going to have time to do that properly but i have written a blog article where i go through like a longer example and have like a full code example at the end as well so i'm going to link that to you in the end and but hopefully these examples have given you some inspiration to go and use this um and work test driven even in your react projects and hopefully we've now turned our fear into confidence perhaps even boredom and thank you so much for listening and here is the link to my blog article that i wrote about this and i'm going to post this in the chat as well at the end so thank you so much i will now have a look in the chat and answer questions okay where is the chat here it is okay so shall i start right yeah yes i'm just gonna go okay cool uh so how is so this is a good question how would you build mocks on top of uh redux i'm guessing it means like how you would test your um code if you like usually you have redux involved in this too right or i think that's what it means um i didn't show that in this example but like i mentioned i think that it's not shallow rendering the component so if we have redux in our application or um yeah we have to basically also render that in our um tested component so we can we have to render like any redux providers and we have to basically work with a mock store in that case and there is like really good documentation on how to do that in react testing library as well um and yeah that's something you set up like once for your project it's it's a bit of like uh tricky and sometimes sometimes but it's uh something you do once and then you should be fine after that and yeah it's um i think it's a different tutorial together going through redux as well but it's a really common use case so there are um documentation just about that as well do we have what sorry i'm just reading through the questions lots of thank yous thank you very much hopefully you enjoy this what are the benefits of unit testing front-end application i understand the benefit of end-to-end tasks per unit that seem kind of pointless sometimes okay yeah i think like i understand this question uh let me know if i don't but um i kind of have kind of stopped doing strict unit testing and because like this person i think albin said i think i agree with the fact that like it's for me it makes more sense to test uh components like not in isolation because they never rendered in isolation in the real application on on the screen in real life so i feel like um especially with react testing library the kind of philosophy there is that you want to try and test higher up in the tree or like in the dom um and then because we're not shallow rendering we are going to cover the kind of individual components um as well so there's no like rule for react testing library not to be used with unit testing um but i think um it can be done for both integration tests and unit testing um but like for me personally i think it's worth testing components like kind of not too much in isolation maybe that's like a controversial thing to say but i think yeah in real life the user is never like the button is always like it's never really resonated with me to test like um on click prop uh things and like checking that that has been called number of times because the the button voice does something it's either like it's doing something and the user is always using these elements together somehow so i think it makes sense to test what the user is actually going to get out of clicking that button rather than just oh it works to click the button and it calls the prop i don't know if you agree but that's what i think what do you like to use for end-to-end tests um yeah good question i am using like if i were to make a choice now uh you don't always get to do that unfortunately when you work as a contractor but i wouldn't use i like using a tool called cyprus for my end-to-end tests and because it's written kind of has like a similar syntax to like the other javascript testing tools um and it's kind of like and it has a nice interface to it i think you should check out cypress there's some i haven't tried it out with um there's a react test or not a reactor but there's a testing library extension now for cypress which i haven't tried but i think that's meant to be really good so that you can make these queries that i talked talked about like the accessible queries getting things by the roll and label text and place all the text so i think that sounds like a really good idea and in my next project if i'm allowed to use that then yeah i'm going to push for that okay how do you approach visual regression testing nowadays seeing as you moved away from snapshots yeah i mean to be honest like we still have some old snapshots in our application but snapshots is kind of like the opposite of tdd like it's very hard to write the snapshot before writing the code or it's i don't know i think it's probably impossible maybe um and visual regression testing is something that i've looked into before i've used things tools like backstop js and things to try and make like proper visual regression where you kind of compare pixels and stuff like that and i think that's something that's really interesting and so far i haven't unfortunately like if people know of good tools for doing this um feel free to to share that with me as well because i've yet to find a really good visual regression testing tools because the downside to all of this is that i mean we haven't tested any um like real layout we haven't tested any css basically in this we have we can we can test that something has a class or whatever but we still don't know how that's going to look when it's rendered unfortunately even in these tests okay next question that ui for running and seeing the results was that in vs code no uh i'm a bit embarrassed to say this but i actually in my civilian life i use java to code so this is intellij which is a java editor um but yeah i don't know maybe available in vs code as well um but that was intellij is it common to test more pixel accurate tests for things like break different break points when making reactive designs and marcus is asking um yeah i think i mean with cyprus the tool that i mentioned earlier for end-to-end tests you can definitely you can set different um breakpoints or you can test in different like screen sizes and stuff like that for clicking because obviously that is like the gui kind of clicks around for you in those tests which i think is quite nice um but yeah again like testing how things are actually rendered on like a snapshot basis or visual regression basis i tried tools like backstop but i just didn't think they really did exactly what we wanted to do so happy to take um suggestions there do you know if you can use cyprus with moxozoca i don't know that um but i don't see why not really i don't want to promise too much but i think like how it works i think the mock service worker is really flexible and the main kind of the use case it was developed for i think initially it was not actually testing but it was to have um do mocks for local development so you can have um have this set up like in your browser as well so when you develop something locally and you don't want to go towards the real api then you can use mock service worker um as a layer between the browser and and the real api as well so it is very flexible i would yeah i would like to find out the answer to that question too but i don't see why not and patrick's saying i'd like to mention a chrome extension i used recently which was awesome for finding selectors for testing like using best practices okay great and he posted a link to that so yeah let's let's take a look at that because that sounds like a good thing that sounds like something i'm going to check out and um and yeah so david just posted this uh a blog post about using mock service worker with cyprus so yeah clearly it works great thanks for that um but yeah there are some there's so many like i think we live in like a world of like best practices and they keep changing all the time and i know it's like it's hard to keep up with all these things and i think sometimes it's just like you just have to use common sense and do your the best as you can like you can never i don't know fully like please everyone i guess but it's it's good i think um react testing library is nice because it is like clearly a very active community and like a very um they have some like good reasoning behind their best practices as well like i really like the accessible thinking for example between the queries and they've started developing this um alternative to or i think it's um something we can use now it like safely use is the uh user event part of react testing library to kind of uh to simulate use user interaction as well and i think um it's something that keeps they they keep adding to it all the time so i think it's it's like a really active project basically so i think they have some good ideas okay vs code has a terminal as well taylor says okay good i don't like it was a long time since i used this code but i do imagine they have something similar mock service worker seems awesome i'm curious if you have pointers for testing code that uses web workers or its own service workers for that matter uh no a good question i don't have anything that i've worked with that i can think of that has its own service worker or web worker yeah if someone else has an idea feel free to answer but yeah sorry i only literally start using mock service worker like i don't know this summer so i'm very like new to it as well but i really like it so far i think it's um yeah it's a nice tool especially because yeah you can use whatever module you want and you can yeah refactor that like i showed you so i think it's a nice and also one thing that i like about it too i can mention it's kind of like a bit off topic is that what i struggled to do with just was to mock when you had a like a search query saying like you had a query parameters in in the url and you wanted to test different scenarios based on that and you can do that really easily with mock service worker which i think is nice okay so we got a tip about something called mirage or mirage.js is pretty neat for mocking data too okay cool we'll check that out haven't heard of it but thanks for the link okay great
Info
Channel: Stockholm React JS
Views: 5,080
Rating: 4.9431281 out of 5
Keywords:
Id: IzAX80fWrOQ
Channel Id: undefined
Length: 41min 12sec (2472 seconds)
Published: Thu Oct 08 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.