JavaScript Testing Basics with Jest

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello and welcome to swashbuckling with code i'm jimmy cleveland and we are going to go over just the javascript testing framework in this video and see what it has to offer if you're not familiar with testing in javascript or unit testing in general what it allows you to do is write some code that effectively runs whenever you run the script and it tests each of the individual units of your code that you wish to test for reliability and consistent results and if you're wondering when you would actually run those test scripts well it's actually up to you but it's really common nowadays to run them in continuous integration setups or in your code pipelines or anything like that where each time that you push up your code or you make a pull request or anything like that some tests will automatically run and it'll give you that extra bit of confidence that you didn't make any mistakes in those commits and those pushes or pr's etc you can also run them manually as you're doing things and you can even do a really cool thing in just where you have a watch mode where it's watching your code for file changes and automatically running the test on those codes so you'll get instantaneous feedback of whether you've introduced an error regression or anything like that this is really useful for you to get some extra confidence from running the tests as you run your code but i think it's even more useful for maintainers or people that are foreign to your code people reviewing your code if you work at an organization or you're doing open source or even users of your code to know that your code runs as expected by just reviewing the tests or running the tests really quickly it's kind of become a standard in a lot of companies that your repository or project must have a test suite this even allows people that don't write the language of code that you write to run the tests and see that it does run as you expected at least it even doubles as an extra form of documentation which i think is really cool and i go over a little bit in the video where as you're writing these tests it's showing to someone who wants to come in and look at your code rather than looking through that code and having to you know mentally load everything that's going on they can start at looking at well how do you call this function and what do you typically pass to it and what does it typically return so with those definitions out of the way i'm going to show you setting up a project from scratch and adding jest to it which is pretty simple and then we're going to add some tests uh step by step as my usual format and i'll show you what it's like to pass a test and fail a test and making some new files so we can bring in to test a little bit of that red green refactor pattern for test driven development if you've ever heard of that i'll just briefly touch on that we'll also go over some of the nice little tools and functionality such as the watch mode testing regular expression patterns for files matching and stuff like that we're going to go over coverage reports which is a really really cool feature of jest that can show you how much of your code is actually covered by your tests and it'll give you a nice little visual report of what things are missing what branches of code that you're not actually checking in your test which is awesome and then i'm going to wrap it all up with snapshots which is one of the things just is really known for love it or hate it it's a hot topic but it's actually really useful in my opinion and i'll just show you some basic use case of it in a little bit more complex testing example and i think that sums up the overview so let's write some tests [Music] all right so let's start out by making our project and what we'll do i've already made the directory here but we'll do npm init dash y and i'm just you know going to answer all the questions yes and then i'm going to npm i for install jest and you can obviously use yarn if you prefer it doesn't really matter to me now that that's completed we could make a script in our package json or we could just run mpx jest now when you run that it's going to run all the tests once in this case you can see it says no test found so what we'll do is we'll do mpx jest and then you can pass a dash dash watch flag to it which also isn't going to work for right now and they tell you why it's because without git or hg please use the dash watch all command which is nice of them to give you that hint now the reason for this is because the watch all command just every single file change runs all of the tests whereas if you're let's say you use git it will watch the changes to each file and try to run the tests on only the files that have changed just so you know we're not going to add git for now because i don't really need it for this demo so we'll just continue to do watch all so we'll say bix jest dash watch all right so you can see that it didn't find any tests still of course and we have all these little helpers which i'll go into a few of them a little bit later for now let's actually make a test to satisfy that so i'm going to make this wolf.test.js and you can see that it automatically picked it up and it says your test suite must contain at least one test so dialing back just a second this woof.test.js well i named it woof because i'm actually going to have a function and a file called wolf and that's a really common convention for testing is to name the test the same as the file and or the function and then there's a few different ways that you can structure your code for now we're going to keep it flat but it's sometimes common to put all of your tests in a test folder and it's sometimes common to put them right next to the files it's really up to you and your workflow to decide what's best for you i i kind of like the merits of both but i typically put them right next to my files for now we're going to keep this flat and you'll notice that this dot test well this is why it's picking up this file automatically without any configuration at all just is going to look for any files that are named dot test and here i just want to show that there's also a common convention to call it spec dot spec and some languages that's how they commonly do it but i usually see a dot test and that's what i stick to so you can choose that as well but you'll see that floating around just so you know okay so now it says your test suite must contain at least one test well they don't really help you out too much here but you could read the docs really quickly to figure this out so what you can do is you can type test here now when we type test this is actually a global that just is adding to the test runner so when you're running the test suite you have access to this in any of these like test files so i'll just call that function so i know that i need that and you can see that it says invalid first argument undefined it must be a string so that's pretty cool so let's do that we'll say our first test we'll save that and now it says missing second argument it must be a callback function you'll notice they also make this little hint to perhaps you want to use test.to do which is really cool little helper that i'll show you in a little bit so for now let's give it a function now we can just pass it our standard function format just like this or you could use an arrow function and i'm not going to do anything in that i'm just going to add the braces and save you can see that our test passes so this is interesting because we haven't actually done anything but what it's just looking for is that the code runs successfully within this function so you might wonder okay well what causes the test to fail well let me show you you could just type some gibberish in here and that's not real code so it's going to fail all right you could also type uh let's see oh you could actually throw an error here and say did not work and now it'll actually give you that message our first test you can see the x failed did not work and something interesting that i want to show you is this unlike you know having all of your code execute in like one file where if you end up running an error like that the rest of your code will stop executing in javascript there well i can actually make another test here and in this test i'm going to say failing above or something like that there's really no rhyme or reason what i'm doing and you can see that that test still ran and that's the thing that i wanted to point out is this is kind of an isolation here whenever whatever's running in here fails it's still going to go on and run the rest of the test suite because you want to know like in total how many tests fail you don't want to just fail on the first one so that's really cool and just wanted to show you that's basically how that works so next what we want to do is actually make a file for this so i'm going to remove this and i'm going to remove this for now and save both of those get our test passing and then we'll make a file called wolf.js here and in this file i'm going to make a function i'll call it wolf and i'm actually going to make it take a string and what i'll do is i'll just return the string and then i'm going to change it just so it actually has some sort of functionality and i'm going to add a loud wolf to the end of it and i'm going to use module.exports here to export that woof now of course you can use esm uh exscript modules if you have that set up but we're just going to keep it with this module exports comma.js format so let's actually import that now so i'm going to say constwolf equals require and i'm going to go grab that package real quick and now importing it works fine and then here we'll actually run it so i'm just going to call wolf right here straight up and i'm going to call it with a string or hero now you can see it's still passing uh so how do we know that it's actually running that code well if we hop on over to wolfe.js let's just throw a console log in here and then let's say uh the wolfram and then we'll just put like the argument that it got here just to show that and this is pretty neat so you'll see over the left here there's this console.log the wolfram oh hero and that's what we got all right well that's pretty neat and so you can see that it's actually running our code from the test suite and receiving our argument now a quick little thing that i want to show you here is uh i'll close this down now there are times when you're troubleshooting and you want to console log some stuff especially when you get into mocks or you're just trying to figure out like how that all works and it's really flooding up your test logs well what you can do just so that you know as you can run let's say we run this mpx jest again just to show that you're going to see that console log but if we run jest dash dash silent it actually won't print out any of the logs that it receives which is pretty cool so that's just a nice little flag to know in case you you don't want to be adding and removing logs over and over again just to hide that stuff and see the tests so let's go back to our watch mode watch all here so let's actually make this fail now from the actual code that runs so i'm going to take out that log and i'm going to change my function and let's say what i actually want it to do is take the string that comes in and do a dot length okay and so now i'll have however many letters there are in my string woof okay and if we want to see that we could do let's store the result for a moment so result or whatever you want to name it and then we'll just console.log right here what are we getting back from that result okay you can see we get eight woof so what i'll do next is i'll pass it nothing and you can see that when we pass at nothing we get a failure and that's because we try to read dot length so it says cannot read property length of undefined so you get your typical error printed out all right well let's just make that pass now we just go over to our code and then let's do we'll do a condition here and we'll say um you know type of string that's passed in the argument is not equal to a string if that's not true then we want to return okay and then now you can see we get back undefined but our test does indeed pass so right here this is a pretty normal workflow for testing and and this is what can help you get a little bit more confidence from your code and why testing especially unit testing in this case is so useful because you get this immediate feedback from running your function and then trying it out in different ways and every time you find a way in which it could fail you can write a test for that and then you can make it pass afterward and that is known as this red green refactor pattern which you might hear sometimes especially in test driven development so that means that red is a fail you want to write your test first with the idea of what you want to test and so that's our wolf function and we'd say that we expect it returns the number of wolves or something like that so let's do that let's say test should return number of whoops or something you know name it whatever makes sense to you for your functionality this is obviously a silly example but from there we'll make it fail first by passing it no argument like we did and then we go into here and then we we rectify that and then now we have a test to give people some confidence that that works and then what's cool about that is if someone in the future is not even looking at the test files or anything like that they come in and they change this for some reason maybe you know they change it to just look for was string passed in but then like something that an argument's passed and that doesn't have the dot length property so they'll get a fail as soon as they run the test suite and they can know that they need to go back and fix that code and so we get a little bit of extra assurance in an automated way that takes you know human error out of the picture now this topic gets pretty deep i might actually do a video covering all about unit tests and and the why and how and all that stuff you know not from an actual code perspective but instead of derailing us let's stick to you know just functionality for now i just want to give you a quick little reason on you know why we're doing what we're doing so going back to wolf.test we can actually take it a step further here i'm going to stop logging this for a moment we can use the next type of gest functionality which is an expect statement so this will return what's known as an expectation object and so what we can do is we can pass in the result there you could also just run the code right there if you want to so we could just call with like this but i'm just going to do the result since we have it and i like to store it in a variable because then i can you know quickly log it out or or do other things with it so that's just my preference so when we expect result that's not really going to do anything just yet that's useful for us we need to add what is called a matcher after that and then one of the most common matchers is 2 b okay so when we run this 2b here what we want to say is what do you expect to come back from this well we know that from our previous log we're going to get eight woof back right so i'll just put that exact statement now we can see that our test failed because we didn't pass anything in right so let's go back and pass in uh what was it oh and that gave us our path now how do we know that that actually works there's a lot of ways we could go about this so you could just change the string that's the first thing i do and you'll see that it gives you this nice highlighter and it shows exactly what's different here so maybe we got the number right but for some reason we messed up the string and you'll see it's like oh expected received let's take a look at that real quick so it tells you uh the name of the test that failed should return number of wolves and then the expect received to be expected and it's trying to tell you that the green here is the good scenario this is what you want you think that you want 8 wf to come back in this instance and then received here is what you actually got we have these kind of reversed in this in this instance but it's just for showing like how to make it fail and so this is this is showing you here okay like you got something different and we're we're kind of color coding it red sometimes this gets confusing uh in certain scenarios of why it's red and why it's green so i always just kind of like default my brain back to well the expected is green like what we expect in our test should be green so let's make that go back to passing okay so now we have a passing test we have a test that says uh here you go you call this function and you pass it the string and then i expect the result of that to be and you can see how it kind of reads a little bit like english here and as this eight wolf as the argument so that's an exact match there now what's really cool about this is that this starts to show how testing itself can be used as a form of documentation i'm not saying that it should replace you know actual handwritten full explanation documentation but it's actually really nice to come in and look at okay you know i've got this wolf.test file so i'm new imagine we're new to this code base and we're trying to figure out how something works or we've been working in it and someone added some new functionality we're a maintainer well i might look at this wolf js and in this case it's really easy to read right no big deal but if it's this big long file it will take me a while to mentally parse that but if i go into the tests not only can i run the test and be like does this code even run first of all which you should do you know run as they expect the user who wrote it is like i expect it to work in these situations and they write the test for that but you can also come in here and read the statement and go okay so looks like wolf is supposed to return a number of wolves and then we expect to be oh okay so this is how you use it basically you're saying oh you just you get to see it in action it's called so you get a little example here and then you get to see what what the result is and so that's a really nice way to kind of be introduced into a code base to see all the code and how they intended to be run so we have this statement and to re-iterate over the terminology here this is called an expectation object that's returned from this and this is called a matcher by just documentation now there are other forms of matchers as well so let me show you if you you can run more tests in this one test so we can expect result dot 2 b and in this case let me show you the opposite you can do a not in front of it so you can say dot not in front of any of the masters as far as i know i've never seen one that you couldn't do it in front of and this will say it's kind of how you say i want the opposite so i expect this not to be now this is a dumb example but you know let's say bark and that works out right now i could do a woof just to show you and it will fail so the first statement actually passed because it did expect it to be but the whole test fails if any of these expect statements fail so in this case let's say that you know we remove that and the first thing that we wanted to test was um you know we had an error one time where the number was printed out and we we changed our code in the future that we didn't want the number printed out for whatever reason we might throw this in as kind of a cover for that to make sure that it doesn't ever revert back to that functionality or we might want to just test that other values that we know uh might come up are are not what is the result here and so that's what the not is for in a lot of situations there's other other reasons to use it but just to show you that so there's also other matchers here so there is uh let's let's wipe this whole thing out i want to show you that there's a two equal that sometimes people get confused with and so you might wonder what's the difference between 2b and 2 equal let's copy that and replace it so now they say the same thing two b and two equal you see they both pass and that's what kind of trips people up understandably is that it's like well what's the point of this well two equal is actually meant for objects and arrays for the documentation and that has something to do with uh 2b being more of a strict equality comparison uh or an exact equality comparison where as to equal like objects and arrays you typically have to handle them differently and you you serialize them or something like that to do a comparison so that's what two equals typically for let me show you that while i show you that you can actually just write you know whatever you want here first of all so let's just make an object okay and this will be an interesting example so we'll say we have this object and we'll do a is equal to one and then we'll just do two properties okay e is equal to two let's actually get rid of that sidebar real quick here just so you can see the whole code okay so now of course that's not going to work so what i'm going to do is i'm going to copy that whole thing we'll put it in here so now i have uh both of the same thing uh being compared here and you can see that it's passing them and if i were to change anything in this it's going to fail and will actually give you this nice little layout here where it shows you you know the properties and exactly the difference between them so remember that the green is the expected so our two equal here is what we expect and then the red is what we actually got that was wrong in this case so let's go back to that and let me show you if we were to do 2 b here it will actually fail now this kind of threw me off a little bit since it says if it should pass with deep equality replace 2b with too strict equal they don't give you just the simple the answer that it should just be too equal but i never use too strict equal for any sort of deeper quality check to be honest because i always test my objects in smaller chunks or snapshots or something like that but you know if you happen to know why uh that is the error that's thrown there go ahead and throw a comment but i'm not sure and i know that it's just supposed to be two equal per the docs if you're just doing a simple comparison here now this is also true with arrays so we could make it an array right here and it'll be the exact same thing let me show you another common matcher here real quick so we can also say expect result and if we want to get a little more generic which i find to be really useful and i use this quite often we can use to match here now to match we'll also take a string but what we can pass it is a regular expression which is what i usually use it for and i'm typically going to make it a case insensitive here but what we can do is we could just pass you know a woof or whatever now notice i'm leaving off the exclamation point here and when i test this it actually passes well what if i do something like that no it's not because that's not the correct format but we could leave off the eight as well so what what this is essentially doing is saying you know can we match any part of this here and so what might be useful in this example is we might want to use uh the escape d for like digits here and say i just want to make sure there's a number in front of it okay and then it has the wolf afterward so let's say that we don't do that anymore you can see we'll get a fail here oh let's actually go back and um comment this one out for a moment and then you can see expected pattern it'll tell you that the pattern that it expected and then what you got back it can't give you um you know as much nice highlighting because there's a bunch of different variations that could match this but just to show you that that is a really common way to get the general meaning of what your test is supposed to do is to use regular expression matches and i usually use case and sensitivity it depends on you know what your use case is you don't have to do that of course okay so cool now we've got 2b to match those are some quick ones that i would typically use in this situation so a quick note for you following along here let's say that you start writing this statement now and when you're doing this you don't get what i'm getting here this intellisense or helper text here that will auto complete what you're typing as you type it out or list out all of the possible matches and all that stuff so i had this uh once and what i actually did was let me show you i installed the at types jest package to get the typescript types for it and that fixed it for me what's really interesting is even though i installed it just locally in one project it has seemed to carry over to some of my other projects and i'm not sure why that is exactly i'll just do that real quick just so that you can see um but you know that that worked for me and then that made auto completion just start working so just so you know now i'll give you one one more quick matcher here just so you can see a little bit different than just checking for equality here you can also do stuff like let's say we have an array here that our thing returns and it has an a a b a c something boring and then what we can do is we can say two contain this is a really useful one and you can just check for a single property in that so it'll test that so does this contain an x per se no it does not expected the value x received the array abc so it's really nice and so here this is a another way where you can just check like partial uh you know maybe you you give it uh some sort of object or array and then afterward you expect it to just return back something that at least has one of those things so that's a way that you can just kind of test for just partial functionality or partial properties or something like that okay so now at this point let me show you a little bit more usual way to handle this what we're going to do is we'll close this down we're going to package json and i'm going to add this test script so that it usually comes with one so you can just update this and you just simply need to run jest and so that will make it to where instead of running npx jest or whatever we can run npm run test and then it will run our tests pretty cool right and what we can also do just as a shortcut just so you know as you can if you're using npm you can do mpmt i don't believe yarn has that one unfortunately but you can just run your arm test so now what i'll do is i'll also get knit just to show that so now we've initialized this and of course this is mad because we have a ton of changes so let's make a new file we'll make a git ignore real quick and add node modules to that git ignore so now we have git setup please go away and when we now run npm t we can use the dash dash a little argument here to append more arguments to our npm scripts and the dash dash watch so that is going to be the same you know as if we were typing npx jess dash watch in this case if you're using yarn you don't have to append that extra dash dash just so you know so mpmt watch and you could also make a script for this but we'll see if that works and you can see that it now works and what's cool about this there's an extra little uh command here that you don't get with watch all that's press a to run all tests and i use this a lot that's why i'm mentioning it because sometimes i feel like git can kind of or it can make some mistakes when it's reading git and not read all the files uh that it should be or not test all the files that it should be and so i'll press a just to like give myself a sanity check like hey run all the tests again i want to make sure that they all work now that you have the gist of jest let's go over coverage because that is really cool and something that i love a lot about jest so if you do npm t just for your you know just command and then you can pass it a dash dash coverage flag and what that will do this is kind of an ugly format when it's too small let's make that more normal here rerun that just so you can see it okay so now you have this table laid out that's just because my zoom is high for recording typically that won't be an issue for you so when we run this you can see that it gives us this overall coverage of all of our test files and what that means is it runs each of the files and notices it'll tell you the file itself not the test the wolf.js file where the function comes from and it's going to say 75 of statements are tested 50 of branches which is like conditional logic uh you know if statements and tern areas and such like that and then 100 of functions so we've test there's only one function we've tested that one so it's 100 and then how many lines of code well that ends up being the same as statements in this case and then it tells you the uncovered lines which is really cool now this is something that's really exciting to me and it really leveled me up when i figured out how to utilize this so let me show you if you go here now there will be a coverage folder in your directory that's been created you could open that you can go to this l cover port and what you're looking for is the index.html here now i'm going to do reveal and explorer just to open it however you want to get to it on your file system that's fine so i'll open this up and you'll see here let me pump that up for you real quick that should be good so you see here that it's kind of the same information but it's done it in this nice little graphical way for us it gives us this bar of this file to show all of the same stats that we saw before a little bit extra actually so when we click this it will take us to the code for that file and it's really nice it'll tell you how many times each of these lines were run and in this case this red line is saying this is the part that is uncovered if we hover over this eye it's really small unfortunately but it says if path not taken and so this is using istanbul under the hood if you're familiar with that at all it's really cool and what it's telling you is that this condition right here you're not testing this you are testing that your function runs and you've tested all this other stuff the module.exports is just because you imported it but this was never tested you remember that we wrote a test uh before where we passed it nothing and that worked so let's try that out again so now let's say we're going to write a new test and here we'll say should return and i'm actually going to make it do null so so we get something here but i'll set that up first should return null when given when not given a string so we'll do a function this time i'll just do an arrow function just to mix it up a little bit so we'll do the same thing we'll say const result because i want to store it here equals woof calling it and then we're going to do oh we're calling it nothing that's right and let's just do that let's not even write an expect statement uh right now so we can go back over to our terminal we can run our coverage command again and you'll see you can just see from here that it passes so you don't have to open it but if you want a little bit of extra information let's go back to here this is all updated now you can just refresh once you've opened it once it's really neat i kind of wish i had a sort of server or an auto open i tried to look that up but i couldn't find anything like that if anyone knows of anything that allows it to do that that'd be pretty sweet you can append like an open command but it's not universal across the operating systems unfortunately so i didn't go down that route you might write your own but i wish there was a more standard way to do that anyways rant aside now we can see that all of our code it's not it's not highlighted red we don't have any notifications or anything like that and it shows that this has been run one time and this is see how this has been bumped up to two because we've hit this actual statement twice now because we have two different tests that's pretty cool so now we can move uh back to our code and then do our test as usual so we probably want to do in this case expect the result and then 2 be null this is one that you'll commonly do a not for like not to be null uh because you wanna make sure that it doesn't or whatever and in this case that's what i'm gonna do because uh i'm going to show that it will fail right now so we can use coverage to test that notice you'll still get the failures when you run coverage now why would you run coverage all the time it actually takes a lot longer i think the documentation says that it can increase it twofold for how long it takes because it has to build all the coverage stuff and so you wouldn't want to run this all the time you probably run this in your continuous integration pipeline if you're doing that that's what i do and it's really nice for just doing some coverage checks real quick but just so you know uh you could do that or you can just do mpmt like you normally would and you'll see that this test is failing so i just wanted to show that that as the coverage report also will print out failed tests and that the whole thing will return a failure code so here you can see it expected it to be null when not given a string and it received undefined okay so let's fix that real quick go back over to here and we'll just do this null and let's say yeah that's that's actually what i wanted for whatever reason i i don't want it to just be whatever i want to specifically be null test that boom we're passing again and just to make sure that's our coverage awesome so now we have that covered now because this comes up so much i'm going to cover this here though it can get pretty deep so i'm only going to briefly dive into it i want to show that in in a lot of situations you actually would just want to throw here in your code let's say that's what you want and and you just want to say must be a string you know you probably want to write a better message than that but in that case let's go back to here or run t and let me do the side by side again and then let's start our watcher back up and if you're doing this a lot you might want to make a little script for that just a reminder okay so now we get the error printed out and i want to show how you do this because it's a little bit different than the normal expectation object matcher paradigm here so this time we don't want to be null what we can actually do for this i'll just do it all in one we can say expect and then you want to wrap this in a function and call it's a little bit weird and then now we can say to throw and you could check for a specific error as well i'm just showing that that passes right now but you could actually say to throw well did it would it throw wolf no that shouldn't work right received message must be a string so we could check that can we just pass let's try a lowercase one just to make sure nope must there you go so you can see that you don't actually have to put the whole error you might just want maybe you wanted like something printed out an id or part of a message or something like that you just want to be like okay it should throw roughly this error essentially you can play around with that now coming back to this this is a little bit weird you have to wrap this in a function here and the reason for that is that it needs to capture it inside that function otherwise you remember how we when we did just a straight up throw error here before well that's what's going to happen it's going to throw that error and it's going to fail the test and so you can think of this as putting it inside a function here will allow this expect to capture this and then you can just check whether that threw inside there and then we'll come back here and just you know you could do your coverage again and everything is going to be that is very unfortunate that that's so hard to read okay so now you can see our statements are only 80 here and so let's go back to this and refresh and you'll see now we have this return null remember because we didn't we can't return anything when we throw an error so this is pretty cool just kind of showing you that you might leave some dead code here that isn't tested for and so it'll catch more than just errors it'll catch kind of just little mistakes and stuff like that not necessarily things that just you know fail when you run it so let's quickly go over get rid of that and then we'll be good to go now i don't run coverage all the time this is typically something that you run in your continuous integration suite or you know every so often when you push up or something like that it's just a good general check to do especially when you're writing a bunch of tests now there's because there is some really cool stuff that you can do there i'll probably do a whole video on coverage in general because there's a lot to cover there so let's move on because uh there is some other cool stuff that we want to get to now okay so back to running our our test suite here let's say that we know that we want to write another test but we don't have the time right now this is a really neat thing that we can do we can write test and then dot to do and with that we could say maybe we're going to test for um should not allow numbers to be passed or something like that you know what whatever that ends up being that you think about and you'll get this it'll it'll pass everything like normal but you'll get this little uh it's supposed to be a pencil i think this should to do should not allow numbers to be passed and that is really really neat this is a little bit better to me personally than writing comments saying write a test for this or write a test for that because it does actually get print out printed out in your test suite when it runs and you can see it actually right here in this nice little format i think that's just a cool little functionality that they added okay so what else can you do here just give you a couple extras little fun ones let's say that we uh we ran wolf like this and we know that it fails our test and currently we're dealing with this thing where we've got maybe you know five or six or so tests in this file and we don't want to run this test for the time being but it's really long we don't want to comment it out for whatever reason you can really quickly just write dot skip here and you'll see that it draws that little circle around it and shows that this is skipped and reports that it was skipped just so that someone doesn't accidentally leave that when someone tests it in the future that's a really nice little quick way to skip a test what you can also do is let's say that you had multiple failing okay so we have two of these i know i don't really need to do this but uh you know you've got a bunch of tests that are failing and skipping it isn't enough you're just trying to get to a passing state and maybe you're trying to test the functionality of just one test well let me show you let's say you've got that you can do dot only here on the end of this one and it'll only run that to see how it just automatically added skip to every other one and so that's that's really useful just so you know this only does it per file so it's it's going to do that for here but if we had other tests for different files and stuff like that those are going to be run well let's show an example of that real quick so i'm going to really quickly make a mu.js and then what i'll do actually let me show you this this is interesting so i will make a view.test.js and then in that i'm going to make it you shouldn't mix and match these normally i'm just showing that you can uh so i'll make it does the mu and then that takes a function et cetera et cetera okay so you'll see uh that it automatically picked that file up and runs that test now let's do this really quickly i have a reason for what i'm doing here bear with me uh i'm gonna throw an error okay whatever i don't care now it's going to throw that error and i want to show that if we were trying to get around that error in our wolf tests here let me do this if we're trying to throw an error to get around that that test i only want to do test out only well you can see that i left that there and it's not working it's still failing and it's still printing out only the failed one because by default just it's gonna you know put emphasis on what's failing that kind of sucks okay so what we could do here is we can use some watch usage we're finally getting to this we press w to show it and then you can press a to run all the tests again et cetera et cetera but now we can do the filter let's see right here press p to filter by file name regex or uh you can press t to filter by a test name so in this case let's say we want to do a test so i'm gonna do a test and then we have this test that shows should return the number of wolves and it's actually the only one that has whoops in it so maybe let's do that press whoops enter and look at that so now it doesn't show those failing tests if you press w here you'll see that it's checking for this this regular expression here whoops and that's your pattern now you can do the same thing with a file you could you could uh press c to clear the filters you'll see it starts failing again and then you can also come back here and then let's say well i don't really care because i have dot only and so what i want to do is i just want to press p to check for files and then uh the file itself well that is the woof file and there you go now you get all of the tests in that file and it'll stop failing on your mu dot js there this is really really handy now the reason i made that extra file was because i want to show you and enlarge again that's annoying when i do coverage coverage that notice that the mu is not in here okay it's only checking wolf.js currently and the reason why it only has this lower coverage is because we are only testing that one test we've skipped all the other tests that actually would make this coverage complete let me let me show that again so let's get rid of that just real quick just so you can see and we'll run coverage again and there you go so our wolf's great but we're not even tracking mu and that's kind of interesting because it does fail where is that here it is failing this test here interestingly so why that is is because we aren't ever importing it so by default the coverage report is only going to show uh well we don't even have anything in this file right so let's let's just say uh uh const mu equals some string you know this is pointless of course module dot exports mu show that again uh you could see that only wolf is there and if we go over to here we go back we'll only see that one file and then now we'll say const mu equals require and then dot slash mu now as soon as we import that let's see if it does anything look at that it automatically popped up and said that it's 100 covered because it's just a simple string that was imported and so that's what it does now if we are really quickly to change it to a function instead so let's say that it's a function instead that returns that we'll run this report again we'll see that it's not covered now zero functions because we never called it okay so that's that's the gist of how that works when you are without any configuration that's important because there is a just.config that you can set up for this it's going to only run the coverage report on the things that you import into your tests and actually have but you can set it up to check for let's say the whole source directory you can set specific ones folders not to look into and to look into and i'll probably go over that in the coverage video that i'm planning on doing but it's a little bit much to get into right now but just know that that's the case so you could you do a really cool thing where um you know you check that all of the javascript files in your source are covered in some way in your tests if you want to and a common question that comes up there that i'll answer right here quickly and then we'll move on is how much coverage should you have because you might look at these numbers and be like what does this even mean you know what what should it be you might not know there's no hard and fast rule for that uh you will typically see in my experience with other languages trying to aim for like an eighty percentage threshold that's just really generic and it varies by project just so you know uh in just setups that i've seen uh you typically want a little closer to 90 to 100 depending on your project because uh probably due to snapshots another another functionality that just gives you uh to cover things a little bit more easily so just so that you know you're you're trying to get it it's a goal to get as high as you can but there are diminishing returns and you typically don't go for 100 percent i know some people will strongly debate against that and it really depends on your project but just so you know it's just the more tests you have uh you know the more comfortable you can be that your code is working correctly but don't overdo it to the point where you have to test every single little thing possible because there's sort of a diminishing return there you can just do some reasonable default checks and be fine don't let that be a barrier to you getting into testing is what i'm trying to say you can add those things as you go and the best thing about starting with coverage now and adding tests as you go is that once you have like the basic building blocks you can see as things are starting to get out of control and then you can use that as a mental reminder so you could see that mew or wolf ends up getting to like 30 statements uh covered after a certain amount of time and that's a good flag for you to just be like i should probably write some more tests because we're getting a little bit crazy here it's kind of a hot topic so i'm going to leave it at that all right well let's wrap this up by going over snapshots which is a really cool functionality of jest to showcase snapshots i'm going to reference some code that's a little bit more involved that i used in my get bisect video let me show you how this works real quick when i run start start command all it does is it simply prints out this invoice and you don't really need to know a lot about how the code works for this example all it is is that it runs a series of different functions and then it ends up printing out the sort of invoice statement this is actually taken from martin fowler's refactoring book now i really should test all the individual functions there but i'm going to show one of the cool things about snapshots is how you can really quickly get a test up and running that shows you the difference between outputs when you run tests let me show you that so if we do expect and we do first invoice here we can do to match snapshot now when we run that we'll run npm t and you can see it says one snapshot written and if we take a look over here there's this new snapshots directory and if we look into it it's pretty interesting is that we have the essentially the exact same output here printed out for this export so how's that useful well if we go over to the invoice printer i want to show the mistake that i showed in that example there was you know while we're refactoring our code we moved into a new function we accidentally left off that minus 30 and we didn't need now i want to show this first is that you know if you're doing mpm start and you run this especially if you're you're doing a lot of changes or it's been a long day or whatever and you're kind of brain fatigued it's very easy to miss the differences between these outputs between these outputs here so you like as you're comparing them 137 credits oh 47 credits so this kind of 47 to 137 got messed up there but the rest seems to be okay right so come back to our our test here what if we just run mpmt again boom look at that so it immediately went and and checked our snapshot it printed out in a different formatted color now which is pretty cool and then it highlights the difference so you know the rest of this was all the same but here uh it automatically tested this for us based on the output we didn't have to individually run each of those functions now you got to be real careful here i have to start with a disclaimer because this is a really hot topic in the testing community especially javascript here with snapshots and all that that snapshots are not where you should aim to be for all of your tests and by that i mean don't use it to skip testing out individual functionality it is nice to get a test up and running because what it essentially is telling you is that your test does run your code and does return a consistent output based on the previous one but it doesn't necessarily know whether that output is intended or not so in this case we ran this test you can see it said inspect your code changes to run npm u to update them and you can also do this in watch mode let me show you so when you're in this mode there's a u command to update the failing test and so if you're not careful uh you might come in here and you have like a lot of different diffs or something like that and you kind of get overwhelmed once you have a ton of snapshots going on you'll just press u automatically and update it'd be like oh yeah yeah that was what i expected and you won't read each individual line it happens trust me and that's bad because now you have a fail in your code that's not really testable let me show you i just press u and now it just thinks that that's the correct output and we've just moved on and we think that we have passing tests so i just wanted to show up throughout there that there's a little bit of a disclaimer that needs to be said that it can be a little bit dangerous to just you know go willy nilly on all snapshots so this actually to me though is a pretty cool example of how to start with just a real quick test snapshot uh because as you could see from that one before let's change it back it immediately caught this regression is what that's called a you know the code went back in performance or functionality or reliability in some way so i want to update this to say that sorry and then i'll fix this back so let me show you this real quick this is really neat for small code examples like that this is perfect for two match inline snapshot and i really love adding this to some tests you can see that it made uh one snapshot obsolete that's the one that was in this directory here before so it wants us to press u to say yes that is obsolete that's fine and then that those snapshots go away now for that particular instance but now it's printed out here live isn't that crazy so it takes the result and it prints it out as a string and it automatically updates this file so if we were to go over here and we were to change this i'll show you before i save notice it says you earned 47 credits down here we're going to save that flip back on over here and then notice it shows the difference here between the two and then i press u to update and my code automatically updated in the actual test file itself to 137 credits that's pretty crazy so this is really nice to show like a quick documentation of what the output is when the when it's very short or condensed and it's able to do that you wouldn't want to do that for you know a gigantic css file or something like that but for this instance it's actually quite useful so as you can see snapshots are a really quick way to test whether the output of particular functions or anything like that is returning differently or whether you know you want to test that it's consistently outputting the same thing each time and you know i already gave all the disclaimers that you should be careful with how you use those but they're very nice addition to some tests some people really don't like them at all and don't think that they should be existent i've actually found them to be really useful in particular when i have a react component library and some css it can be a flood when you change a component and you have a bunch of test snapshots that fail uh because you change you know one line of css but if you're diligent about that it's a nice thing that can catch things that are really difficult to test otherwise especially when it's just like output css or javascript which you really probably shouldn't be testing that too much anyways but either way let's say you were to change a you know a button and another component uses that button and you forgot about that or that it added a different styling and it overrides that style so it can catch some things like that and i particularly found it to be useful although other people have you know obviously very heated different opinions about that and that's fine i just want to show it to you so that you know that you can use it as long as you know great power great responsibility all that good stuff so that wraps up everything that i wanted to go over for this particular video just basics you know there's there's a lot more to it of course you can never get it all but i think that that gives you a pretty good intro into what just offers a little bit about unit testing and how you use it and some of the different matchers and expectation objects and formats and how you typically use it in an idiomatic way but i do plan on making more just videos where i go a little bit more into configuration and some general setups and then use cases and all that type of stuff for more the functionality of just if you're interested in that so stay tuned for that and of course you can hit me up on twitter if you have any individual requests about jest or anything like that but that'll conclude this video i hope it was useful to you and thanks for watching you
Info
Channel: Swashbuckling with Code
Views: 7,529
Rating: undefined out of 5
Keywords: testing, jest, javascript
Id: __QEPUdnJS0
Channel Id: undefined
Length: 54min 3sec (3243 seconds)
Published: Wed Feb 24 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.