 Hello and welcome to this course. This is not a regular course, this is going to be a practice with TDD, Node, TypeScript, and Jest. And we will focus on the checkout cata. This is a preview on the other courses that we have published. We have three courses. We have first the introduction to TDD in Node and TypeScript. But we see the basic rules of TDD, we start understanding how it works, using some small exercises. Then we have a second course that is building APIs doing TDD in Node and TypeScript, where we build an API starting from inside building our way out. And then we have a third course called building APIs doing outside in TDD in Node and TypeScript, where we recite an open API specification file, and we will start from there building our way inside our system. So this course or this practice is just going to be one simple exercise, where we will practice TDD and we'll practice also object-oriented programming. So the cata that we're going to do in this course is the well-known checkout cata. Here in this cata we need to write a program to implement the checkout system of a store. This program will receive a string that is, as you can see in the example, ABBDBBAC, that represents each one of the items or products that are in the basket, and it will return the total amount to pay. Here you can see that each item has a fixed price, that in case of age 50, B is 30, C is 20, and in D is 15. But the products A and B have some discount. So whatever you get, three As, you get a discount of 20 currency amounts. You pay 130, and if you get two Bs instead of two times 30, you pay 45 only. And here you can see some examples. When we send two As, we pay 100, and when we send all these items, we pay 260, because here we only have one B, but we have three As. And in the other example, we have three As, three Bs, three Cs, and three Ds. And we will apply the discount for A and B that are necessary. So let's try to implement that. Okay, so let's go with the code. We will use this initialization script. What it does is initialize the NPM repo. I'll execute it in the meanwhile, because it takes a while. So it initialize the NPM repo. It creates a source and a test folder. It installs the TypeScript dependency, the Jest, TypeScript Jest, as you know, the Dive for Jest. It creates this TypeScript configuration file with these parameters. Then it also creates the Jest configuration file. And finally, it creates a small test to verify that everything is okay. So let's wait until everything gets installed. As you can see, everything is getting created. Cool, so we have this example test. Let's see if we can run it. We're going to call Jest with the force exit. There's a type here. And everything is okay. This should pass. Okay, cool. So I'm going to create one with the watcher. I need to restart all the time in the test. And we can start, I guess. So I'll run with the watch. First, what I'm going to do is to rename this file and call it checkout. I'm going to come here and rename that. And let's start with the first test. So what I would like to do as the first test looks like it's a good candidate to assess whenever we send nothing. So it should return zero when no items are sent. So whenever we do checkout nothing, we should get a zero. Okay, let's create this as... We don't need to manage any state so far. I'm going to create checkout as a function. This checkout is an item list, but it's a string. And it will return a number. That is the total amount that we have to pay. And I need to return something, return... I'm going to return a rule. So if I come here to the test and I import it. Okay, I have a red test now. That is telling me that... Well, I'm expecting a zero. I'm seeing a rule. So I'm going to do the simplest thing I can do. I'm just returning a zero. And now it should be all green, even though it takes a while. This laptop. Okay, so we have the very first test. Let's move on. Let's start with sending an item. So it should return 50 when sending an A. So if we send an A, it has to return 50. This, if I run it again, has to fail. Okay, now. So I'm going to do the simplest thing. That is, if item list is equal to A, return 50. Otherwise, return zero. Cool. So we got A covered. Let's go for B. Oops, this naming was not okay. So we have to return 30 when we are sending a B. So 30 when sending a B. This test will fail because, yeah, if I run it again, we'll see that better. And we are receiving a zero when we are expecting a B. As it's not anything, it will go through this case. So I'm going to duplicate that and adapt it. So now, if I run them again. Cool, we have another one. Let's go for one more. We have 20. That is when we have a C product or a C item. Yes, we are getting a zero. This is exactly what we wanted. So whenever it's a C, we want to return, okay, that's green. Nice. And the last case or the last item, it's whenever it's D, we are returning a 15. We are running again. Let's return a zero. Okay, so we have a red test. Now let's make it green. So we have this and now it should be green. Cool. So, okay, we have a basic test. Basic implementation. Not much room for factoring so far. So let's create a new behavior. Maybe we can go taking more than one item at a time. So it should return 100 when sending two ways or two days, whatever. Not 100. It's going to be 30. So this is going to be 30 when sending the D to have the proper red test. Okay, so we have a problem here because we take, we assess only one character. So something that we could do is to have a total amount to return. And we will have a four loop to const item. And we will split that for each character. So we'll go one by one. And now instead of returning this value, what we will do is add it here to the total. So total would be that now. And then at the end return the total amount. I need to make a proper before properly. And this is not item list. This is item. Okay, so now it looks like it's working so far. Let's make a new test to return when sending one of each. So we make sure that it works for all the cases. So one of each would be 50 and 30, 80, 100, 115. This would happen when we send ABC. Okay, so yes, apparently everything is correct now. And we can move on with something else. Okay, I see here now a test that we could do is what happens when we send an item that is not here listed. So let's write the test for that. It should, what we want is to throw an error. So it should throw an error when sending a known item. So when we send something, I don't know, was it? It's not, to be, it will throw an error that is called unknown item error. So, okay, here at the bottom, we could have an else clause here in all these cases. And if we arrive to this variant, we'll throw a new error called unknown item. Throwing, okay, because we need to be called to an anonymous function here. Okay, now we got it. We have that here. I see some improvements that we could do and it's get rid of all these magic numbers. So I'm going to extract that into this module, calling it the price went to the same for all of them. So module, this is the price in the module and a price, primes, price, okay. Something else that we could do maybe, and improving that before going to other functionalities is to create a class for each one of the items that we have. And so they store their own price. So let's do that. We have, we could create first an interface or item that is going to be generic interface. And we could get a price that is going to return a number. So now we could create classes for each one of them, implement item. So I need to implement that and instead of throwing this error, return a price and we need to repeat that for all the items. I'm going to use this sophisticated copy and paste method. This is a C and then we have the, finally. We haven't broke anything, but we are not using them. So to use that, we are going to create a factory that so far can be a function only and leaving here we need to item factory. We need to move that into file, but we can do it later. So this is going to return an item that is going to be one of each. And it's going to take as a parameter item, the item chart that is going to be a stream. So, okay, what is going on with that? But we are going to do is that same if similar. We don't need these else words. I think because if item chart it's D, we will return a new instance of that. New D. And we will do the same for each one of the cases. New C, new V anyway. Okay, the same are still not using it. So we haven't break anything, but we will know. So here instead of doing that, what we will do is start using that. We probably need a better name for that. We could use that item chart, name it, and we will have this item that is going to be the item factory return sending the item chart we have. And now what we will do is this operation of adding to the total, whatever amount we have. And in this case it's going to be item get price. And we can get rid of all of this. We don't need it anymore. Nice. It's still green. We haven't break anything. Okay, maybe it's time to move these things out of this file. So it doesn't get that messy. I'm going to create this item. I'm going to move the interface there. Extract also export. And I will have the factory also there. Export. And probably move each one of them into a different file. So D is going to cut that and also that. That will leave inside this file only. But we need to fix this import. A will leave in A and also the A price. And we need to fix this import. The same with B. We have this price. And this implementation with this import can close A. And finally C. Going to do exactly the same. And we will need to fix the imports here. And all the imports here is not detecting it. So I need to do that manually. Maybe it's not the best name for this ABCD import. I need to export that. Probably why it's not recognizing it. Export. Unexport. So now it works. It will restart the test because many changes happen. Usually there are errors. OK. We are still on green after this refactoring. So let's move on. Now we have pending the discount. So to do that of course we will write a new test. So it should apply a discount when having three As. So whenever we have, maybe we can use this line. Whenever we have AAA what we should actually return is 130. And I hope we have an error. It's not the proper error. It's not 130. Now I like more. So let's work with that. Here it's going to be the total calculation here. And I don't want to mess that up. So I'm going to do again this calculation. So what I will do is to have a, probably not even that. I'm going to count how many items we have. A counter that is going to be the item list. And we are going to take only the item that are As. So this is going to be item that it's equal, equal to A. And I don't need to have an array because the filter is returning as an array. I want to get only how many. So we have that. Okay, so now we have the number of As that we have. And we know that every time we have three, we have to apply a 20 in whatever current cities. We have to discount 20, every three. So what I will do is to the total. It's going to be that 20 and for that, it should be... Wait, not like this. Only if there are more than three. To pass this test, I meant. If I try to pass this test, applying this would pass. But we need to make that intelligent. So only whenever we have three As. So if A counter divided by three, what I want to do is to take only the non-decimal part. It's not round. It's another one. I don't remember this. So what we do is, okay, we have three now and we'll divide and take only the non-decimal part. So in this case, it's one and it's okay. But imagine we have a four or a five. This is going to be 1.3, 1.666, whatever. So this is going to take only the non-decimal part. And we will count that as many times as we have this number divided by three. So let's write another test just to verify or let's change this one. So instead of having three As, we're going to have eight, for instance. So we'll have one, two, four, one, two, three, four. And this is going to be two times 130. So it's going to be 260 plus 100, 360. And it passes. So that implementation was okay. This is applied twice. I need to rename this. Twice the discount when having eight As. Cool. So let's do the same for the other discount that we have. The other discount says that we need to apply the... We only need once. The discount when having, I don't know, three Bs. So it says that whenever we have two Bs, we have to charge 45. So we have 15 of this count. So when having two Bs, it's going to be 45 plus 30. And this is 75. And of course it's not because we're not getting this discount applied. So we will do something very similar to that so far to make it green. And it's going to be a factor this. So whenever we have a B, this is not going to be every three. It's going to be every two. And instead of 20 of this count, we're going to have 15 of this count. This is wrong also. Okay. So we have it green. So far we have everything we need. But let's see if we can change that a bit or improve that a bit. What we could do now is to create a discount class. So we can store this and calculate all this discount there. So class, we're going to call it discount. But this would have, we need to identify which kind of item it is. And maybe we need to create an enum first item type. And we'd have a, it's going to be like this B. So create this is item type of item type. We are going to have another one that is this thing. That is the number or quantity of discount that this is type number. And this count that we will apply that is a type number. On this class, what we would have is a method called calculate discount. That is going to return a number. And as a parameter, it would require this item list. And we will have that here inside. So we'll take the number of that. And instead of accumulating here, we have to return that. And now instead of, we have to update that. So this is going to be this item type. If it's equal to that, this is going to be this quantity. And this is going to be this discount. Okay, as we are not using it, we haven't break anything. And now let's try to use it. Let's do it first. Like here, maybe we can start with a. So we can const discount a. So it's a new discount that it takes item type of a. And then it's three, the quantity and the discount is 20. And we will change the total with this discount calculation. And what happens if we remove that? I need to send the item. Item list. Okay, so it looks like it's working. And if we do the same with a B. So instead of calling it B, this is going to be B. This is a two. This is a 15. And. Okay, we have that looks a bit better. I will move that. To item and to export and also move that into a discount class. Or file. Discount.ts. I'm going to export that and come. Oops. So which one is broken now? Not anymore. Let me restart. Okay, so we have this in green. But I would like to refactor this because. It's not something. If we want to add discounts and this someone, we cannot have this hard coded. So for that, I would like to create a class that is going to be called. I don't know store. And we will pass this discounts to this store and then use this in the inside the checkout. So to do that. Let me change that created here class store. And I'm going to receive this discount in the in the constructor. So. This countless. But it's going to be optional. It's going to be a discount list. This is going to leave. Oops. Going to export the class. And it's going to leave. Inside this store class. Yeah, now I need to come here and fix everything. So. Now an empty store. And I need to change all the calls. And now it's green. But this story is not receiving anything. As you could see here. What I would like to do is to move that here outside. And also this. I will need to, of course, import that. And I will inject that. This content. This country. So far, everything is, is okay. Well, no, it should not, but anyway. And what I would like to have now is here a discount. Equals to zero. And go. Or iterate this discount list. And calculate the discount. Of discount list. And this count. It's going to be plus equal. This. I'm sorry. Total discount. And whatever we have on this discount. And here what I have to do is to. Apply. This comes to the final price. So I like more that. Now I have here all this logic. In item I have these other thing. And maybe I can clarify that a bit. An extract that. In a method. Calculate total. That would be this name. And. Also do the same for that. This count. I could even rename that into a discount. Even make it constant. So. This is a better approach to solving this exercise. I like more. The total. Even though it's not probably optimal. Because we go and check this item list. Once. And again and again and again. I think this matches more this. The business. Modulation. So. That's it.