Unit testing Angular with Jest tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey welcome to the first video on my channel I thought as most of us are in lockdown it's probably a good time for me to throw together a quick tutorial on testing with jest in angular sorry in advance for all the car sounds are living right next to a main road and so sorry if there's a bit distracting so today we're going to look at unit testing only with jest we're going to learn how to test basic functions mock dependencies and services mock responses from observables and if we get time we're going to look at how to handle promises as well in jest we're not going to look at how to set up just in an angular project I'm happy to do a video on that so if you want to see it just leave me a comment below and I'll throw together a video so let's jump straight over to our project now now what you'll see is it's a really simple project I've just throwing together to demonstrate these tests we've got the main workers component here from that we've got a child component which is a new worker form we've got a service which is where we get our workers and submit our workers and then we've got some of these utility classes and services one for a loader an error handler and a dialogue so like a pop up give you your successes or your or your errors this is very very typical for most angular projects I use on a day to day basis first off we're going to look at this new worker form component because it's actually quite typical of a lot of components that I look at an angular and we're going to cover quite a lot in here so if we just get familiar with the component itself we've got some dependencies injected which are these utility ones we were looking at before we've got a life cycle hook on in it and the calls a method to set up the main form we've then got a method here to submit the form we've got some functionality here for if it's successfully submitted and we've got a method here that's called when it fails and that method handles and the dialogue or the pop-up telling the user that something's gone wrong so we're going to open our spec file here snap it to the other side of the screen so you can see both it now first thing that we need to do zoom in a little bit here so we can see everything do the same here so first off we need to add a describe now if you're not familiar we describes they're exactly what they sound like they describe all of the code that sits inside them ie the tests so you can nest describes as heavily as you want I nest quite a lot I prefer my tests to be really easy to read through and when you get quite complicated components down the line you're going to want to nest so that at a glance when a test fails you know exactly what method failed so here our first describe that we use needs to describe what all of these tests in this spec file are so we'll give it the name of the component we then need to create a fixture that we're going to test I call this fixture you'll see in other places on blogs and stuff some people call this component or service depending on what they're testing i blank it use the term fixture just to make it very clear when you're looking through my tests this is the class that I am testing so now we need to use it before each before each is once again are exactly what they sound like before each test within this described lock this set of code will run so the first thing that we want to do is we want to create a new instance of our class that we're testing you might ask yourself why aren't we setting this up just once at the beginning of doing our tests and it's because we don't want any of our units that we're testing to impact other units that we are testing we want them all to be standalone that way if we're leveraging one of the great things from just where you can run tests concurrently you don't have to worry about sometimes these tests fail because a variable has been updated to this or that here we've got a red underline that's because it's saying it's expecting three arguments which of these dependencies here so we need to mock these dependencies and I say mock we're not going to be creating instances of them here because we're not testing these dependencies we're testing this class so let's make it very clear that these are mocked take each of these we put each of these in here it doesn't care about what types these are it just cares that a value is passed in here down the line when we're using some of the methods in these dependencies we will actually have to mock them but for now we can just put the empty variables in there now this component is ready to start writing tests so the first set of tests that I like to write are component setup tests now what I would put in these are things that happen in ng and nip also if we have any values that have to be set at the beginning for this component to be created so if let's say for example if this was actually input here we said that if is submitting is not set or passed in we will set to false so I might want to write a test to make sure that this is actually being set to false because down the line I might be relying on that but as this is a very simple component the only thing that we'll be testing in this component setup block is ng on a net still crate here and I do setup component as I say we can nest these as heavily as we want and then inside this setup component we're going to be testing as I say this ng on it take this and put it here this might seem a little bit like overkill but when you've got a really complex common component down the line you're gonna really thank yourself that youyou really nested these so that it's clear to see which tests failed so we write our first it it can't be nested they're not like describes in that way it is one it for one test and we use the it should syntax so if we try to put this into words it should call generate work or form with this dot worker so literally type that it should call this method with this value now the way I like to lay out my tests is with the three days of testing that's a range Act a sir a range being set up my tests Act being run my tests assert being this should happen when I run my tests and so to set this up we need to spy on this and spy is just a term that is used in Jasmin as well and some other testing frameworks is just watching something for a change so in this case we are watching this method let's make it clear that this is a spy we use the gesture keyword spy on we look inside the fixture for this method it's as simple as that we are now we now have a way of looking at things that happen to this method that's are arranged then our act is we need to call this you might think that this is called automatically when this component is instantiated that's actually not true when you're doing unit tests any lifecycle hooks you need to call yourself which is great because it means you can really just test one method you don't have to worry about unchanged being fired and all these other things happening so here we need to go to our fixture dot ng on an end next we do our assertion so we go expect what do we expect we expect this to be cold with you can also use Jasmine's to have been called with you'll notice that a lot of the assertions have cross over and that's because Jess was originally built on jasmine to have been called with and we need to create this variable going to be called with we go here Const worker what is our model here is our model now you'll see me doing this a lot in tests I don't think this is great practice when you're writing typescript itself I think this is actually a bit of a cheating can cause you more trouble than a value actually adds but with tests I don't care what value is passed to my method I just care that when I call on an it a value is passed through to my method I'm gonna give it a few basic things so we both work or one is the ID and give it a name great drummer so what I need to do is I need to go to my fixture I need to set my worker because we need when this is called the worker to be passed through and now there's actually a few ways that we can run our tests here we can go here we can go run tests that will run all the tests inside the describe block and it will do it in this nice little formatted way here I go down here that you can see all of the nests that I was putting in here all of our described blocks here and then it gives us details about the tests that are actually running and you get a nice little tick spot aside this is great if you're running all of your tests once at the end the way that we're gonna be right in our tests I actually prefer to use just - - watch and that will do exactly what it sounds it runs a watcher every time I change this file will rerun these tests I can press a in here and it will run all of the tests in my project or I can leave it in watch a mode and it will just run the tests that have been updated or the tests that have failed it's really really useful it's one of the major benefits of using chest over some of the other testing libraries you can see here that our first test has succeeded just to make sure that it is succeeding and that's not false positive if I put here no this should fail and here it tells us it expected null which is what we told it to expect but it actually received this so if we set us back to worker it's another great thing about just the errors that you get given a very very precise tell you exactly where like what line and how your test is failed so that's our first test and that's actually all of our component setup tests done as I say on a much more complex component there might be a lot more going on there now the next thing if we scroll down here the next test that we want to look at is setting up this form so we do the same thing that we did a minute ago we create a describe inside this describe we're going to give it the method name we pass it a phat error function there so what I'm actually going to do because we're gonna be creating a lot of these gonna be a bit lazy create a load down here this actually just goes to show it doesn't matter how many describes you have on the page if they're empty it will just run through the tests with no worries so here do the same thing we get our method name now we have to look at what the method is trying to do let's move this down here so we can see the whole method so what it's trying to do here is it generating a form if a worker is passed in it we use the values from that worker so if worker and work with that ID it's not the most elegant way of putting this but then use that else generate a random ID and sell them through this so I would say the first two tests that we want to write for this is a test to check that the form is generated with the values passed in and a test to check to see if it is generated with default values if one isn't passed through so using the it should syntax again it should generate form with passed values and then take this with default you'll see me doing this a lot anything that's very very important to the test I tend to do in caps actually don't know why I did it with the fold I'm going to change that I tend to do it with knots or shirts so it's very clear when you're looking at should not do laughs so similar to what we did up here let's take this put this here for the sake of this test though we actually want to pass all the values in so we've got a roll here and we're gonna give it great weight great drummer it's got an ID what else is there and active we're gonna set active - what's a default is set to false and so this is our range we need to we need to set this up and then we need to do act which is fixture dot we want to generate this form we want to pass in our worker now the easiest way to check that forms values is by literally just doing that go get the form value and then we want to use to eat all and actually it's just gonna equal this because the form structure is the same as the worker that we're passing in if we had a slightly more complex form we might have expected result here but we're trying to keep things as simple as possible so this should work if we run these our test to run again I've just saved it our tests are running oh we've got a failed test [Music] so our test has actually found our first problem in our code we've got this check here there's basically saying okay if it's saying if worker and worker active but we're taking a boolean so really this needs to be does not equal no because otherwise it's always going to be true and to accept true here this is our test to just found our first bug in our code here so if I save this again there you go those tests have now passed in my mind our tests have now done their job they found a bug in our code it's worthwhile us writing these tests and so now we want to see we want to do a similar test but we want to see what would happen if we didn't pass initial values so we're going to take a bit of copy and pasting again here we're gonna take this and this is going to be our expected result I'm gonna change this to be our expected result we're gonna pass undefined here because we don't want to pass anything to this method now what are the default values here so if nothing is passed before the name it needs to be null if nothing is part of the role it's an empty array and if nothing is passed for active when you set this to true we're still going to have a failed test here though because we've got this dynamically generated ID and there's no way of knowing what that is going to be in our tests so just has actually got a built-in way to deal with unknowns we use expect any and then all we need to do here is tell it what type of value is so as long as this ID is returning a string we don't care is the rest of the values that are in there that makes them you have to do a lot more complex stuff with that and but in this case we just want it to be a string here and so if I run my tests again I save these and there you go we've got three passed tests here now you can do a lot more complex stuff when you're testing forms we could do some extra tests where we populate a few of these to make sure that it's not valid with required or make sure that it's not value valid when the length is too long for now I'm just gonna move on to the next test because you get you get the point here so if we move down and we take this describe and we put this here and the next tests that we need to write our tests for submitting the work or form this is where things are going to start getting a little bit more complex but you like to see when you start doing it it's actually not as complex as it looks so if we create our initial describe here and that inside we're gonna have quite a few describes now the first thing I can look at here with this method is that if the form is not valid I don't want anything to happen so I like to put describe and hit it saying form not valid and then another one same form valid there might only be one test in this and for not valid but I think it's a lot clearer when we look at it later on so it should what should I do it should not cool let's say that it's not going to call this if don't even need it if because it's right here okay so we've got a few more complicated things to play with here now we need to create a form and make sure it's not valid now we've already done that above so if we take this and put this here we now have a generated form that is not valid because we know that by default it sets this to null and it's required filled so we should be able to we go hit it with a fixture we're calling this method and now we expect there's a bit like what we've done before we expect this to not be called but we actually haven't mocked this yet so we need to go back up to the top of our file here and you remember earlier on I said here that we were going to have the mock some of these so for this one we go here we use another bill in jest feature here so we take this method name from here and then we go jest dot F n now if we click through to F n we'll see here what it does give it returns a mock function so what this is allowing us to do is allow us to any point during our tests to call this dot this and then give it a mock return this go become actually really really handy further down in our tests for now we just want to use this in the same way that we used our spies earlier on if I go worker service mock dot and then we want to go not to be called this test should pass now there we go such as simple as that that's the only test that we need for not valid so now we need to look at valid tests and I would say the first test we need to do is the complete opposite of this test so we copy and paste this in here it should call this now how have we had valid forms in the past if we scroll up and we still this we come back down after here we put this here and we want to pass this in here this is now a valid form now we are going to run into an issue because we've got some up until now we've been dealing with only synchronous behavior we've now got some asynchronous behavior happening and we need this observable because this is return observable that's being ascribed subscribe to although we're not we don't care about what's being returned in this method for our test to finish we need all the things to return so if we take what we did a minute ago just get rid of that if we take this we put it here we go here we can go mop return value we use the shorthand for observable which is of back in the day this would have been creating a new observable and then it doesn't matter what value we pass it because we just want this complete we don't care what finally gets passed through when we use this mock return value it takes something that is asynchronous and actually make sure that it happens straight away in a synchronous fashion so we're saying that as soon as this method is called when it gets to this it will return true straight away which allows our tests to run we've got ourselves a little error here and it's because we've got some more things that now needs to be mocked now it seems I know like a lot of work mocking all these things but you only have to do them once per file and then you're fine so if we go back up to here we need to do the same as what we did just above what is our error tell us it tells us the set load of state so we've got hit set load of state is actually been actually here actually it's being called so if we go to here and we go just dot F again semicolon that's there we go we don't actually need to mock that because it's not returning anything it just needs to be there because otherwise if we look here it's saying it can't get this of undefined because we're mocking that class or that dependency so it can't find that method where it's now it's finding our macht method and it's calling it doesn't care what that method is it's called net and it's fine so what happens here the next thing that happens is is submitting get set to true now this is where we're gonna see a little bit of a shortfall of these tests in libraries and I've never actually found the way of fixing this and if anybody does know anyways that would be great write down in the comments and I'll be eternally grateful but I actually don't know a way of testing that this is set to true and the reason for that is because when this succeeds it's then set to false again so we're gonna skip over this one because the way that if I was really worried about testing this in the real world I could take this pull it out into a method and I could check to have been called which is exactly what we're gonna do with this next one so we're going to test that it should call this with true and then the matter it's going to call it with false because I'm going to check that the first time it calls it it calls it with true so we go it here don't want to talk about zero every time so you go here it should I take this whole dog here with so we need to take most of what we've done up here and put it in here and this is getting a bit gross because we've got lots and lots of duplicated code so this is where before each comes in handy we know that for each of these tests in this block in this form valid block the form must be valid there's no point of us repeating that code over and over and over again so we take everything that makes that form valid take this we plunk it in here and we can now move that up we don't need to duplicate this code because that we know the forms valid already and we can put this here we're gonna keep this mock in here because in a minute we're gonna be depending we're gonna be writing tests that depend on what valid is what value is returned so for now we're gonna keep this here doesn't matter that that slightly cheaper kated we've removed a lot of the duplicated code here so we want to spy on this in the same way that we spoke before we care what it's been called with to have being called we actually want this one and now the first parameter we pass in is when it was called so the first time it was called and the second one is what we want it to be called with so true so we're saying this chance to mock that this gets called firstly with this now we could hear say that the second time is called it's then called with something else false but I don't like to do that I like to have one test with one expect it makes it means there's a lot more tests but it makes it very clear later on what thing broke your test so I think this will already run in the background but we're here this should now succeed so we're now up to six tests now we're getting to actually returning from our observable once again I would put two describes here because there's two outcomes here we can say submission successful and submission so with our successes we need a lot of the same stuff that's already happened in here we know one more thing about our tests now we know that all of them succeed which means we can use another before each and in here we can take what we've done here on out there we can say we can take this here some more copy and pasting we can go expect it or that response so we take our response I returned it from here so now whenever this is called it will route within this block it will return this responses successfully now I need to look at what tests we have in here so there's three tests that I can see the first one is that worker is set the return value so should set this the worker to return the second thing we should do is this should be set to false so let's create another test for this and because this is the final time it happens in this method we can actually check to make sure it happens unlike the one above so shift set is submitting to false and then third and finally very similar to the test we've got here in fact we can just copy and paste this whole test put it here but we want it set to false and we want it the second time it's called and we can get rid of this now notice that I've still left this space here because we have our range act assert it's not really necessary but I like it cuz that glance I can see it see what's happening so first test here we basically want fixture dot submit form we expect that worker gets set to the return value now what we need to be sure of is that worker did not equal that value to start off with so the best way to do this is go fixture dot worker equals undefined we know at this point it's now undefined so what we need to do is check if once this is called so equal and the response is passed in and if I take this make it a global variable it means we won't be repeating ourselves cut so now both of these can use this response into the for each let's save to make sure that works I'll be shocked to finish of course it didn't because this is actually being set to false now so it was a copy and paste there one of the downsides of copy and pasting stuff all the time now the final thing is this should be set to false we do the exact same thing that we did here in fact I'm just going to take this whole test but it's here this is is submitting same thing here should equal false you can also do just while we're on the subject you can do to be false or false see there's lots of things that to be undefined if you won't still be set to undefined I like to be a bit of explicit with stuff here right let's save this there you go that is all of the tests that we need for success and now we're going to jump down in here down to here on the failure now because we are calling a method here this is actually another pretty typical way that I would do my successes and my failures because they tend to be a lot more complex than just setting a worker or or saying is submitting to true or false so here we just want one simple test that is it should call with error so we do this in a very very similar way to above if we had a lot of era state ones here we'd use a before each but we don't we have one so I'm gonna put that straight in here throw that error and we should probably give it an arrow here so if we go error that's create an HDTV era response equals I'm not gonna put all of the arrow stuff in here so we'll do that we'll give it a status of 401 and let's give it a message so in you are not not logged in there you go so we got this error we'll pass it down here we need to now call our methods the same as we do everywhere else call this and then and expect and we expect this to be called so we know from doing our previous test before we need to have a Const here which is a spy equals jest dot spy on fixture we've created our spy here I'm gonna go to be called with and we want it to be called with our error that we've just created here this should pass and there we have it that is all of the tests for our submit working form it's it this is a good amount of tests we're up to ten tests out for a very simple component but I think you'll agree that although there's a lot of tests there we're getting a lot of benefit from there we've already picked up a couple of bugs in my coat and and also they're pretty easy to throw together there's just a lot of copy and pasting I think that's actually where we're going to stop today I was hoping to get onto promises but more where this video is getting quite long but if there is something that you feel like you'd like to see let me know down below and I'm happy to do a separate video on just promises if there's anything you feel I've skipped over a little bit too much I'm happy to do separate videos if you like this video make sure to subscribe like it give me a thumbs up share it with your friends other than that take care everyone and be safe
Info
Channel: TheRyanSmee
Views: 22,444
Rating: undefined out of 5
Keywords: Jest, Angular, Unit testing, Tutorial
Id: PdVerlfmO6M
Channel Id: undefined
Length: 35min 20sec (2120 seconds)
Published: Sat Apr 04 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.