INTEGRATION TESTING CRASH COURSE IN 80 MINUTES WITH JEST AND SUPERTEST - Node JS (2022)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey there guys my name is clement from the graphic tech and in this video i'm gonna be showing you guys all about integration testing with node.js using jest and supertest if you like this type of content please do not forget to leave a like and subscribe because that really helps the algorithm now without any further ado let's get on with the video [Music] now let's go on talking about integration testing what is integration testing in the previous video we talked a lot about unit testing and we explored the beautiful world of jest but we didn't really talk much or at all really about integration testing so in this video we're going to dive into that using node.js let's just talk about it without going into the code for like a minute so what is integration testing well put simply integration testing is um just testing a couple software modules or functions um together as a group as opposed to testing them individually which is what we did in the last video i left the links to the unit testing video i did um in the description below but in this in this case we're testing functions as a group as opposed to individual functions just to see if our entire integration works together that's why it's called integration testing and the most the most common type or most common example of integration testing is basically testing our apis when we finally um you know build them testing our apis to be sure that they pass all our tests and we we're not going to use jaw suggest in this scenario we're going to be using something called super test and super test actually helps us to test our apis and that's exactly what it's built for it has a really really amazing um api documentation that we will go through very soon alrighty so um let's get on with the code that's really not much to present here um but before we do that be sure to have mpm installed to go to nodejs.org get npm installed and then you know let's get back and start with the video also make sure you have visual studio code because that's the code editor that i am using in this scenario you can use whatever code editor of your choice but you know if you want to follow along with me um exactly just be sure to use visual studio code awesome so let's get on with the code now as you can see here i have a not so empty um folder here um just with um a date it's called data and we have a bookstore json but before i go into books.json here um what we're going to be building today to show you guys all about integration testing is a website or not really a website like a back-end api that has to do with books so it's like a regular crawd application where you can create books search for books update books and delete books right so that's what we're going to be building but we're going to be using a test driven development scenario i talked a bit about that in the last video so in this case we're going to be using books.json let me just go into it as our sort of database for this scenario we're going to be using an actual database like sql or mongodb in this case and keep things simple we're just going to be using this and test our code accordingly in that respect so right here is a um is an array of books that have the name property the author property and an id so we're going to be using treating this file as a database of sorts um to speed things up a little bit but in production of course you want to use sql or mongodb or any other database of your choice awesome so before we even get into the code or writing anything we need to initialize our mpm project and to do that we will say mpm init and just add a flag of dash y to just answer yes to all of the questions and of course um you can check the git repository which i'll leave in the description description below to type all of this um to paste copy and paste all of these things in so yeah cool so we have initialized our mpm project now and we want to go ahead and go into our package.json file and what we will see in the package.json file is you know just an empty um project here we want to install a couple of stuff not really much at all but um just go along with me and to make our books api we are going to need express so i'm gonna i'm just gonna say mbm install express we will also need express validator to validate the our post body if you have any experience with um building apis i'll work i'll work um i'll walk you through every single um step of the way so i'm gonna install these first of all and this should um happen pretty quickly awesome so we this these are our application dependencies now i want to install our dev dependencies so to do that i'll say mpm install dash d and i'll say jest and this is our testing library that gives us access to the whole describe and it apis that we talked about um in the last video and then we also want to install supertest and i'm installing this as dev dependencies because you wouldn't really be using these in production just for just for our development environment so press enter this will take a second awesome so it's done now so before we move on to create our server file with everything pre installed we just want to make some changes to our package.json to make things work a bit more um well seamlessly basically and one more thing i want us to install before i even tamper with the package.json in case you don't have this package no deem on it's it's used to help make our um developments really quickly really quick basically so um mpm install then want to install this globally dash g no demon it helps um restart our process anytime we save to prevent us from needing to close and restart our process every time so just install this i already have this installed globally so i wouldn't do this but in case you do not have this installed please do um you know delete it awesome so now to modify our package.json a little bit uh i just want to add a couple of stuff here since we're going to be testing i want to change these this um test here um this string here the key value and call this um jest we saw this in the previous tutorial watch all so that we call our jest um software or just program to look for any file that's labeled.test.js awesome so we also want to put a start script as well and this would be node and we're going to create a file soon called index and we want to write a dev uh when write a dev script as well and the dev script will say no dmon index awesome so we have our scripts ready but one final thing i want to sort of do here because of later if we don't do this when we have some issues in our test in our project setup i want to set a jests property here we didn't see this before but you can set certain gest properties to make just act a certain way if you go through um through the digest documentation there are a lot of things you can add in the package.json but for this i just want to add a key called module path ignore patterns and i want to ignore um put this in an array books dot json so i want to ignore the restarts of the jest process whenever i save this books.json because what happens is if you write to books.json like we're going to do in um the next few minutes it's going to restart the chest process and it's going to keep on writing to create an infinite loop but we we won't um we'll go through that later um i don't want to go too much into this but just make sure that you have this just property put um here just in case you have issues like that awesome so now we can move on to the actual code guys let's create our index.js file so for our index.js we want to create a regular express application right to do this it's pretty simple nothing much to it so we just say cons express is equal to require express and this express helps us to create our node.js api of course there are other um packages third-party packages that help create apis seamlessly in node.js as well but express adjusting was popular so we're going to stick with these in the express api creator package just to illustrate the use of super test awesome so we just say const app is equal to then express we need to execute the express package and save it in the app instance here and we also want to say app dot use here and create a middleware add a middleware rather and this would be express.json to allow us to post um json json objects to our api here if we don't add this won't be able to get anything posted by a user in in the request body property um so we want to say app dot use um in this case we want to make this um a very clean file so we want we don't want to write our routes here like saying app.get and whatever we want to separate our routes in a different file so i'm going to create a file soon um but let me just write this down really quickly i want any request to slash api slash books to go through my route in file which i'm gonna call book route i'm going to i'm going to create this route file i'll do that any second but let me go ahead and instantiate the process and say const port is equal to in this case 8080 and then finally i'll say app.listen and it's going to listen on port 8080 and then when the server is served i'm going to console.log backticks and say listening on port then i'm just going to write my template port awesome so this is our um index.js and this is all we're going to write here or not technically all we still need to um create our book route so to create our book route i'm just going to reference it first here and say const uh book route i'm going to create this folder really quickly but let me just reference it here it's going to be in the routes folder and i'm going to call this um or i need to put a dot forward slash first rookie error routes dot force route slash i'm going to call this books dot route dot js is what i'm going to call the file but you don't need to add the js here you can just make it dot route without adding the js extension and i'm going to create a folder called routes in the directory and i'm going to create books.route the js so this is our route part of me this is our route file right so we need to um sort of just create some code here for our entire application to even start because if we just start off our application like this even though we reference our routes file here it's going to crash because there are no actual routes here so i'm just going to write the routes really quickly we need to bring in express to do that of course so express require express here and then we just have to say we need to bring in the router property um and say const router is equal to express dot capital letter r router and we need to execute this router function because it is a function and it exposes the router um property here the router type here for us to access all routes and i'm just going to create a dummy route here dummy gets route here and say brother.get forward slash and um this forward slash is the path um that's we're going to access and the next argument is our request and our response parameters this is going to be a callback function for whenever a user hits this route here and for now i'm just going to say rest that sends to the screen a message that says working just to be sure that we are properly connected and of course i want to then expose this route properly let's say module.x my same module.exports is equal to router now we can import the router properly in our index file which we have already done of course and we have used it as a middleware so whenever the user goes to slash api slash books it automatically hits this first route here so this slash actually means slash api slash roots slash nothing or basically it's just going to go to this direct route here for the roots route here awesome so let us start off this api this entire server i'm going to clear my console of course and i'm going to say mpm in this case ron dev calling this dev script here that gives us access to nodemon if i do this i can see i get listing on port 8080 so we can see that this actually does work right but to be sure that our route is properly connected i'm going to go over to my browser here and i'm going to type in localhost in this case 8080 um slash api slash books to be sure that it's actually working properly and if i press enter i see i get this message working to be showing that it's actually working properly for us awesome so we haven't really gotten into testing yet um let's us start trying to do that and basically we're not going to use this route which i just wrote this routes you know to actually illustrate that the server is working properly um to start with the um entire testing operation i am going to uh just i'm just i'm just gonna um i'm to leave this route for a bit and i'm going to create a folder called tests right and in this test folder i'm going to create a file called bookroute.integration.test.js right um i i put dot integration here because this is not a unit testing file this is an integration testing file and it's just a way for to make me and make anyone using vmware file to know that this is an integration test for the book route awesome so this is a testing file so we're going to write a couple of things here for our tests and the first thing we sort of want to do here we don't need to bring in jest or anything because installing jest um our our nodejs understands that describe and it are for the jets package so the first thing we want to do here before we do anything because we're testing the api right we want to actually bring in to create a sort of fake application here um a mock application is it's a better way to put it that actually um sort of mocks our application and everything we're doing here in the book routes to be sure that it's actually working right so to do that in the first place we need to bring in express here as well so we say const express is equal to require express right and we also need to bring in uh super test which actually helps us to access this our mock api which we will see shortly so const you see const um in this case quality request is equal to require super test right awesome so the next thing we want to do is we also want to bring in our book routes because we need to be to actually um write like a mock up application here we need to actually bring in our book route or whatever else we're going to be running our integration test on because we are testing api routes at the end of the day and to test api routes we need to bring in the routes we are going to test so we say const book route is equal to require in this case we are in the test folder so we want to go up one directory and go into the routes folder and go into the bookstore route file awesome so the next thing we want to do and we're done bringing in our key files and programs we're going to say const this will be our fake app app is equal to then we have to execute the express function again to actually create that app and we need to put in all the middleware that the app is going to use for us to actually have access to it i know this seems a bit weird but this is exactly how it's done we we're testing we're creating an instance of the app of the server we're going to test so we need to bring in the server so to do this we say app dot you to create a middleware for the server right to recreate to make it look exactly like our actual server we'll say um apt use express.json right to make it to accept um json data from the client and we say app dot use again app dot use again and we say we want to have access to slash um api slash books right i think that's the russian route we had here in index.js and this route is going to then um have the second argument of our route file here so we have slash api books going to our book round just like it is in our actual application awesome so we have done all the necessary setup and we can begin to write our api tests so the way i'm going to do this is it's going to be a test driven method and in this case you can see if you follow what i do we don't even need to use postman to actually test our applications right it's a really really um cool process of testing our apis without needing to use postman it's uh in this case testing we just we will be sure that our integration is always going to work all the time right so to do that um the first thing i want to write here is our describe block i'll say describe and this is going to just talk about our integration tests for the books api right and then the second argument is a callback function where we write our tests and then to do our we um i i'll name this is um you know first of all we want to do a couple of of um operations here for what our api to do a couple of operations the first operation of course we want the api to do is to be able to get all the books right and to do that i'm going to write a test that says it's part of me it's oh what's this it's uh should get right it should um it should send a successful get request to slash api slash books and success uh this is just my naming convention for my test so a get request to aps books should lead to its success and the success is get all the books right cool so this is going to be an asynchronous function let me try the regular function first and show you why it becomes an asynchronous function um so and this this is this um part where we actually make use of our super test package because right now we want to test that our get request to slash api books which is our little route here will actually give us all the books right now it doesn't give you something dumb here but it doesn't matter because we're going to write our test first and then we then edit our code to fit our tests which makes sense right that's called test driven development so to do this to make sure that we are able to write a improper test to our api route we say await request which is our actual zipper test package here and it's going to request this progress is going is actually a function that takes in as you can see here in my suggestions the app um the express app we instantiated here and then we can then append other methods to it like get in this case we're going to get slash api books right and doing this returns a couple of things here which is what we are actually interested in uh so what we what we want is we want to extract those things that come with it right so we do a little bit of the structuring here this gives us two results this request to our slash api slash books it gives us the actual resource result first which is the body and then it gives us the status code it just gives us a little bit more but this is already only two i want um it gives us a couple more stuff but it doesn't really matter for this tutorial so i'm going to get the body and the status code right and for this test to pass i'm going to expect my body to equal to something and remember from our last tutorial to equal is um called deep equality is used to check the equality of reference types as opposed to primitive types like you know the primitive types of javascript right um the number the boolean yada yada um in this case we want since we're going to expect an object back or basically an array of objects an array of book objects and we want to do a db quality to be sure that we get what we are expecting and of course we want the api to return every single book in this books.json file which is our mock database so we want it to look like the books.json file this books array here in the books.json file i mean to say so basically we expect our database to return to us and array containing something right so in this case it's going to be we're going to put an array there and instead he'll be it will put expect that array containing and this will be um oops my bad there is no array out at the outside here my apologies for that it's expected array containing and then there then there's an array inside here and this is going to be an object in the array because we have objects in the books that's json array here we have an object here so it's going to be then expect dot object containing right and then we'll put in an object inside as the only argument of the methods that object containing and this will then make sure it looks like the actual objects that we have in here and what what items do we have in here we have id property that is of type number so this is how we reference the number type we say expect that any number if any of these things look new by any chance we've covered a lot of all this stuff in our unit testing video i'm going to leave a link to that in the description below um so for you to check that out and we expect a name as well that is of type string and we expect a an author which is also going to be of type string awesome so this is the first thing we're going to expect an array containing an object containing these property and values awesome so the next thing we're going to expect from this test is we're going to expect the status code to give us the success status code which is 200. if you to brush away your status goals 200 or 201 means success i think to all 200 minutes successful retrieval of data 201 makes mean successful update of data right so this is our test here and um you see that we're going to have an error if we try to run this file because of course we're using the await syntax here we need to put the async in this um in this uh anonymous function so awesome so now we have written our first test successfully so yay let's then execute our test let me close um this index file and this route file and the package.json file i'll use that let me close the books.json file cool awesome so let's run our tests our test will of course initially fail let me just write mpm run test cool so you can see that our test actually does fail right um you you if you if you read through this um it's showing a lot of red um text here don't be scared of this right it's really easy to understand it's just saying that it expected to receive an array containing an object containing all this author id and name this which is what we actually put into our code but it received message working which is exactly what we have in our route file if i could go there really quickly we just it just this just returns message working which is not what we want we want to get our list of books right exactly so of course the test will fail so how to make the test not fail we need to actually work with our api so i'm back on the routes folder in bookstore router js i'm going to take this out and just basically bring in my books right um const book data right it's equal to i'm just going to bring in the file directly um we're going to go up one directory to the data folder um and then we just access books.json awesome so what we just want to do to make this make things like really simple is a rest.json or whereas that send it doesn't really matter book data right and if i save this it should then pass awesome so our test has now passed here as you can see at the um this window here see one a test suit one passed test one passed awesome so everything's looking green and happy awesome so we wrote our fast integration test so this is a really really big deal guys i'm glad we all did this together awesome so uh now we want to go into the something a bit more complicated which is not really complicated it's really easy right it's it's nothing not so much to it really to be honest so i want to then write a post request to actually add a book to this books.json array here right um basically to do that uh the best way to do that is to first of all write the test before writing the code right but um i'm going to make use of a couple of things here i'm going to make use of express validator so we're just keep keep watch for that so to make this um what i usually like to do i like to test for failures first when it comes to posting things to the database or posting things to my server rather so i'm going to write the failure case first right the failure cases first right the first thing i want to do is say give me a second here let me go to my integration test file here and i want to write another test that says it's going to be a post request right and it's going to post to slash api books we have not created this route here again we haven't created this route so i i just want to test for failure then tackle the failure first right so basically i want to test for a failure on invalid host body right so basically to add a name here we need to pass in the name to add a book here i need to pass in the name property and the author right so if we tell we want to write a test um where the user doesn't pass in one property for example or the property is say empty how will that actually look so what we want to do is to say this is going to be an asynchronous function as well because we're going to be accessing the application using async await syntax then we say const of course this is going to be the structure to get the body and status code await request and we'll pass in the app as well and in this case instead of the get request we want to send a post request to slash api books right but also we also want to send in some data some json data so there's another property that i have not shown you guys yet so i'm going to say it's called the send property right the send not property this the send method i mean to say and listen method carries in what data you expect to be carried in ideally and we're going to write the test case for success but ideally for the success test case we want to have a name that says whatever the name is and an author that says whatever the author is right but in this case i want to say pass in only the author right or maybe just an empty string for the name and we we don't want to we want an actual name for the book um i'm just going to pass in the other as maybe john travolta or whatever right so um obviously we want to actually the structure to get the body and the um status code so to do that we're just going to say body here and status code right uh so the first thing we want to do if we pass in wrong data is we want we expect the status code to actually oh what am i writing here one second expect status code if i can type to b which is a permit primitive equality to be 400 because i want my database to return 400 when the data well on my server i mean to say to return the status go to 400 when the data is invalid right in this case the name is empty and i want to prevent the name from being empty so to do this i expect i expect it's to give me 400 right and i also expect the body to give me a certain error schema and the body is going to in this case it's going to give me something similar to what we did in the get request but not the same just it's going to be an array with um you know an object that has a property right so in this case it's going to give me i'm going to say to equal and this is going to be equal to um actually just going to be an object not an array basically at least not yet it's going to be an object that has a property called errors and it's this error is going to have a key a value of an array that has our list of errors and this is a very common schema with the um express validator um package npm package right and it usually returns um proper um it returns errors in this exact same schema so i'm using this for our tests so see the location the location usually is called body and in this case if i didn't pass in the name property i'm going to say the message has a name it has the error message rather is going to give me something like book name is required and i'm going to be i'm going to set book name is required in my api when the name is not provided so i'm going to expect it to give me this error error schema that says location body which refers to our request body message book name is required and then the param is of course the name which is this name property here so this is the general schema and then the final one here is value which is going to be empty um we will see where i put this very soon when i log out the error that expressvalidator provides us right so this is exactly what i expect my um the the failure error code of the failure the failure scenario rather to give me if i save this of course the test is going to fail because as you can see here the first thing to fail is this we get we expect the status code to be 400 but we get a 404 and we get 404 because we have not created the route right we need to create the route to make to make this test pass of course so the first thing we want to do is go back to our route file to sort of imitate this um file here to imitate this our um what we expect to happen in our test file so to do that i'll say router.post and this is going to be a post request to the exact same route and then i'm going to write request and response and this awesome so we've created our post routes um so the next step of course is to you know write our post function and um to do this to make our post to make our post to check for invalid entries by the clients um we are going to bring in our express validator package so to do that i'll say i'll come to the top here and line five and say const and i'm going to destructure the properties here in a second but i'm going to bring in our express validator awesome so this is going to i'm going to bring in check and another one called validation result which are both functions or methods of the express validator here awesome so i'm going to write this as a single route middleware which is a middleware that only affects a single route and it's going to be a list of middlewares here if you are uh i know a lot of you may probably be able to use this extra validator or have some experience with it but for those that may not i'm going to take this as detailed as possible so basically this checks for invalid entries by the client as i said earlier so i'm going to check right i'm going to use the check method here or in this case the check function here um it's going to check that there is a name property right because as you can see here in the left of my screen we we're sending both the name and the author property right for the integration test file so we're going to check whether there is a name property let me just close this to create more um to create more real estate awesome so i'm gonna type in the name and then the error if the name does not exist is going to be book name is required right and um and i expect this name to not be empty so i'll say dot not dot is empty right this negates the smt and this basically spells out like check if the name is empty right so this basically just saying the name must not be empty that's what this is just saying like just reading it from left to right not is empty and if it's actually empty right say book name is required also i'm going to check that the author is not empty so this is going to be the exact same thing so i'm going to copy this first line but in this case i'm going to say i'm looking for the author property and i'm going to say author name if i could spell is required so this is all that we have to do as regards the check function then the next step of course is to validate um that we are actually um whether or not we received an error so to do that we just say const errors is equal to validation result request we pass in the request property and this validation result um function actually checks for the request body to be sure that everything is as we stated properly in the middleware right and if it's not then it populates um this errors value here so we need to now then check if the errors are actually the error array is actually not empty so we say we'll put the um exclamation points to negate our check and say errors dot is empty is empty is a method that um express validator provides us to check if our um our basically our request actually gave an error as defined by us in the um middleware here if the user actually entered an invalid um property so this is going to be an if check to check if it's empty and if it's actually empty we can move on but if it's not empty this if check will return something and we have to return that an error as a chord right there's actually an error here so how we do that is to say return rest.status and in this case we're going to return a code of 400 which is what we're actually testing for return a code of 400 here and then dot json to send our errors back to the client and it's going to be our errors property here and then we're going to send the errors array and say errors that array like this so to have access to the error array which is this schema of errors that we are actually expecting as the find bar our test file here to get this error array like this this entire return this is what we're trying to construct here so the errors that array actually is the one that spits out this array that has the location message param value thingy here awesome so um if i save this now before i save this i just want to return something in case there's there is a success case right so um or no let me just leave that a little slipper right and that no need to return anything so i'm gonna save this awesome so you can see that our test passed right uh it doesn't really give any log out but to make things clearer i'm going to log out what i actually get um here in my test file i'm going to log out the body so we see how exactly how the body looks like obviously we we we are sure of the body because um our test path was just but just so you see that this is what we actually get from our requests if i save this you can see that if i do constant log body you can see this is actually the body we get we get a value that is empty we get book name is required parameters name and location is body as we rightly um you know surmised here right so this works at least our error case works now what about our success case are we actually able to post a book here right are we actually able to do that um to make that work we need to then um push the [Music] request body to the array of books in the book data here that we have in line four to make that work we go to the next line after we check whether the error array is empty and we say book data.push right it's going to push in the name the author and in this case we're going to just put in a random id here and to generate a random id even though this is not totally random we say math the random right just for our case this is just okay awesome so now this this will work this will um actually uh push the book into this and before i even complete this code uh this is just an illustration i want to write the success test case for this right and to do this i am going to say i want to create another test case here and say it in this case it's going to be a post request again to the same route slash api books and it's going to be a success test case awesome so what is this success test case all about we want to then have our regular async function and by now this you should be getting pretty used to this and this async function should have the same structure as this so i'm just going to copy and paste this from the previous test case and paste here just to speed things up a bit and in this case i'm going to add an actual name and say um instead of this i'm just going to say um author is uh i don't know why i called the okay let's call the book name um face off i don't know face off or whatever um so it's basically trying to send this to the um to our api and i expect of course the status code to be 200 because 200 means success and i also expect to receive something from the body right so i expect the body to in this case equal just a regular object that says message success right something simple right of course this test will fail and it'll even time us out for a bit it's still running the test because we haven't even um sent anything to the client at all so it's uh kind of weird so to to make this actually work let's just go ahead as you can see the test is even failing here so um let's make this work for all of us shall we so to make this work basically we need to as i've done here already push book data push this actual item here into book data but we need to do more than that we need to actually then update the file in um books.json we need to update this book.json file and we're not obligating we're not updating it right now right so in this case after pushing this we need to write a function that actually enables us to um save this into this new book data instance after we're pushed to this new item into the file so to do that i'm going to write a function in a different file that will require us to just say save and it will update the book data right this function isn't created yet but i'm going to create this shortly and to do that i'm going to create a new folder i'll call this helper functions and i'm going to create a folder here called save dot js right so there's going to be a folder called save.js and in this folder i'm going to create a function or you know what i'm i'm going to call i'm just going to rename this to services makes more sense since it's actually a service so i'll call this services and i'll call this save dot services.js doesn't really matter just my own personal preference awesome so i've created save the services the js and in this function we're going to require a couple of stuff we want to bring in the fs module which enables us to write into a file in node.js it's a core module meaning that we don't need to install it to use it it comes with node.js ready awesome so um the next thing i want to do is say path which is equal to this another is another core module of node.js which enables us to form paths um easily without needing to do something super complex right it's a really really cool helpful module so it's going to require path and i'm going to then write my save function let's say function save and i'm going to write a couple of things in this function but first of all i want to this save basically uses the new book the new book data instance to update the books.json file so i'm gonna it's gonna have the book data as an argument here as we rightly passed it in in our routes file in line 33 here so this book data that's been updated is what we're going to receive in this function here and to actually update this i'm going to write a try catch block in case there if there are any errors and i'm going to make use of the fs module here and say fs and i'm going to i'm going to write book data into a file to make that work i'm going to say fs.write according to what i want to do on the right the file so with the write file sync this means i'm going to write into the file sync synchronously right without using the callback function um write file method this makes things a lot simpler for us basically so what white file syncs does is it takes in the path property and then the item we want to write into um the path the file path and to make us make right in this path easy we're going to make it to the path module i'm going to say path dot join what path the join does it helps us construct our path and we want to construct our path from this saved save directory here this saves services um file i mean so to make this work the first thing we want to do is we want to refresh the directory that we're in right which is the service directory so i'm going to move from the service directory right by writing underscore underscore der name just follow me here it may seem a little bit uh complex but it it's really understandable so i want to move from their name up one directory so i'll put a comma here and then a string of dot dot indicating that we are creating a path one um one directory above so we're gonna start with our current direction then move up one directory then we enter into the data directory and then we want to access books.json so this is pretty easy to understand we're in our current directory we want to move up one directory into the data directory then books.json easy so this is path.join into this comma separated list of items that build our path for us and then to the next parameter of this write filesync function is the actual item that we want to write but remember book.data book data i mean to say is actually an array an acular array and we want to convert it into a string and to make that work we need to say json.stringify right to convert the um array or basically any json looking data into a string to actually write it properly into a file if we don't stringify this it will throw an error and it would it wouldn't work right so we want to stringify the book data right and then this is all it takes to write in a file but i put this in a try catch block because this may fail if we're given an invalid book data so in case it fails i want to just return false back to indicate that this function actually failed but if it successfully writes this synchronously write this new book book data into the book.json file i want to return true to indicate a success in another world of course we would want to run a unit test on this to be sure it works so basically uh we're going to do that in this video of course i'll say it'll be way too long so i'm just going to export this file this function hoping it is going to work so it's going to be um save here what are the exports equal to this object and save to be sure that it's exported properly awesome so going back up we're going to bring in the save function so const and we exported this in an object so it's going to destructure it and then require it right so we're going to go up one directory go to services and then go to save save that services right awesome so we have our save function with us here so we're gonna we're gonna then call it and pass in the new book data in here to then rewrite this file to give our updated book here the new book that the user has added or our test module here has added for us awesome so um what i wanted to do is um since this save function actually returns a boolean i want to save that boolean in a variable right to be sure that it actually does complete the operation so i'll just create a variable here called is saved and then pass in save this reference to the saves function this returns a boolean if it saves it returns true if it doesn't save return false so i'm going to then say if this is it's almost done here if it's saved then return res dot status um that if it's not saved i mean say if something happened in a database database is messed up if it's not saved then return status um maybe 500 to show that this is actually an error and then just send error true and message could not save book or db down or whatever you want to write here we're not really going to test for this scenario because it's a db scenario we don't want to write tests for this then if it's finally saved and we're sure it's safe we just want to say rest that's json and then we just you know return what we are expecting here which is of course um message success right so i'm just gonna say message here and success awesome and that is our post request so let's save this to be sure it works and we are still having a failure case here okay just looking at the issue here i can see that actually what actually happened here was i didn't really bring in name and author here i just um referenced it that was an error on my part um what you want to do i'm sure most of you already saw this instead of just pushing nothing in here that's why i threw an error um i want to i want to actually extract um the name and author from the request body using es6 syntax and just have this here and then this should work pretty fine awesome so the test has passed now because i it had an error here for a second so now it's actually saving it properly into the file and let's just look at this and see that that are books that jason has actually changed and then we have face off john travolta in here with a random id here which is generated by math.random awesome so we have our get and post requests awesome awesome awesome so we're gonna do um a an update request and update um api routes here and to make this update work i'm just to speed things up because i know you guys um pretty much have figured this out by now to speed this up i'm just going to write um uh maybe a a few not all the failure functions just a few failure functions just make this video now um so uh to write the update um tests here i'm just going to write a failure request for when the book is not found for example and say um and this is of course it's gonna it's not gonna be a post request it's going to be a put request right because put requests are basically um rest language for um updates right so this is going to be to api slash then this symbol here this uh column symbol then book id now just to show that this is going to be a dynamic value sent by the client indicating our book id and i'm going to write a failure scenario here pillar when book is not found awesome so this is going to the second argument is going to be an asynchronous function and um what i'm gonna what i'm gonna have here is you know the same request structure and i'm just gonna copy this and paste this um because i'm lazy save time as well and this is because this is gonna be good it's gonna go to slash api slash of course um this is an error here it's going to be slash books slash book id so i'm going to send this of course to slash book slash 3 right or or in this case i'm going to test for a failure so um i'm going to send i'm going to look for look to update an id that does not exist in this case i'm just going to write 5000 because i'm sure that 5 000 does not exist in this um json file and um to make this work basically i'm just going to say i'm going to pass in just new values here right and um give me a second i'm just going to say love me like you do ask the book name let's leave john travolta he's on a roll here so i'm going to look what this is trying to do right now this api request is trying to look for a book with the id of 5000 and then update it given this this name and this author but we we're going to expect it to fill right and give us an error of book not found basically which is what should ideally happen so the first thing of course is to expect that um the status code is going to going to be 404 404 just basically means resource not found of course it's gonna give us 404 now because we haven't created the api but it doesn't really matter because we're going to expect something else to be sure that our test actually passes and we're going to expect the body to equal in this case an object that says error true right and message will be book not pound easy so to make this work if we save this obviously it will give us an error and the error is in the put block here and book not found it's telling us that we he expected a value here it's give we it's given us an empty object yada yada so we we're going to have to create this api route right so to do that really quickly as quickly as we possibly can we go to the route file to create the put route so let me just go here quickly and just minimize this for a second and then say router in this case dot put because we're creating a put route and this is going to put to book id in this scenario here and of course we're going to have our request and our response and then we want to um get basically our request params and say const in this case book id is equal to request that params to get our parameter passed in here this book id because we be sure that this book id parameter is the same name as this book that we extracted via this es6 destructuring process also we want to get the name and author passed in so get the name and get the author this is equal to request.body of course and then we want to check whether the book exists in the book.data array right so the book data array i don't know why i keep saying book the data so to check whether the book exists we're just going to write a symbol array search function right so we're going to say it's const found book is equal to book data that in this case we're going to use the array method called find and this to use this we pass in a pass in an anonymous function here that had that takes in the argument of the actual book instance for every instance of the array and the index well we're not going to use the index in this case so we're going to leave that out so this is going to return a function in this case it's going well it's going to return an object that contains the book id we're looking for so every item every item of this area has an id property and we want to check if that id property is equal to the book id that we're looking for which has been passed in the params here awesome so if this doesn't if this book id does not exist here if this book id that we're looking for does not exist in this book data we are going to say that if book if found book gives us null right because that's what it'll give us if it doesn't exist we're going to return a 404 error right let's say res that's status 404 and then we're going to send the actual what we're actually expecting here which is an error of true an error property of true and a message that says book not found if we save this now this is going to it still fails oh cool to make this work of course um let me see why it's failing basically it's a put request yada yada um give me one second okay i just spotted why it's not working and the reason is pretty simple because of course this is a put request and i didn't change post to put so if i change post to put here expect it to run successfully right awesome i just did a little playing around here right just to check whether or not it's working uh so my apologies on that that was a simple fix awesome so it's working properly now and i don't know if you've noticed but of course it keeps on adding new properties here when we run the test every time we'll address that later um so basically um our first error case is working properly right so all i want to do now is um say let me go quickly here and then write our success case right so the success case is just going to look like this um let me just uh copy and paste this real quickly um okay and it's going to be a success case right um successfully successfully updated book right and of course it's going to have a lot of all this stuff and then in this case i want to update the book with id 3 or id2 basically id2 let's go with id2 in this case awesome so we want to i think the book with id2 here is called charlie bronzey we want to change this author name to basically anything basically here so going back to here we want to say instead of charlie bronstein i want to say jack white and then pass maybe maybe i want to let me just let me just leave the name like this right let me uh okay i'll call this i'm bad with names let me say hello world basically so i want to send a request a success request basically um a success put request to the update api and then i expect this to give me a 201 response to show that it has successfully updated the resource right and then i expect the body to give me a um basically to give me what i pass it in right right it give me give me the new thing that i passed in and of course the id as well of two and in this case right so it is what i expect the body of this request to equal if i say this of course i get an error because obviously i don't get a response of 201 right i receive something completely different um yeah so basically i need to make this work out properly right so let me save this of course awesome so i need to um work on the put request here and to make this work actually to make this actually give us a proper response um we need to give me a second here we need to actually update the book array basically so to work on this we need to then say um if right um if found book already checked for this year we want to then update this found book right as easy as that and to do that we need to have access to the books array so we want to create an update book updated books list from the books array so to do that we say const updated books is equal to in this case book data and we want to actually update this book data array so say dot map spare with me here and of course the map loops through every item in the book array and for every book we want to say if the book id of a of the current book in my loop is equal to the book id property and uh um i just noticed i don't want to do a deep equality here because it's going to check for the type of the for the um javascript type of this and the book id here is a number but everything that comes in to into um api request in node.js comes in as a string so i want to make this a double equal as opposed to a triple equal and that's why we're getting a 404 error here for our test we're going to get um not 404 basically it's meant to just time out but i'll get into that later um but this is just a common gotcha here um just make this a double equal as opposed to a triple equal awesome so in this case i'm going to do the exact same thing here if book that id is double equal to the book id i want to then up um create an updated book instance right i want to then update the book and i'll say and what i'll do in this case is i'll say let updated book right is equal to null i'm going to save an instance of the updated book outlet of this map method here so that i can return this back to the user when the function is when the whole api process is done so what i want to do here is i want to say update a book in this case is equal to um a new object where i'll spread the current book property this is this current book item here i'll spread this book here and then i will say i want the name the new name property to be equal to the name that i get from my request body and i want the author property to be equal to the author that i get from my request body or to make this you know es6 compliance i can just take out similar names for the key and the value in a object literal awesome so once i save the instance of the new book right i want to return the updated book instead of returning the regular book in the map array which means it's going to return if the book id is equal to the id you want to update it's going to return the updated book in that position in the array as opposed to the original book it's a bit i'm confusing but i'm sure um i'll try and go through it again before the end of the video but basically it's just if the book id is equal to the book parameter here save an instance of the updated book based on what the user enters and then return that book in the position of the array as opposed to what was there before the update happened and then we want to if this condition is not met we just want to return the regular old book here awesome so this is our update method here and then we have our updated books and again we want to actually then save this in the database and say const is saved is equal to save updated books and basically i want to write this exact same logic as in the previous api route so i'm just going to copy this and just make a few changes i'm going to copy this yada yada make a couple changes here then then copy and paste this here and instead of writing book data here i'm going to write updated books so it's just going to save the updated book with our save function i'm going to save it to the books.json file and if it's not saved return on error but if it's safe return success and to be sure that it actually matches up with our cinema jig right here we want to instead of returning success we want to return the actual updated book right so i'm going to return instead of this i'm just going to return res the json or rest that send updated book book without the s awesome so this should actually give us a good result hopefully and we have a failure why do we have a failure and that is pretty simple and pretty straightforward we're expecting a status quo of 201 but by default um express gives us a status code of 200 so we want to set that to 201 and we should be all good now two on means successfully added resource awesome awesome awesome we're getting somewhere so now we our success case is well successful and are and if we actually check this out here we see that we actually have hello world and jack white here as opposed to what we have before if we just take this back a couple of times ago we see we had charlie bonsley bronzy and love like no other let me run my test again you see that that changes and we then get um one second i think i i did a i did a console i i did a ctrl z by mistake so let me just save this again and this is gonna turn into hello world and jack white if i save this i'll see for id2 i get hello world and jack white as opposed to charts bossly and love like no other awesome so i want to write a final test this video is going on very long so i was just going to write a final test and say um it's going to be a deletion test to complete our entire crawd application which is what i set out to do and darn it i'm going to make it work so i'm just going to write a final test here it's going to be our deletion test and then we'll call the video a day and i want to just write a single failure failure test of course for the deletion um uh test here i'm just going to say it and in this case it's going to be deletion delete delete route and it's going to be to slash api slash books slash again book id because we're going to delete by the id and then we're going to say write another failure um event for when the book is not found uh okay and it's gonna we're gonna we're gonna get a failure when the book is not found and it's going to be pretty much almost the same as this one so we're going to do a lot of copy and pasting here to speed up the development so this the second argument is going to be an asynchronous anonymous function and we're going to make um just going to copy the failure for book not found for the put request i'm just going to copy everything here and paste it in our delete request for a filler for when the book is not found as well and then we're going to look for the same 5000 book and in this case we're going to use instead of dot put as the method we're going to say dot delete right so i've seen a couple of stuff i've seen get we've seen um post and we've seen put and i was seeing delete and we're not going to send any data because we don't send data when we delete the date the the parameters already passed in here again we expect the to get an error of 404 and a message of book not found awesome so this is what we expect to get if we save this of course we're going to get um an error here because it's it's the route is not found and we're not expecting the um error for the book not found here so let's quickly write up that route the first thing i want to do to make the route uh sort of alive is say router.delete because it's a delete request to book id and this is going to have request and response and i'm going to do a lot of copy pasting here as well i'm going to from the previous put request i'm going to grab the book id the name and the author i'm going to leave that out basically but i'm going to grab grab the entire foundbook logic here so i'm going to call copy the book id and paste in here i'm going to copy the found book logic here and then paste in here as well and we're going to get much of the same thing so if i save this i'm gonna get all successes because this is entirely the same logic as the uh update route here so let's write finally the success route for deletion right so if i come here let me just copy paste this to the bottom if i come here i want to then delete um watch me call it the the book here awesome so i want to delete um an actual book and it's going to be book 3 right and i expect to get 200 or 201 to be sure that it's uh correct um something has been updated and then i i want to get just a simple message success right if i save this of course i am going to this is gonna even time out because i'm not sending back anything um in my request right it's gonna you know time out and not give me anything basically so i'm not i'm i'm not sending back anything if there's a success case so it's just gonna time out okay so i want to then do that and to make that work of course i need to actually edit um my book data to delete that item from my book data so i'll say book data right uh or i'm gonna say const updated books is equal to book data uh which is we're getting of course in case you're not following we're getting from line four the books json file um book data in this case i'm going to use the filter method to delete the actual book that the user wants to delete by the book id and it's going to have the book instance and then it's going to say filter for the book id not equal to or in this case um regular non-deep equality here the book id right that is passing as a paragraph so what this is saying is i want my book data to only have all the books that are not equal to book id passed in the param right so that's just what the statement is saying so now we have our updated books we then want to save it and again we will copy our save logic here and just copy this from the previous put request and then paste it below and this is exactly what we want here except we don't want to pass an updated book because we have no updated book here in this case just want to pass in a message of of course success i save this of course everything is successful but when i save this again i get a failure why do i get a failure because once it's actually um edited the um deleted the id of three running the test again expects to see id of three there but the id of three is not there right so um yeah it's not going to work it's going to fail so how do we resolve this um we need to make use of a um a function that we learned before the um uh in the previous unit tests that we did and that is called it's called before all so i'm going to run a function before all to re-update my books.json right before every single test so that i have the items there as i expected so i'm going to write a b4 all and this is going to have a an anonymous function that executes before every single thing and i'm going to bring in the save function so i'll say con save is equal to require go up one directory go to data and then go to books.json and this should be the final act for the whole um show let me just ctrl z all this back to the original um state and then copy this right and paste it here as the let's call this init data const in each data is this and i'm going to instead say um save init data and this is wrong i shouldn't have brought in save as this of course save is not this save is actually um services my bad and save the services um my apologies for that mistake so this is going to take in this data and then write it into the file before every single test runs awesome so let's save this and see what we get we still have an error here okay the error here saying save is not a function and that is true because save is not a function we need to pass this in and save awesome so it's actually been extracted from the function in an object so we need to destructure the safe option there awesome so we can see that the test passed and when we save it again the test still doesn't pass odd now doing the before all right now um doing before all doesn't really um solve the problem even though it seemed at first that it would solve the problem taking a more deeper look as to the way jest actually works it doesn't really this before all doesn't really allow the right to file um property to be done um the right file function to be done before all the um all the items here run and the problem with that is we are trying to access um the the book with the id of two before um like before it actually writes everything back to file so before all even though it seems like an ideal choice to save our data to the data to to every to the um to the books that json file before we run our tests it's we fail upon the second reload of our tests so if before all does not work in this scenario what then does work um thankfully the team adjusts made and adjustments that made them a couple of helpful methods to help us to write things into files before we actually start tests and that i'm just going to take this out comment this out basically and i'm and that is called like it's called the mock method and what the mock method does it writes um mock data into a file before the jest functions run right so we do this by saying jest dot mock and in this case we are in our test file we want to go up one directory to our data file then into books.json and then the second argument of the mock the first argument takes the path the second argument of the mock method takes a callback function that then returns what value what's um basically data we want to return in our json file and in this scenario we want to return this exact array here just copy this and then paste it here before i uncomment yes so this is exactly what i wanted to return i wanted to return an array of the books here and for that since i'm doing that i'm going to cancel this out so what is going to happen here this is going to run this first and wait for the right to file function to be done first the the just write the file i'm going to be done first before it then runs all of these tests that are here so right now if we save this we see that we're going to get success no matter how many times we run the um the the the we run the test here and that concludes our jest integration test special and one other thing i need to state we're seeing this process here running at the left we don't even need this to run to make our application our test driven development work we can save this and we get our test being passed and we can still work with our api without even needing to run our process on this port 8080. it's really really cool that way and to make things cleaner i'm just going to take out the save services um method since we're not using save anymore with before all i'm going to save this and that is all and we covered quite a lot here um but uh i'm sure if you go through all the videos you will be able to properly um you know understand and reinforce your understanding of all that i have been talking about for a while so i'm gonna end the video here so i encourage you guys to leave a like and subscribe if you like this type of content and i'll see you guys in the next one and next one i'll be talking about um end-to-end testing with puppeteer and jest uh that will be a a lot less intense than this one for sure but this one is a it was requested by one of um the people in the comments so that is why i decided to um to talk about this as extensively as i did so if you like some content please don't forget to leave a like and please subscribe and goodbye
Info
Channel: Degraphe
Views: 12,458
Rating: undefined out of 5
Keywords: programming, nodejs, node, jest, supertest, TDD, NPM, javascript, API, CRUD, Web development, APP
Id: IPX0OswHoxg
Channel Id: undefined
Length: 87min 16sec (5236 seconds)
Published: Mon Mar 21 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.