Test Driven Stripe Checkout with Laravel | Arturo Rojas | Skillshare

Playback Speed


  • 0.5x
  • 1x (Normal)
  • 1.25x
  • 1.5x
  • 2x

Test Driven Stripe Checkout with Laravel

teacher avatar Arturo Rojas

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Watch this class and thousands more

Get unlimited access to every class
Taught by industry leaders & working professionals
Topics include illustration, design, photography, and more

Lessons in This Class

18 Lessons (2h 34m)
    • 1. Intro

      0:38
    • 2. 1 Project Setup

      3:30
    • 3. 3 Passing The Test

      26:19
    • 4. 4 Update Cart The Test

      4:00
    • 5. 5 Cart View

      8:42
    • 6. 6 Cart Class

      14:31
    • 7. 7 Purchase Test

      2:55
    • 8. 8 It Can Purchase Products

      8:46
    • 9. 9 Fake Payment Test

      7:57
    • 10. 10 Create Order After Purchase

      6:44
    • 11. 11 Order Products

      9:44
    • 12. 12 Stripe Payment

      10:02
    • 13. 13 Real Charges

      10:54
    • 14. 14 Product List

      12:10
    • 15. 15 Cart Content

      3:27
    • 16. 16 Checkout

      13:50
    • 17. 17 Order Confirmation

      9:37
    • 18. Conclusion

      0:41
  • --
  • Beginner level
  • Intermediate level
  • Advanced level
  • All levels
  • Beg/Int level
  • Int/Adv level

Community Generated

The level is determined by a majority opinion of students who have reviewed this class. The teacher's recommendation is shown until at least 5 student responses are collected.

37

Students

--

Projects

About This Class

Integrating a third party API into your project can be complicated. Even more so if you want to use Test Driven Development. In this course we will examine a simple approach to test your integration with Stripe 

Develop faster and deliver better products

By using Test Driven Development and integration testing, you will feel much more confident about your final product and its interactions with a third party API, knowing that it has been thoroughly tested and it works as intended.

Meet Your Teacher

Teacher Profile Image

Arturo Rojas

Teacher

Class Ratings

Expectations Met?
  • Exceeded!
    0%
  • Yes
    0%
  • Somewhat
    0%
  • Not really
    0%
Reviews Archive

In October 2018, we updated our review system to improve the way we collect feedback. Below are the reviews written before that update.

Why Join Skillshare?

Take award-winning Skillshare Original Classes

Each class has short lessons, hands-on projects

Your membership supports Skillshare teachers

Learn From Anywhere

Take classes on the go with the Skillshare app. Stream or download to watch on the plane, the subway, or wherever you learn best.

Transcripts

1. Intro: hello and welcome to my new course on test driven development. In the next videos, we're going to learn how to create a real application. This is a store with a product list, a simple shopping cart, but most importantly on integration with stripe a P I. For the check out, we're going to do all of this using only tests treatment development, which can be a little complicated. When you are trying to integrate 1/3 party AP I into your project, I'm going to show you a simple approach you can take so that you can make sure that the integration is fully tested. So without any further ado, let's get started. 2. 1 Project Setup: we're going to start by creating a fresh new project. We compose it. So we tied Composer, create project We're going to use prefer distributions. So we get the latest version of level with their stash. Prefer this, then a lot of ill forward slash lateral. And finally, for the name of our project, let's use store. We will be using literal version 5.6, which is the latest version at the time of this recording. This is going to take some time for you to download and install all of the dependencies. So I'm going to pause the video here and come back when it's done. Okay, so the project is now completed and installed. The next thing we need to do is to set up a development website so that we can see our project in the browser. These I have to do outside home step. So I'm going to exit and inside the homes, that folder there is a file called Homestead Dottie Ammo. So let's edit that out and in the sight section, we're going to add another entry, and here we're going to map our application. Your L, which will be store the local and we're going to map that to the application folder specifically the public folder within our project. So that would be home vagrant, code store public. This is a complete path inside homestead. This path may change depending on your set up, save and exit. If we want those changes to take effect, we have to reload our virtual machine. You seen vagrant Reload Best Ash provision. This will reload our return machine and then provisional of the changes which is made. Okay, that it's done. The last thing we need to do is to edit the host file. In my case, I'm using a Mac so that file is located on their forward slash btc forward slash hosts. I'm going to edit that you seem administrative privileges so subtle. Vim forward slash it see for slash host in here we have to add a new line for our application. Earl. Using the home State I p address, I'm using the one by default, which is 192.168 10 10. So let's add a new line here with 12 0.168 10 the 10 and next to it we at the U R L for our application, which is store don't local safe. Next it. So if we have done everything correctly, we should be able to access store that local using our browser. So let's do it. Open up chrome and navigate to store dot local and yeah, we have a working website with the default Lauraville Welcome page in it. So that will be all for setting up our project in the next video, we're going to decide what are we going to test by looking at the project requirements and figure out which will be the easiest steps we can write? 3. 3 Passing The Test: now that we have our best ready, Let's go ahead and run it and see whatever's we get. Let's move to the ketamine. Make sure you are inside the Project folder and run PHP unit. The first error we received is that the class product was not found, so we need to create a model class for the product. We can do this from here using Ph. B. Artisan Make model. Let's call it product with the model class created, Let's run the test again and we still got the same error. But this time is because we haven't important that class in our test. So let's move to the editor and we have to include this class in the U statement. I'm going to do it automatically using my editor. But as you can see, all you have to do is at this line. Use up backslash product. Let's run the test again. Now we get a mass assignment exception on the name field. This is because Larible, by the fault, is going to try to protect models by guarding fields and only white least in those that can be actually passed in the simplest way to solve this is by telling the product model not to guard any fields and just accept everything to do this. Let's hope in the editor again and open the product model class. This class will be located on the store at Folder and inside the class definition. Simply Ari protected Field called Guarded It in Set it to an M theory. Let's run the test again. Now we're getting a database error saying that the base table or view not found referring to homestead, not products. The first problem that I want to fix here is that we're trying to connect to the home state that elevates by the fault. I'd rather use an in memory SQL Light database for the test, mainly because it's very fast and simple to use. Let's go to the editor and open the database configuration files to see how things are set up. The database configuration file is located on the conflict batteries. Here we can see that by default, he's trying to connect to a database defined in the Devi Connection environment, viable or my SQL by default. If we scroll down, we can see that we have the my ask your configuration, which will try to connect to the local my SQL batteries. It is also extracting the database name, user name and password from thes environment variables. But we also have an SQL light configuration up here. So technically we only have to change two things. One will be that of its name to use an in memory database instead of the database. That s Q A light, which is an actual data bits file. And the 2nd 1 is the TV connection value so that it will 0.2 sq a light. Normally, these values are configured in the dot e N v file in your product folder right here. If we open that one, you can see that little already comes configured with a bunch of values here, starting with a D V connection that points to my SQL database host sports and credentials To override these values on Lee For the tests, we can use a file called PHP unit dot XML, also located in your project folder right here. If you open that one up and scroll to the bottom, we already have a few environment virals already set up. For example, the A P P environment is set to testing cash, Driver said Toe array as well as a session driver. And the Q driver is said to sink. Let's add a new entry here. Right below this will be for the Devi connection, which we want to 0.2 sq a life. And finally, let's at one more this time for the D V database and for the value here. We want to use an in memory database. So we use column memory calling mistletoe. Tell me no and run the test again. Notice how it's still complaining about the product stable, not existing. But he's no longer accessing the homestead database. He is now trying to look for the product stable in the in memory databases To fix this, we're going to use that. Always migrations. We're going to create a migration for the product stable. We can do this from here using PHP artisan Make migration. Let's call it, create products stable and finally, let's add a stash. Create equals products. This wheel is scaffold, some of the code for us. Now that the migration has been created, let's run the test again and we still have the same problem. But this time is because We still haven't told our tests to run the migrations for each and every test case to do that. Let's go back to the editor. Let's open our product least test and to instruct lateral to run the migrations. For every test case, we're going to use a trait called Refresh Database, which is already imported up here. So to use it, let's say youth refresh batteries. Let's go back to the terminal and run the test again. Okay, we get a new era. This time, it's telling us that the product stable has no column named name. So now we have to modify the migration and add that color. So let's go back to the editor and our migration files are located inside database full there. And in there there is a Migrations folder, and here we can find a couple of migrations that come already with lateral, but also the create products stable migration, fire. So let's open that one. And as you can see lateral already scaffold, it's some of the code for us. Specifically, the function up is the one that creates the table, and the function down is the one that drops it. Once the test is complete, so we're going to need to add a new column so table this column will be a string column called name Let's Run the Test again and now it's complaining about the Description column . So let's add that one back to the editor. This at a new column this time will be a text column. This will be a long text called description. Run the test again, and finally, it's complaining about the price. So let's add that column as well. This will be an integer column. So table digit cold price, Let's run that test again. Now we get an interesting problem here. Notice how it's telling me that if we scroll up, it's saying failed, asserting that, and then a bunch of HTML and at the end that HTML does not contain the word test product. But if you look up here, the HTML content is telling us that this was actually a 404 error because we were trying to look for a page that does not exist yet. If we want to see this more clearly, let's open the browser in navigate to the products page already have grown open, and we are in the store that local Ural, which is the home page of our project. If we navigate to products, this is the render page we're getting. But how do we get this? Well, lateral by default is going to catch the exceptions in the application and render them as HTML in this case, a 404 exception will be rendered with this message, but this is not good for our tests. What we want in artists is to see the actual exception being thrown out in the terminal. So what we can do for now And this is, by the way, a simple solution is to modify levels, exception handler, and simply re throw the exception before a lot of Ellis able to render that as an HTML page . So in your project folder, there is a folder called up and inside it there is another one called exceptions. Here we find the handler that PHP file This is a class that level uses to handle exceptions . If we scroll down, there is a function called rendered. Here is where lateral will take the exception in Based on that exception will render an HTML page. So before that happens, we're simply going to re throw that exception. And as you can see, that exception is being passed in as a parameter. So we can say Throw exception. In that way we can see the exception in the terminal. Let's does that out. Let's go back to the terminal and run the test again. And, as you can see instead of the HTML page that we get before now, we get the not found http exception. And this is what we want. From this exception, we can tell that there is no products Uriel created, so we need to create one. Let's go back to the editor in your project folder. There is a folder core routes, and inside. We have several files. These are your aerials specific to AP eyes, channels, console applications and Web applications. So we're going to edit web dot PHP and here you can see we already have one route for the welcome page that we get before, which is this one right here. So we need to create a new route for our product list. It's added up here. We say route get because this would be a get request. The u. R l is products. And instead of having an in line function like this one to handle the request, which will be the easiest way to solve the problem, let's try another approach called programming by Wishful Thinking in which will write the code that we wish we had in. Based on the errors from the test, we will add the necessary code to make that that's passed. For example, I'd like this request to be handled in a controller. So as the second parameter, I will pass the controller name, which can be something like Paradox controller, and this should be handled in a method called Index. So at index again, none of this exists, but I'm going to let the test let me know that so that I can go ahead and add unnecessary changes in at the code that I need to make the test passed. So let's go back to the terminal and test again. Looks like we got a new error, so if we scroll up, it's complaining because the products controller class does not exist. We can easily create a controller class using PHP artisan make controller with the name products controller now that the controller is created. This run the test again in its grow up to see the new error, and now it's telling me that the method index does not exist within products controller. So let's go ahead and create that. Let's open the products controller class, which is located inside APP. They see it to be controllers. And inside the class definition, let's create a new public function called Index. Let's run the test again. Now it's telling me that it failed to assert that empty string contains test product. Now, if we continue to program by wishful thinking, Ideally, what I want is to return a view from the index method. So let's do that return view. And I'd like this view to be called something like products dot index, which means that I will have a full medical products, and inside that folder I would have a view called Index. Let's run that test again and see if we get a new ever let's grow up. And as I expected. Now it's complaining that the View products that index was not found, so let's create it. All of our views will restored in resource is find that folder here resource is of youth within views. I'm going to create a new folder called Products and Inside the Products folder. I'm going to create a new PHP file called Index, Not Blade, Not be HB. Okay, now that we have a view found, let's run the test again and we're back to the previous error, where it failed to assert that empty string contains the word test product. So to fix this, let's feel the view with some simple content and later on, we're going to clean that up and add a little bit more style to it. Remember that right now we're only concerned with making this this pass. So let's go back to the editor. And here I have the view open already, So let's create a least of products in our view. Ideally, I'm going to receive a viable something like products which will be a collection of products. And for each one of those, I'd like to display the information of the product. So let's say something like for each products as product and let's close that right away and for each and let's just put everything inside a thief, we, the product name, may be on an H four product name and right below it will say Pitak with the price. So product. And as I mentioned before, I'd like to get the price formatted as currency. If I simply said price, it will give me the price incense. But that's not what I want. So let's program by wishful thinking and pretend we have a function called get price and these get price function will give me the price formatted as a currency. So let's go ahead and run the test again and see whatever's do we get. Let's grow up. And now it's complaining because the products viable does not exist. So let's pass that variable down to our view, from the controller back to the elevator. Let's open the products controller class and to get a least off all of the products, we simply say products equals product. Oh, and now we simply passed down this fireable products to our view, and we call it products. Run the test again. Let's grow up. And now it's telling me that we're calling on on the fine method called get price within the builder class, which can be a little confusing because we were calling the get price on the product class and not on these query builder class. But this basically means that level is going to try and find this get price in the product class. But if he doesn't find it there, he's going to defer to the parent class, which ultimately is the query builder class from which all model classes extend from. So to fix this, what we have to do is to define this method inside the product class. But since we are working with Tess treatment development in mind, what I'd like to do is to create a unit test that will test specifically that function inside my product class, get that test passing and then circle back to our feature test. So let's create a new test using Ph. B. Artisan. Make this. Let's call it product fist in the endless at Dash dash unit. This will tell Lauraville that this is a unit test and will create a file inside tests unit . Okay, are test class is created, so let's go back to the editor and find it inside this unit. Here it is. Then you file. Let's open that one up and again, I'm going to make some changes here, changing these two and annotation a test. And for the name of test, let's call it. It has a formatted price. So what? We need to test this. First of all again, we need a product so product equals product create. And I'm only interested in the price in this case. So price, Let's say again, thin 99 or 1099 cents. The next thing we want to do is to actually call product, get price in store that in a terrible, cold former price. And finally, we're going to say this assert equals the expected value. It's 10 dot night nine and the actual will be product to get price. Whenever you're testing equalities in PHP unit. Always remember to use the expected value or the one that you expect first and then the actual value that when you're comparing second, otherwise you'll get weird errors and on wanted behavior. So let's run these tests on Lee, and I'm going to do that by copying the S name and you know they're me. Now I'm going to say BHP unit, that stash field that equals the method that I want to test and is complaining again about the product stable not being created to fix this. Let's go back to the editor in Let's use that refresh database straight and this again. Now it's complaining because we failed to provide a value to the name field. If you notice from our test, we only provided a value for price, but not for name and description, which makes sense because we are only focusing on the price. The easiest way to avoid that problem will be to pass in the name and the description. But that will make artists a little complicated because we don't know what data is important and what date it's not. So to avoid this problem, we're going to use something called moral factories. You can create model factories easily from the terminal by saying pH. B. Partisan make factory and let's call it product factory. If we go back to the editor, you can find your model factories inside database factories. Here you can find the newly created product factory and also the use of factory, which comes with the latter will by default. Let's open our product factory, and here you can see that it's calling a factory define expecting a model class in the second parameter is an only in function that receives an instance of the Baker class. The way this works is that we simply return an array with the data that we want our product to be created with by default. For example, we want the name toe always be this product. We want the description to be test product description in a price off 10 99. Now, to make use of our newly created factory, let's go back to artist. And instead of calling product create Oh, hold on a second. I forgot to change the model class. Go back to our model and you have to change these and replace it with the actual model class you want your factory four in this case will be product. Okay, now back to the test. And as I was saying, instead of calling product create, we simply called Factory Pass down. The name of the class in this case is product product class and then call create. If we call it like this is going to create an instance over product class and then persisted to the database, we can also pass an array of data into the create method to override the default information for the model factory, for example, we could at a different price off 15 99 or maybe change the name of the product to some other names. But in this case, I only want to highlight that the price of the product he's actually in 99 in That is what we expect but formatted as a currency down here. So with all of those changes does go and run the testicle, and now it's complaining again because the get price method does not exist. So let's go ahead and add that method to the product class back to the editor and let's open the product class and at a new public function called Get Price, run the test again. And now we get a different ever failed, asserting that no much is expected 10 99. So now is the time toe actually implement. They get price function. So let's go back to L. A tour in here. Inside get price. What we want is to call number format on this price, and since the price is incense, we want to divide that by 100 and for the number of decimals, we want a two decimal point. And of course we want to return this and yeah, that looks good. It's run the test again and we get green. Excellent. Now let's go back to our feature test. I'm going to go back to the editor, open the product least test, and I'm going to copy the method name to filter by that one on Lee. Back to tear Amina, BHP unit Dash Dash Fielder equals it can display the product list. Run that and we get green as well. Now let's run everything. We just BHP unit and we get green as well. So notice that by creating a unity is and making that unit test passed, we also made the feature test pass. The last thing I want to do before we go is something that has been bugging me because we only created to test glasses. But somehow we have four desk classes here. That is because level comes with two example test classes by the foot, so let's get rid of those right away. Go back to the editor and if you can see we have one example test here in the U noticed in another one inside feature folder, so I'm going to select both in Delete them. Now let's go back to terminal and make sure I didn't break anything by running all of the tests and we're still green. But now we only have two tests in three assertions, and the last thing I want to fix is that after watching this video, I realized that I made the assignment for formatted price, but I ended up not using it. I went directly to the get price and using the result of that for the assertion, you will get exactly the same result. So it all comes down to personal preference. If you prefer to have it in a separate viral, can just simply replace this with former Price. And if you run the test again, let's run everything you'll see that you still get green in. Everything is the same, but personally, I'm going to live it as it was by accident, because it kind of makes the test shorter and easier to read again. This is personal preference, and if you want to have a separate viable, it makes no difference. You'll still get the same result in the test and you'll still get green. So that will be all for decision. We're going to take a break here and in the next video, we're going to write test for adding products toe our shopping cart. 4. 4 Update Cart The Test: let's start working on the test toe at products to the shopping car. The first thing we need is a test. So let's create one using Ph. B. Artisan. Make this and let's call it update card test. The reason I want to call it this way is because basically, every time we add a product to the card, we are essentially updating its contents. Now let's move to the editor and start writing our test. I'm going to open of the card test, make the same modification again, the annotation at fist And for the name of the test, let's call it. It can update card content. Let's remove this line from here in. Let's start thinking about what we need to test this. First, we're going to need a product so product equals factory product class. Create now for the action part. What I would like to do is send a food request to a certain neural past the product I D and have that product added to the car. So something like this put in for the Eurail. Maybe something like CART and its buys the product ideas a parameter so product Heidi and let's store the response like this now from the response, I want to assert a couple of things. Once I've added the product to the card, I would expect to be redirected to the card view where I can see the contents of the shopping cart. So to make sure that we are actually redirected, weaken, Say response, assert, redirect. And in here we put the UL. We are expected to be redirected, which should be something like cart. The second thing I'd like to test is there. Once this operation is completed, I should have a shopping cart available indecision so we can say something like response assert session has and pass a key off, maybe cart. That will be the key that we're going to use to store the shopping cart in the session. Finally, the last thing I want to make sure is that once I've added a product to the card, I should be able to see that product when I get to the card content. So here we are already testing that we're going to be redirected to the card content. Now let's make sure that once we visit the cart contents, we are able to see the product information we just added for these. I'm going to call this get in past the Ural cart, and from here I can say a certain see product name. And also, I should be able to see not only the product name for the product price formatted as a currency. So a search See product, get price. And there is one last piece of information I'd like to see when I get to the car contents. And that is a total amount that I have to pay based on the items in the cart. And that seems to be something associated with a cart itself. So maybe we can say something like a certain scene cart total price. But this card, whether we get in this card from, well, we already tested that thesis card should be in the session. So maybe right after that assertion, we can say something like card equals two session cart. So to sum up, we create a product up here. Then we send that product in a put request to the card in past the product. I d to that. Your L Once that is completed, two things should happen. I should be redirected to the cart content and there should be a card available in the session. Then I retreat that car from the session using session cart V. C. D. Card contents view and assert that I can see the product name price and also the car total price. I believe the test is looking good for now. So in the next video, we're going to run it and see what errors do we get. 5. 5 Cart View: in the last video, we finish writing our test for adding products to the shopping cart. So now let's run it and see what errors do we get. I'm gonna copy the function name and then moved to the terminal in Run PHP unit That's stashed, filter equals and based. It's saying that the products table is not created because we didn't tell the test to run their migrations. So let's go back to the editor and include that use refresh database. Run the test again. Now we're getting a not found http exception, which means that we need to create a route in this case. We need to create a route for this put request. So let's open routes. Webb, Ph. B. And down here, let's add a new route. Put you rail will be card and then we need to receive a parameter. We're going to use implicit model binding for this. So maybe something like product and this should be handled in a controller called maybe card controller at update, because again we're essentially updating the contents of the car by passing in a new product. Run the test again In the new error class, car controller doesn't exist. So let's create that Ph. B Artisan May controller card control it in Run this again. Sorry, run through this again and it's see what's the new error. The update method doesn't exist in car controllers, so let's add it. But to the editor in this open car controller at a new public function called and guess again. And now it's telling me that the response Status Co. 200 is not a redirect status, which means that once we get to the update route, it's not actually redirect me back to the card index as we expect. So it saw this. Let's go back to the editor and in the other admitted simply return redirect. And here we want to go to card. Always remember that you are just trying to resolve the current error in the test and not anything else. So let's test again, and now we're missing the car key in the session. Now let's go back to the editor and think how we can sell that. Ideally, what I would like is to have a card class so something like carte equals new car. And finally, when everything is done, I would like to put that car into the session with something like session put car and then simply pass the instance of that car, and that should do it. So let's run the test again with these changes and see what new Evers we get. Now it's telling me that the CART classes not found, so let's create one real quick. A quick tip is that you can create a class using PHP artisan make model, which would create a model class for you. But then you can modify it and just make it a simple class. So in this case, the class will be card. Let's go back to the later opened a new car class and simply remove these extends from here . It'll be a simple class and run the test again in the new error is no, actually the same ever. But this time it's because we need to import this class in the controller. So open the car controller and let's import this class, use up cart and run the test again, and we get another not found http exception. But this time is for the second route that we're trying to access in our test, which will be the CART route. So let's add that one right away. Open the routes web dot PHP. File again in this at another route, this time for get request for Yeah, this should be handled in the CART controller on the index method. Okay, rounded us again. I suppose, is telling me that the index method doesn't exist and that's correct. So let's go ahead and add it. Go back to the car controller, had another public function called Index and run the test again. Now it's saying failed, asserting that empty string contains this product. That means that when we get to the car content were not able to see the product we just added to the car. So first of all, from the index method, I'd like to return a view. So turn View Card index in its run the test again to get a new error, Which will be that the view is not found. That's correct. So back to the editor and it's created inside resources Views is creating you folder here Gold card and inside that folder has created new PHP file Cold Index not played that PHP run the test again and we get the same error as before fail, asserting that empty string contains best product. Now we need to add some content to the view to display the least of products present in the shopping cart. So, ideally, we should have items in the card so we could say something like for each card items breath item and it's closed that right away? No, for simplicity sake, let's just had a thief, maybe class role and in here can have another thief with a classical MD, maybe four. And maybe we can have the product name inside an H four. Maybe. And the way this is going to work is that each item will have the product. We add it to the cart. Something like item product Name saying for price, maybe at another dif This will be maybe another four columns wide, So call Mt. Four if having age six and he we're going to have a price. So Itim product price and actually we want price formatted as currency. So get price. With these changes, let's go back and test again, and now it's telling me that the card variable is undefined in the view, so let's pass that down go back to the editor, open the car controller, and we can use the same nine. From here. We can create a new card index method and then pass it down to the view as a car. Okay, let's go back in. Test again. Let's grow up Now. It's telling me that the card has no items property to find. So let's go back to the editor in at that property to the car class inside the class, if initial, we can have maybe a public items, that's this again. And it's telling me that we have an invalid argument supplied for for each. So that means that the items variable is not an array, so we can't use it inside a four reach statement. A quick fix for that will be to initialize is as an empty array. This test again and we're back to the same error fail, asserting that empty string contains that's product, which makes sense because the items property is empty now, ideally, in the controller, I would receive the product as a parameter here, so, product remember that we're using implicit model binding, so a lot of it is going to fetch that product for us, then I would like to add that product to the card with something like Card, not product, and maybe associate that product with some sort of key. In this case, the easiest thing to do would be to, as a product, I d. As a key itself. So product i d. And the reason I want to do it in separate parameters. It's in case you need to associate a product with a different I d other than the product ready. So with those changes in, let's go back to the terminal in Testicle and now we get an error saying that the ad method off the CART class does not exist. So now we get to point where we actually have to implement the ad method of the card. But we're going to take a pass here and do that in the next video, because I want to drive that functionality on its own unit test for the card itself. So let's take a break and let's continue in the next video 6. 6 Cart Class: in this video, we're going to drive the functionality off card at using a unit test. So first of all, let's go ahead and create a new test from the tear. Amina using Ph. B. Artisan. Make this. Let's call it card Fist and we used Tash Tash unit to let level. No, this is a unit test. Now let's go back to the editor and open the new test, which is located on their tests. Unit Car test. Let's make sure we make the same modifications we need to have the annotation at test. And also let's use the refresh database trait. Now for the name of the test, we can call it something like it can at heightens to the carved. So where we need to test this? Well, first of all, we're going to need a product, so product equals factory product class create. Also, we're going to need an instance of the cart so card equals new cart. Next, we need to call CART at past the new product and then associate that product with some kind of I D. In this case, the product I d will do just fine. So product tidy. Once I have done this. I would expect the items in the car to be exactly one. So we can say something like this. Assert equals one card items. I'm going to be using a collection for the items. That is why I can use the count method on it. Now let's go ahead and run this test and see what errors we get. So I'm gonna copy the function name, move to the terminal and use PHP unit. Dash Dash Fielder equals it can add items to the car and let's see what we get. First error is that the ad method is not find, so let's go ahead and add it back to the editor in open D car class. This at a public function called at. They shouldn't receive the product and a key. Let's run the test again called to a member function count on a raid. If you remember, I initially using array to set a value for the items. Now we have to use a collection. So let's go back to the editor and unfortunately, we cannot call collect from here. We cannot initialize a public field like we did with the array. For that we're going to have to create a constructor. So first of all, let's eliminate this quality here and then create a constructor for this glass. And here we can say this items equals collect and simply pass an empty array to create an empty collection. And actually, I think we can omit the array. Okay, lets test again Now it failed to assert that zero much is expected one. Now it's time to actually drive the functionality of the admitted. We need to add that product to the items. So to add a new item to the collection, we can simply say this items and then call the foot method which will take a key which was best in and also the value will be the actual product. But using it this way is going to cause issues with card view. Let me show you free Open card index. We were making the assumption that the items will contend the product, but in this case, the item is the product. So this is going to give me problems, but I'm not going to solve it now. I'm going to continue with the unit tests, make that pass and at some point the test is going to tell me that there is a problem and then I will fix it. So let's go back to the unit test to the car class. Sorry. And with this change, let's go ahead and run the test again. Okay, so that unit test is passing. Now let's go back to the future test. Let's open update card fist and run this test one more time and see if we still have errors . Copy the name back to DeMarino, BHP Unit, That stuff field that based at name in running. Now this may be a confusing it failed, asserting that empty string contains test product. But this is because how we lay down our people, Let's go back to the editor and Open card index. And as you can see, all of the content depends on the card having items. If we were to have, I don't know, maybe Heather here, something like h one card items and if we run the test again, we will see the same ever. But we will have some content in our view, as you can see here. But the main problem is that the card has no items in it. But how can that be if we have a test that it's passing, telling us that we can indeed, at items to the car? Well, the answer is very simple. If we go back to the editor and go back to the Guard controller whenever we make the update , we create a new instance of the cart at the product to it and then put that card in the session. But when we get to the car, content were simply creating a new instance of that car. But look what happens if we instead retrieve the card from the session. So something like card equals session. Yeah, let's run that test again. Now we're getting a completely different error, and this time it's complaining because we're trying to get the property name off a non object. And this is the problem I mentioned before. Let's go back to the editor to show you and open the card index view. We're trying to access these name property, but as I mentioned before, the item doesn't contain the product. The item is the problem. So I saw this simply access the name property directly from the item as well as the price and run the test again. Now it's complaining because we're calling the total price method on card. But that method has not been defined So again, let's drive this functionality using a test back in the editor, let's open car test one more time and let's create a new test down here in it's College. It has a total cracks. So for this test, I'm going to create more than one product. So I can some the prices and have a total price. So let's say products equals two factory product class. And to create more than one instance of this class, we can simply pass a second parameter with the number off instances we want. In this case, three will be enough sindical create. Next, we're going to need a car so card equals new car. Now we need to have the products to the car we can use for each products as product. And for each one of those, we simply call card God pass it product and then key, which will be the same product. No, for the assertion are going to compare with this. Assert equals. Now the expected value will be something like total price, which I'm going to calculate in a moment and the actual will the car total price. So this total price should be some off all of the product prices. To calculate that we can use a method of the collection class called Reduce Like this, we're going to say total price equals two products which is actually a collection. And on that I'm going to call reduce into the reduce method. We're going to pass a callback function that we received the carry value, which is total, and the item of the current iteration, which will be something that brother and this function will simply return the carry value total plus the product price. So a little bit of explanation. The reduce function is going to reiterate over every item of the products collection, and he's going to pass that item to the function in the second parameter, and the Kerry value is going to increment on every iteration. So, for example, if we had a collection of three products in each of those products has a price of $10 in the first iteration total will be cereal. Then we would return zero plus 10 which is actually then in the next iteration, the total, which is a carry value, will be 10. So we'll return 10 plus 10 that's 20. And then, in the final generation of this reduced function, total will be 20. So we will end up returning 20 plus 10 so total price will be equal to $30. Okay, with that out of the way, let's copy this function name and let's run the test to see the errors that we get. Copy that. Go back to the terminal PHP unit. That's touch Field based on in Right, a suspected We are calling the total price method, which hasn't been to find yet. So let's go ahead and at it in the card class. Let's add a new public function called total price test again. No, it's telling me failed, asserting that no matches expected 32 97 in this number may be a little confusing. So to make things a little bit easier to understand, let's go back to the test and clean that up a little. Back to go artist. Let's create those three products with a price of $10 so price $10 will be 1000 sets Let's run the test again in Yeah, that's a little bit more straightforward, but I'm actually expecting this in a currency format. Solis fixed back to test, and actually, now that I think about it, I don't think we're going to need to do this calculation here. To make things a little bit more easy, we can simply replace total price with something like 30.0 But I'm not going to remove this just yet because I had the feeling I'm going to be using that in the actual implementation off total price. So for now, let's just come in that out. Let's run the test one more time. So, yeah, that's a much better error. Failed a 13 new matches, $30. Now let's implement the total price method. I'm going to copy this. Actually, I'm going to cut it and then moved to the car class and based it inside the implementation thought of Price. And instead of using products I'm going to use, this heightens in just to stay consistent with the naming convention. I'm going to rename product to heighten. Now we just have to form a total price, so we're going to return number format. Total price divided by 100. And we're going to at two decimal points. Run to test again, and now we get green. Perfect. Now let's go back to the future test, which I believe waas. It can update the card content. Let's run that and we get green as well. Now this is good, but there are a couple of things that I would like to change before we in this video. If we go back to the editor and opened the card controller, I really don't like to be pulling the cart from decision and then putting it back every time I'm doing something with it. I'd rather have the card do that for me and take care of putting itself into the session and then recreate itself from the session. So to do that, let's remove this from here first. Let's on comment this line, and whenever I do a new card, I like the car to recreate itself from the station without having to expressing Lee doing so myself. I think the best place to do that will be in the constructor, so let's go to the cart class then, right after this line we're going to check either station has a card in it. So if session Haas car in this case we're going toe overwrite the items of the card with the ones in the session. So this items equals session items. Now, with that re factor, let's run all the tests again to see if we broke anything back to tell me now BHP Unit to run everything and we're still getting green accident. That was a good re factor. Now, the last re factor that I'd like to do before we end this video is the fact that I don't want to be having to put the card back in decision after every other again. That's something that the CART class itself should be able to do on its own. So when we take this lying from here and let's add that functionality inside the ad method , So let's open the car class in right after this line, I'm going to say, session put, I'm going to use the key car instead of card. I can say simply this. That means that after we're a product to the items collection, the instance is gonna put itself back in the session So let's go back to the terminal, run everything again and hopefully we'll get green as well. And yes, we do. Excellent. In the next video, we move on to the check out process and also testing the payment system. 7. 7 Purchase Test: in this video, we're going to create test to make sure that we can create successful purchases off the car products. So let's create a new test class you see in PHP. Artisan make dist. Let's call it purchase test going to make the basic modifications again at in the annotation at test and including the refresh database straight for the name of the test. Let's call it, it can purchase products for these days. We're going to need a product so product equals factory product class create to make it simple and going to give this proud of a price of $10. Next, we're going to need a card. A guard equals new car. Now we need to add that product to the card using card at product and faster product I D. As the king. Now, when making a purchase, what we are actually doing is creating a new order. So for the action, I'd like to make a post request. So this post in the Ural can be something like orders, and this is going to receive two parameters. 1st 1 is called stripe email. This is something striped AP eyes consent with the email of the person making purchase This case, we can pass a test value of maybe test at email dot com in the 2nd 1 is called Stay stripe token. This will be provided by stripes AP I Once they have validated the credit card information . Now, for the value off this token, we can take two routes. One will be to actually contact stripes a p I to get a valid token, but I feel that will be too complicated. So we're going to take a much simpler approach. We're going to create a payment class and then use that class to retrieve a talk in for us , which will have a test value so we can say something like payment get test token. So maybe up here we should have an instance of the payment class, like payment equals new fake payment in this fake payment, class is going to act exactly like the rial payment class which we're going to create later . So then we can just swap them out and start using the real one now for the assertion. I can say this assert equals and here I want to make sure that the customer was charged exactly $10 for the product. So the expected value will be something like then the actual value will be the total charge off the payment. So maybe we can say something like payment Total charge. OK, this looks like a very good starting point in an expedient. We're going to run this test and work through the errors to make it past. 8. 8 It Can Purchase Products: Now that we have our test for the purchase products, let's go ahead and run it and see whatever's we get. I'm going to copy the function name so I can filter for that one only copy. Let's move to steady me none. BHP Unit Dash, Dash filter in PE set in It's telling me that the fake payment class does not exist, so let's create. I'm going to create a new class using Ph. B. Artisan Make model fake payment. I misspelled. Make make best make model. Sorry. All right, so we have a new class. So let's go to the Editori. Open it. Let's remove these extends and also this use statement, and that should do it was run the test again. Same error. But we have to import the class in the test. So is that, and it's important that class and again my editor does that automatically. But all you have to do is at this line up here, use up fake payment. This from the test again. Now it's complaining about a get tests token method. So let's add that to the fake payment class. Inside the class definitions this very public function called Get just Tokcan. And here I'm only going to return a test value, maybe something like palette Token. The value itself doesn't matter because we're not going to do any validation on it. Anyway. Let's run the test again. Now it's asking for the route. So at it, open routes with the beach be. Let's add a new route down here for a Bose request to quarters. This should be handled in a controller, maybe something like Gorder school troll if in the store method, because we are creating a new order. Okay, test again. And now it's telling me that the orders comptroller does not exist. So let's create that using PH. B artisan make controller orders. Control it contest again. And sure enough, the next error is about store method missing from the order school troll F. So let's create that one. Open the orders controller class in our republic function called Store in just again. Now we need to have the total charge matter to the fake payment class, so it's open sake payment and create a new public function Gold Total church and you guessed it just again. And now it's saying failed, asserting that no matches expected 10 which means that we get to the point where we actually have to make a charge using the fake Bateman system. So let's think how we're going to achieve this. Let's go back to the controller, the orders controller and in the store method, what I'd like to do is maybe get the card from decision first. And then I would perform a charge use in the payment class something like payment charge, to which I have to pass the total I have to charge. And this total has to be incense, not in a currency for me. So maybe I can get that from the cart saying something like card total, which is different from total price, which gives me the total in a currency for me. I'm assuming this will give me the total incense. And then I passed a token which I can extract from the request using request stripe token. Now, how am I going to get this payment class in here? I could say payment equals fake payment, but then if I wanted to swept to the rial payment class, I'd have to come back here and change the name in the coat So instead, what I'm going to do issues laudable service container to dynamically load the class that I need by associating that class to a contract. So, first of all to the orders controller, I'm going to add a private field called Payment. Then I'm going to add a constructor, which is going to receive an instance of the payment contract. Let's call this payment and then I can simply say this payment equals payment. So basically, level is going to look for a bind between the payment contract in a specific class. And then he's going to instance she ate that class into payment, which I then assigned to my local payment viable. Now that I'm here, I can say this payment charge. So let's run the test again with these changes and see what new Evers we get. Now it's telling me that payment contract class does not exist, so let's create it. I'm going to create that class inside folder cold up and inside app. I'm going to create an folder called Contract. In theory, you could have the class out here, but I like it this way because it makes it a little bit more order So let's create a new class cold payment contract. The name space will be up contracts, and this will be an interface called payment Country. Now this payment contract will have only one method called charge. So public function charge in these charge method will receive total in the token. Okay, let's run the test again. Same error, but now is because we have an important these into the controller. So let's do that. Use up contracts. Payment contact just again. No, we're getting a binding resolution exception saying that target payment contract is not instead instable while building the orders controller. That's because we have, in balance a contract toe an actual class. Let's go back to purchase test. We are going to create a bind between the payment, which is an instance of fake payment and the payment contract. We do this by saying this up instant. The abstract will be the payment contract, so payment, contract, class and instance will be payment. Remember that we have to import this up here. You said use app contracts, payment contract. Now let's try and run the test again. And now it's telling me that the argument one pass to the constructor off the orders. Controller class must implement the payment contract class. To solve this or we have to do is go back to the editor in open fake payment and make this class implements payment contract. But that, of course, is going to force us to also implement the charge method. So we have that function don't here, and we're going to implement it later. This run the test again. Okay, we move past that error and now we are at the point where we have to add the total method to the car class. So let's do that. Hope in cart in at a public function cold total just again. And now it's telling me failed, asserting that no matches expected 10 which means that we are at the point where we have to implement charge method off the fake payment class. But as always, we're going to drive that functionality using a unit test exclusively for the fake pavement class. So let's take a pass here and let's do that in the next video 9. 9 Fake Payment Test: in the last video. We ended with this error fail, asserting that no matches expected. Then, in this lesson, we're going to cover a few thinks. First of all, we're going to solve this problem using a couple of unit tests and then after we have successfully created charge using our fake payment class, we're going to make sure that we can also create a new order. So how do we fix this problem? Let's go back to the editor to our purchase test. As you can see the result from this method, total charge is coming up. No, but we're not going to fix that just yet. The first thing we're going to fix it's actually in the orders. Controller Solis, Open orders. Controller Dennis, you can see here we're using this total method. But this total method has not been implemented yet. If we take a look inside the car class, how can we perform a charge if we don't have a total from the cart? So let's make sure this works as expected, using a unit test, let's open the car test class at a new test known here in this Call it It has a total this is going to be very similar to the previous test. It has a total price with the exception that we're going to compare, not with a currency formatted output, but one incense. So I'm just going to copy this entire test from here and paste it down here and in the assertion, I'm going to remove the quotes and just leave it in 3000 and instead off using total price , I'm going to use Total. So let's run this. Copy the method name move to the terminal. BHP unit Dash, Dash Fielder equals it has a total failed asserting new matches expected 3000. So let's implement that function back to the editor in back to the court class. All we have to do here is returned this same call to the reduce function, but not format it at the end. So we can just copy this line from here, paste it down here and then return the results. And as soon as I get a green coat from the unit test, I'm going to come back to this coat and do some cleaning up because there is a good opportunity here to reduce code repetition. So let's go to tear Amina and test again, and we get green and don't worry about this. It's saying to test to assertions. And that's just because the fielder, as you can see it's trying to filter by any function or any test whose name begins with it has a total which will coincide with it has a total, and also it has a total price. If you want to be a specific, just change the name of this test to something like it has a total. In a sense, go back to their meaning, and when you run it, make sure you include. It has a total incent in the filter. And now we get green, but only in one fist with one assertion. No, As I said before, we are going to do some cleaning up in the CART class and here in total price, we can avoid code repetition by simply removing this entirely. And instead of using total price, we can just say this total. Okay, so let's run the test again. Make sure it's still green and it ISS and let's also run the other one, which is called it has a total price, and we get green as well. Time to go back to our purchase test. So let's run this one again. PHP unit. That's the fielder. It can purchase products, and it's still saying that no does not match the expected then. But now we know that it's not because we're not charging, but because the total charge method is not implemented. So let's create a unit test to make sure that this works as expected, I'm going to create a new test class using PHP Artisan. Make this. Let's call it fake payment. This. And since this is a unit test, let's include the Tash Tash unit at the end. Said the annotation for the test and change the best name too. It has a total charged. So what are we going to need to test this? Percival? We're going to need a payment class, so payment equals new fake payment. Next we call the payment charge mitt payment charge. It's pass a total of maybe $10 and then a test talkin with payment. Get this token. Finally, we can say these assert equals the expected value will be $10 formatted s currency in the actual will be payment total charged. All right, let's run this test. Copy the name Tamina, BHP unit. That's the filter equals. It has a total charged, and we get pretty much the same everywhere as up here. So let's go back to the editor and self that let's open the fake payment class and from the total charge method. Since this is just a fake payment class, we can return something like this total, assuming that this private field will contain the total that was charged. So let's run the test again with just that on the fine property total. So back to the glass. Let's add this total as a private field and test again, and we're back to the same error. But this time we can fix that. But going back to the class and inside the charge definition, we can simply say these total equals total, which basically mean that as soon as we make a charge, we simply said it in this private field in the total charged, well, simply return development. But as I remember correctly, we need this in a number format. So return number format. This total divided by 100 with two decimal points. Okay, lets test again. Then we get green. Excellent. Now again, let's go back to our feature test. It can purchase products, run that one and we get green as well. Run all the tests to make sure that everything is working. Using PHP unit and yes, perfect. We get green all the tests they're passing. So I think this is good enough for the session. And I know I said in the beginning that we were going to cover orders here. But what if instead, we take a break here, and in the next video, we will take care off creating orders after the successful purchase. 10. 10 Create Order After Purchase: in this video, we're going to take care of creating new orders after a successful purchase. So inside the purchase test this very new test case down here, let's call it. It creates orders after purchase. The preparation in action off this test is going to be very similar to the one about, So I'm just going to take all of the code except the assertion. Copy that and paste it here. So we're going to create a new product, add that product to the cart, creating you fake payment and then send a post requests toe orders with the email and the token. So after that, I'm going to try and look for an order that belongs to this email. So I can say something like Order equals orders where e mail equals this at gmail dot com. And then I called first to get first element of that wary. Finally, I can say something like this. Assert not new border. Let's run this test and see what we get. Copy that BHP unit test That's feed it that it grates orders after purchase glass orders not found. So let's create that which is actually a model, so PHP artisan make model order. And actually, I made a mistake because I named it Orders in code. Let me change that real quick instead of orders. Should have called order where All right, make a model intestine. Same error. We have to import that in the test, so use up order and this again. Now it's telling me there is no such stable orders. So we need a migration for this BHP Artisan Make migration. Let's call it, create order stable best ash create orders and with immigration created test again. And now it's saying failed, asserting that no is not know which means that after I make the query here, the result of this is coming out. No. So no order was created to sell that. Let's go back to the controller over. There's controller in Right after this charge, let's create a new order with or their create. You know, let's think about what information we are going to need to create a new order. First of all, we're going to need the email, which is equal to request stripe email, and I think it would be wise to store also the total of the purchase in the order so total equals this payment total. And again, I am assuming these total method will give me the total off the purchase. 18 cents in not formatted as currency. Okay, lets this again. Now it's telling me that the order class was not found, but that is because we forgot to import it in the controller. So let's do that. Use up order. Investigate. No, it's complaining about total method not being implemented. So let's add that real quick. Let's open the fake payment class at any public function called Total Investigate. Now we're getting a mass assignment exception on the email field. So if you recall, this is just because Lauraville is trying to protect the model by white leasing fields that you can actually pass. But to solve this, we're going to tell the model not to guard any fields. So let's open order in addi protected, guarded field equals empty array contest again. Now it's telling me that the table orders has no column named email. So now we need to modify the migration so open, create order, stable migration and in here, less airy new column called email. So table string E mail interest again Now it is complaining about the Total column. So let's add that to the immigration as well. This will be an integer cold total test again. No, it's telling me that the orders total column cannot be no. Which means that we have to implement the total method off the fake payment class. Let's do that with a quick unit test. Let's go back to the editor. Open the fake payment. This class is that a new test known here called it has a total charged incense. I'm going to copy these lines from the previous test. Face them, don't here and in the assertion I'm going to concert equals 1000 against payment total. Let's run This test could be the name BHP unit That stash feel like that. It has a total charged incense failed, asserting that no much is expected. 1000 back to the editor list opened fake payment class and in the total method listers returned this total in this again we get a green and the unit test. Let's go back to the feature test and we get the green as well. This room, everything and everything is green perfect. So now we know that we can create new orders after a successful purchase in the next video , we're going to take care off taking the products from the purchase and associate them with the order as well as showing an order conformation view was the purchase has been made. 11. 11 Order Products: know that we were able to create orders after a successful purchase. It's time to associate all of the products from the cart to the order. I think we can cover these functionality without having to make an additional test for it. Instead, we can put it inside the purchase test. It can create orders after purchase. Well, we have to do is at a new assertion right after this one saying this. 1/3 equals one, and here I'm going to make reference to order there products. And since this is going to be a collection of product, I can say count so that I can make sure that after a successful purchase, the number of products in the order is exactly one. So let's run this test again in see whatever's we get, copy that function. Name back to 10 minutes. BHP unit. That's touch field that it create orders after purchase. It's telling me that it's trying to call the function count on no, which means that this product's field is actually no. To fix this, we're going to create a relationship between order and product. Let's open the order model in at the new public function cold product and in here we returned. This belongs to many, and we pass product class. So what I'm saying here is that the relationship between orders and products, it's a many to many relationship, which means that one order can have multiple products, and one product can also be associated with multiple orders. The way level is going to set up this relationship is by looking for an intermediate table , which is going to hold the primary keys for both products in orders. Now, by the fault on Lee, the primary keys are stored in these intermediate table. But I will also like to have one extra column for the product price. So what I'm going to do is at a price column to the pivot table, and I can do that by calling with Pivot. And here I passed the column name Price. Now, with those changes, I'm going to run the fist again, and I expect Letterman to tell me that the table order product doesn't exist in that is the case. No such stable order product. So what we have to do now is created a new migration for that table. So the HB artisan make migration create or there credit table. The stash create equals order there, product. Let's just again. Now it's telling me that the order product table does not have a column named Order I. D. So let's open the migration in at that color, we need to add a new column. This column will be an unsigned integer called Order I D. Since this is a small project, I am not going to bother creating any foreign keys for this table. So if you don't see me creating any foreign keys, don't worry. It's not a mistake I'm not forgetting is just a conscious decision just to keep things simple. Let's test again. Now it's asking for a product i D column in the order product table going to copy this basted below another unsigned integer, this time called Product I D test again. And finally it's asking for the Price column. So let's add that as well. Table inte jet bright in this again failed, asserting that zero matches expected one. So now we get to the point where we have to actually attach the products to the order. So back to the controller borders control it right after we create the order. We need to attach books to that order. So I'm going to store the new order in a viable called order. And down here I can say something like for each car items as item. Then remember that every item in the cart, it's actually a product. And to attach that product to the order, we can simply say order products at that positive product idea in this case will be item I D. And as a second parameter, we have to pass an array with all of the extra columns in the pivot table. In this case price, this will be equal to heightens price. Let's test again. And now we get green. Now that we have a passing test, I would like to make a small re factor because if we look at the controller, the orders controller, the action of attaching all of the products to the order should be something that the order itself could handle. So instead of having this for each out here, maybe we can have something like order at products into that we can pass the cart items. So I'm going to come in out this part here and try to run the test again. Now it's complaining because the art products method has not been defined. So let's create a unit test for this method, and then we will circle back around to the feature test. So let's creating new unit desk using PHP artisan make pissed or their test that stash unit . And let's open that in. The editor changed these to a annotation test used that of a sweet, fresh Sorry, refresh that of his. The name of the test can be something like you can that products to the order. Since we know that the card items is nothing but a collection of products, we can simply create one ourselves without having to use the car so we can say products equals factory product class. Let's create a few of them. Maybe three create next we need in order, so order equals factory order class create then for the action. We simply call order at products in fancy product collection, and we can say this assert equals three order products Count. Let's run this test. Copy the name move to the terminal. PH. B unit that starts filter equals, peaking at products to the order We don't have a factory for the order class, so let's create one PHP artisan Make factory. Order their factory back to the editor. Let's open the order factory class and remember that this class is located on their database factories. So now we have to do is swap model for quarter. There can define the faults, this case email. You can say something like faker email, which will give us a random email for the order. Let's give it a total off, maybe 10 99. And that should do the trick back to the terminal and testicle. Now it's telling me that the at products method is now defined. So let's add that to the order class at a new public function called at products to which we received the products collection just again failed, asserting that serial matches expected three. So now we have to implement that function, and we can do that by copying the code from the controller. So orders controller it's uncommitted. This cut it from here and paste it inside the at products method. Instead of card items, they can see products, pass product and replace that everywhere. Instead of order. We strike that for this. So we receive a collection of products and we attach every one of them to the order. Let's test again and we get green that circle back to the feature test. It can create orders after purchase and we get green swell, just everything in perfect everything is passing. In the next video, we will create our first integration test, in which we're going to create a really payment class that is going to interact with stripes, a p A. 12. 12 Stripe Payment: let's create a new integration test to make sure that we came performed charges using stripe A p I. I'm going to create any test class using PHP artists and make this stripe payment test. And even though I said this is an integration test, I'm going to start it in the unit folder. So that stash unit now let's open this in the litter. Change this to at this and include refresh that of it. That's called distaste. It can make riel charges with a valid token, I'm going to quickly open their fake payment test. Let's go Be this three lines from these. It has a total charge test. Remove this line in baselines here. The first thing I'm going to change is thes fake pain class because we're going to actually be using a riel stripe payment class called stripe pigment. Next, I want to make a real charge, but in this case, I don't want the test stoking anymore. I want a real token, and we're going to talk about where are we going to get that in just a moment? And I'm not going to worry about the assertion just now. First, let's figure out How are we going to get this token value for this? We're going to talk directly to strike. I already created an account in stripes, which is set to test data, and I am logged in in the dashboard to get the documentation. Just click on this book over here and then click documentation then from the main documentation page. Look for these AP I reference and on the left side menu, look for tokens. Create car token in here. We have a code example off what we need to do in order to create a real talkin using a fake credit card. So we're going to follow this example. But first, we need to include this library in our project. For that, we're going to use this composer command, so I'm going to copy that head back to the tear Amina based at Enron, It now that the package has been installed, let's go back to the documentation and copy that piece of code that will allow us to create and you talking. Let's copy this entire piece of code from here and based it in our test right after the payment class. I really don't like this notation so I'm just going to include those to libraries youth, straight stripe in. Also use stripe token that will allow me to simply say strike Serapio, King and Duncan create know that this is my secret key, which I obtained because the documentation pages, if you're signed in already, it will replace the value with your actual secret key. So I recommend that you create an account for yourself logging into it and then go to documentation pages. So this value may be different for you, but I don't like this value to be hard coded. In our project, there is a folder called Conflict and inside of it there are different configuration files for mail, database cash, etcetera. I'm going to use this one services to set up my key in there so open that went up. If you scroll down, you're going to find out that lauraville already comes with a section for stripe which gets the values from the environment. Variables striped key in stripes secret. So let's go ahead and set this to in the dot e and be filed so that they are available to our application. This open the dot gmv file and it's on a couple of interests. Stripe Key in Striped secret. To find out where your talking's are simply, go to the stripe dashboard and in the left side, click on a P I, which will give us this table where you have the publishable king and also the secret. So let's copy this value from Pierre and said it in key and also secret. Copy that basted here. So now let's go back to the test and let's replace these with conflict into that, we passed services, which was the file where we set up our keys. Let me show you again. So it wasn't services, which is a file then stripe and lastly, sick. So services stripe secret. Then we're going to have a talking created with a fake guard, which is simply for two for two for two, for two, for two, for two, for two for two, any expiration month in the future and any expiration year in the future in any CVC. But this value seem a little bit arbitrary. So instead of two as the month we're going to set it to one because we're going to also said the year to any year in the future we've date with why as Foreman, So that'll give you see, four digit year and we're going to add one to that. And let's replace the CVC with something more common like 123 So that way we know that this is definitely some test data. That doesn't matter. No, for the time being, a store this into a viable called talking Let's run this test, but just don't out the content of the talking viable. Just make sure. What are we dealing with? Back to tell me now? DHB Unit, that's that fielded equals It can make real charges with a valid talking, asking for the stripe payment class. So let's create that real quick PHP artisan make model stripe Faymann hoping that in the editor let's remove these use statement from here. And also the extent does leave this as a simple class and also to save in some minutes. Let's go back to the test and import this class. Use up stripe payment back to tear. Amina Investigate. Sorry, testing it. So this is the content that we got from stripe FBI and looking at it, we see that the I D field is the one that contains the actual talking. So if we go back to our test down here for the rial talking value, we can simply say token, I d. Now we are going to need a way to get the last charge so that we can compare the amount with the total that discharged. So how do we do that locally From the documentation, we have a way to least all the charges using striping p I. As you can see here, we have a way to simply say charge all and then pass a limit to the least off. All the charges were going to receive. So let's go back to our test. And before we move on, I don't like to said the A p I keep for stripe globally. I'd rather said that for every call it may How do we do that? We simply passed the A P I key as a second parameter for this call I'm going to. First of all, I don't like this array notation here. I'm going to change that right away for a more motor pH B array notation like this Does this one hope bracket this one close his racket thing close bracket here. So as a second perimeter to these, I'm going to pass a configuration or an options array in one of those options is a P I key in. The value for that is going to be this from there space here. So that way we can avoid setting this globally next after the talking has been created, I'm going to make a charge using that token. And finally, I should be able to get the last charge using the charge striped charge class. Oh, and then pass a limit off one in a second. But I omitted again. We said the A P I key and say that to a variable cold charge or charges because technically is going to be a list of charges. But just with one element. Now, let's examine documentation to see how these charges response is going to look like. If he's girl down, you can see one example response in a chase Informant here looks like the amount that was charged is going to be in an A ray called data in this case, that arrays going to have just one element. So if we go back to the editor. We can probably say something like charges data in the first element, and from that we only need the amount and noticed that the amount is going to come in sense . So we need to compare just like that incense and looks like this is a good starting point for a test in the next video, we're going to run this test and go through the errors to make it pass. 13. 13 Real Charges: in the last video, we created our test for performing riel charges with stripe. Now it's time to run that this and see whatever's we get could be the name. And in the third, Amina, let me clear this up a little bit. BHP unit That's that feel that it can make real charges with a volley token, saying that the charge method in the stripe payment class is not defined. So let's add that this open strike payment and first of all I want, is to extend or actually implement the payment contract plus for the payment contract interface, which is going to force me to implement the charge method. So with that change, less this again undefined upset cereal and what does that mean? Well, seems we haven't performed any charges yet. When we call charge, all is going to give us an empty least of charges to them. A straight manages dying dump charges and run the test again. And as you can see data, it's an empty arranged. But in our test, we're trying to access the zero element, which will be the first element, and that's why we get an error on the fight offset zero, which means that at this point we have to implement the charge mental. Fortunately in the A p I documentation from stripe, there is a method we can use to create a new charge to which we only have to pass an amount . What's a currency token, which is cold source in a description which I believe is optional and yet description is optional, so we don't have to pass that. So I'm going to copy that gold. And I'm only going to copy this section here because I'm going to pass the A P I key as a second perimeter. So copy in this open the stripe payment class and let's space that goat here. And I'm going to use or import the charged class from stripe so that I can use it leitess and let me fix this A race in Texas. I don't like it that way. So open bracket in close record here Now, for the amount we're going to use total currency, we can keep s U. S. Dollars. The source will be the token and we can remove the description. Okay, lets just again. And I believe I forgot to remove the dying dumped from the test showed me do that real quick. Take this off, intestine. Oh, yeah. I forgot to pass the a p a k a second parameter back to the editor in the stripe payment class. I have to pass a second parameter to the charge create method, which is an array with the A P i g set to config services stripe secret. All right, it's right that again. And now we get green. Perfect, right? Well, almost See what happens if I go back to the editor and I comment out one of this coat. So now the charge method is doing nothing. If I go back to the terminal in test one more time, I'm still getting green, which is not good. So what happens is that if we go to striped dash work and looking to our payments, we still have the payment that we made when we run the first test. So if we run another test, then we go back to the editor and on comment that code, run the test again and then come back to the dashboard and refresh. We have a second payment. And for everything that run, there's going to be a new payment. So we are not telling level that we only want the last payment that we made. The one that our test run? No, the oldest one. What we need is a way toe Onley receive or only test with the needless charge. So to do that, we're going to go back to the editor and create a couple of helper methods that are going to help us achieve just that. So let's go back to the stripe payment ist. And the first thing I'm going to do is to define a private field called last charge. This is going to be part of the strike payment test class. Now, Every time I run any tests on this glass, I want this last charge to only have the last charge performed since the last best, and that is going to make sense in just a minute. So I'm going to create a new private method down here in this call it last charge, and that is going to return the last church which we can get with charge all passing a limit off one. So I'm going to copy this line, paste it here, but I'm going to return Vada sub zero because I'm only interested in the charge. So last charge is going to give me the last charge performed. Next, I'm going to the finally set up function for a test. So public function set up and in here for civil, I'm going to set up the parent class so parent set up. So that will allow a lot of to do any bootstrapping for the tests. And then I'm going to say this last charge equals this last charge. The method. The last charge is going to hold the last charge that we made before we even start run the tests. So basically, that will give us a starting point. But how do we know which of these charges is the newest? Well, if we look at the stripe AP I reference in the least or charges there is one parameter we can use to tell striped toe on Lee. Give us a list of charges is starting from a certain point. And that'll be this ending before perimeter. Think of it, I say course or for pagination as it's stated here. So let's go back to the editor. And here we're going to create a new private function. And let's call it new charges. And here we're going to return again. A call to charge all. So I'm going to copy everything up to data. I'm not interested in returning the first element. I'm interested in returning the array itself, so let's copy that basted here. But in this case, I am not only going to pass a limit off one, I'm also going to pass another perimeter, which is ending before, and this will have the value off these last charge I d. And let me arrange this line because kind of big, so ending before right there. Like so. All right, so basically, what I'm saying here is returned all charges limiting that leased by one and also starting that least right after the last charge. So, back to the main test, I'm going to make an assertion before this one saying this assert equals one this new charges. So before I test anything I'm going to say, Has there been any new charges right after I perform these charge over here? So basically saying if this charge worked, there should be at least one new charge. And if that is the case. We can replace this with these last charge amount and we can remove this line from here. So to summer. In the settle method, which is going to happen before the execution off the main test, I'm going to get the last charge that was performed then in the test, I'm going to create payment class, creating you token 10 then perform a charge using the stripe, A p a. After that, I'm going to ask if there was any new charges performed after the one that I got, which is the last charge that I got here. So if there was any new charges after that one, these assertion will be true. In that case, I'm going to get the last charge, which is effectively. This when I made here can compare the amount to 1000 cents, which is what I fast here. I hope that makes sense. So with all of those changes, let's go ahead and test again. Array does not match. Expect that type indigent. Looks like we did something wrong in the test, Nemecek. Oh, yeah, I see the problem. Remember that new charges is going to return an array of elements or an array of charges. Granted, Attari has only one element, but it's still in array. So up here, instead of using assert, equals what I meant to uses. The search count, which is used to compare the count off elements in an array T expected count, is one, and we compare that to the array returned by new charges. Let's just again and we get green. But now let's make sure that this is a good result. By going back to the editor, open the stripe payment class and let's comment this code again. And now we should get a never go back to their Amina investigate. And that's correct. Failed, asserting that actual size Syria, which is the size of the array, matches expected one. So that's a good area. Let's go back to the editor and uncommitted this best again, and it's still green. Perfect. Let's test everything. Just make sure that nothing broke and we get green as well. In the next video, we are going to go through the u I and give some style to the views we created, starting with the product list moving on to the shopping cart and finally, the order confirmation 14. 14 Product List: in this video, we're going to take a step away from the tests and dedicate some time to the U I of our application. As of now, we haven't seen anything on the screen. All we have done is make sure that the application works as expected. But with the functionality out of the way, we can take some time for the look and feel. This is the home page of our application that the phone level home pitch what would happen if we try to access a page like products which was the least of parks? As of now, all we get is this http ever 500 page, which is quite ugly. So the first thing I want to do is to roll back on the change that we did right from the beginning, where we told notable not to handle exceptions. So let's go back to the editor real quick. And let's open, uh, exceptions handler, that BHP and from the render function let's remove this line from here, which is just re throwing the exception, which was handy for us when we were testing, but not so much. When we're trying to view errors in the browser. So if I go back to the browser in Refresh, we get this ever scream that comes later. Bill saying that we don't have a database to work with, so let's go ahead and fix that first. I don't want to work in the the Fold Homestead schemer. I want to create a schema for our application. So let's go back to the terminal and from here and going to access my SQL with my SQL I asked you for User, which will be home sit that city full user and Ashby for authentication with password in the default password is secret. Well, let's create a new database cold store, so create that the base store and let's exit out of here. Next thing I want to do is to run all of my migrations, but for that we have to make sure that we are connecting to the right out of it. So let's go back to the editor and open the dot E and D file. And on the's section, we have the credentials. Shorter database to be connection. My SQL That's fine. Host is also okay. That's what a sport No, that that a base schooled store, user name and password are OK as well. So let's go back to Terminal in runner migrations using PHP Artisan. My great know that we have tables created. Let's go back to the browser and see if we still have any errors. That's refresh and appears. We're getting just a blank screen. So let's go back to the view. The view that we have so far and see what's happened. This Open Products index and yeah, the problem is that right now we don't have any products in our database. Let me demonstrate by just adding, when H one products and we now have the H one. So we have content. We have a view, but we don't have any products. The next thing I want to do is to have some data to work with, so I'm going to see at least a couple of products in my database. So back to the terminal, let's open Ph. B. Artisan. Think it, and from here I have access to all of the classes in my project and also my model factories , which I can use to create a few fake products. So let's a factory at product glass. Let's create. Maybe 10 records create. And as you can see, it created 10 products in my database. So let's see that in the browser. Let's refresh. And now we have products in our page. But it's kind of ugly right now, so let's fix that. Let's go back to the editor in with our view, openly start adding some content to it. But actually, first, let me go ahead and run one more step in the terminal. PH bi partisan make out. Now, this process will s careful authentication for my application. But all I need from this is the fact that he created a few extra files. For example, it created a layout file for the application and also added a CSS file to a style to it. Let me demonstrate back to the editor if we open resources views, we have a new outfall there here and also there is Layouts. Folder, which contains a file called App that played at beach mean in the content of that file is basically in layout that is going to be applied to any other page that extends from it. It has a navigation bar, some navigation bar items and down here we have a section called Content. It also includes a CSS file, which at the time is located on their public see Assess. And it also includes a JavaScript file located under public Js. Now this JavaScript file is magnified, so it's not going to make any sense. Now. Look what happens if we extend from this layout. Inside our view, back to our product index, what we have to do. It's a extends in here. We give the name of our layer style, which is layouts that a PP Now we're going to need to add the section called Content, So Section content in a deviant, we simply say in section. So with just that, let's see how our view is looking. Now let's refresh. And as you can see, it changes the style of Page this Heather right here. It's part of the layout and everything within the contents section. It's down here, so let's give this section a little bit more style back to the editor. So let's start by removing that from here. And let's are a Deve class container inside that a deep class ro. Many of the classes I'm going to use for the content are part of bootstrap. But I'm not going to dedicate any time explaining bootstrap because that is beyond the scope of this course. For now, let's just keep moving. I'm gonna take this for each and move it up here inside the Rome. No, for each product. I'd like to have a DIF class gold dash. MD bash three. That'll be three columns wide in here. Let's have another Deve class thumbnail and then one thief class caption. Let's add another row here, the class RO. Then another Deve school MD 12. And here I'm gonna have the product name. So I'm gonna take that, Put it here, and let's at another row below that when a copy, this too. And right where the road ends. Space that close to stiff and then close this other one. And here I'm going to have the price Mistake that Pitak off. There you go. The right below the price. I'd like to have a button to have the product to the car. So, Dave, Class role and thief Class Co MD 12th. No, we need a form. The action, as we remember from the test, is going to go to card, and we have to pass a product I d. So product Heidi, this is going to be a post. So method equals post. And since lot of it comes built in with cross site request forgery protection, we have to include something called CS R F Field. Next, if you recall the action off, adding a product to the cart was handled in a put method, not a post. So we have to make a lot of will believe that this is a put request and we do that by including a method field put. And this to all they are doing is rendering some hidden fields that will handle the C s A ref protection and also handling the mimicking of a put request so you don't have to worry about them. Next, we're going to need a button. So button, class B TN BT and success in here we see that to can. Okay, let's see how that looks back to the browser and refresh. And it's starting to look a little bit better. But I don't like the way this button comes off this block here, so maybe we can add some placeholder images, so maybe we conclude an image stack here, the service we can use place hold it, which is a free image placeholder service. All we have to do is set the source to a be the, uh you do it placeholder dot com and the next thing we have the best is how big and white images will be. Maybe something like 400 by 400. Just to see how that looks in its at a class off image. Responsive. And let's see how that looks. This button is still coming up. I don't understand. It's go and check the HTML to see what's happening. No, of course there is the type of here this is Class Ro. This is fresh, and now it's looking good. Let's add some distance between the price and the button and maybe at a dollar side, probably just adding the P tag back will do the trick. I had a dollar sign here. Yeah, that looks better. Also, we're not going to use any authentication, so let's remove these buttons from here. Let's go back to the layout file and upped up. We have the navigation bar, and somewhere in here we have two buttons Yeah, right side of Nath Bar. We have long in a register when we have a guest otherwise is going to show the user name. But we don't need that. Soldiers remove it entirely. Everything that has to do with authentication links. I stayed that off. And now that we're here, let's also change the name of our application. As you can see from the title, this is coming from a configuration variable called app name. And if we open the dot e and D found, we can find that at the very top happening. A lot of ill has changed it to store back to the browser fresh. And there you go. Now, since we already tested this functionality, this at two carp should be working. So what happens if we press it Well, based on our test is going to take us here to the car content and you can see that we already have one item called this product in the next video. We're going to give style to this view. The card content 15. 15 Cart Content: Let's take some time to give the car content. View a better looking style. Let's go back to the editor. Let's open card index. First of all, we're going to extend from our application layout using at extends layouts that AP team and then had a section for the content. So at section content in right at the end, at in section with only that, we can go back and refresh, and it's looking a little bit better already. So up here I'm going to remove this h one. Let's add maybe a DIF class container, then a deep class role and finally, a thief. Class call M D. Maybe something like eight. Now, I'd like to have a panel in this view. So thieve class panel panel info, and it's going to have a heading. So the class final heading another Deve Class final content or actually panelled body And one more to Deve class. I know food er inside a panel hitting one deep class final title and then maybe an H five shopping cart that would be our heading. No, for the body actually holding. I'd like to have a button in the heather, something like continue shopping, which will take us back to the product list. So maybe let's add the row here, the class ro and then a Deve class called Mt. Six. So that ago halfway and then we can take this age five from here. Put it in here. And then there's another thief class call M D six and then have a link that goes to products. Class Bt end BT and primary Maybe in let's make it a block button so it will take all of its space et en bloc in here we tied. Continue shopping. All right, now let's move on to the body of the panel here. I Kenbrell thing this for each. I caught it from here and move it up into dependent body and we can almost living like that . But I'd like to you also add a placeholder image at the beginning. So maybe something like the class school MD to and then an image from taste it to be the dot placeholder not come. And this can be something like maybe 100 pick sounds by 70 pics of stole and let's make it a responsive one. So class I am G responsive. Next is the product name and finally, the product price. But the name is gonna be a little bit wider. Maybe six. Okay, lets see how that's looking. Refresh. Yeah, that's a lot better. 16. 16 Checkout: now for the panel. Food er. We're going to have a total of the car and a check out, but well, it's at a DIF class. Ro in close. Let's center all of the content in this rose or text center. Next a D Class Cole M D. Maybe nine. Next list at an H four. It's lined this up to the right. So class text, Right? And here we contact total. And let's make the total bolt so strong a dollar sign. And here we're going to use the cart. Total price. No, next to it. We're going to have the check out. But so, Dave Class, call em the three. Next, we're going to need a form which is going to make a post two orders. It's Method Post. Let's not forget the CSR field, and now here I'm going to use one of stripes libraries called Check Out that J s, which is going to allow me to add a button that will directly include a JavaScript library from stripe. And they will take care off having a small pop up window that will have all of the functionality to ask for the credit card information and the customers email. So all we have to do is think include a script back in the script, AC will take a few parameters. First of all, the serfs and the source is http s check out that stripe. Not come forward slash Check out that Js. Next, we can specified class of this button which is going to be striped. But next, these check out the Js file will require some parameters that are going to be included by using data. Tash something. So let's begin with the 1st 1 which is data Paschke, which us you already know we can get from the configuration file. We can say something like conflict services, not striped, not secret. The next perimeter is called Data Tash amount, which is going to be the total of the purchase and that we can get from card get total. This story is incense. The next parameter is called data dash name. And this is going to reflect the name of our store. We can get that from con fic, huh? Name Next. You can add a description for this purchase with data Tash description. Let's just call it test purchase. Next. You can include an image of your store, Maybe your brand or your logo. Using data dash image, I'm going to use a desk image provided by strike. This is the image that they provide for testing purposes, and I think that should be enough. Let's go ahead and test this. Gonna go back to the browser back to the products page. It's adding new product to the car and it looks like we have an error. Yeah, I made him at stake with the method for the total car price that get total is total press. Let me correct that to the other third can total price. Actually, that's in currency. Should be car total. All right, let's straight that I'm going to refresh in. There you go. And as you can see, with the inclusion of that JavaScript tax, we have a new button that says pay with car. But as it stands right now, there are a couple of problems that I discover what I was doing. This project. If we look at the documentation on their dogs, quick star, you can see that they have a code snippet here to do exactly what we're doing. And they even give you an example button here that you can press and this is what we should get on our side. A nice pop up where you can enter your email card number, expiration date, security code, etcetera. And then when you click pay stripe will take care of authenticating the credit card number , return a value token for that car and then post in the form to orders. But if we try to test this right now on our side, when we click, the button is going to submit the form right away, which means that the JavaScript provided by stripe it's not working as expected. There is also the issue that the payment contract is not extensible, but we will solve that in a moment Now. The problem with this try button is that for some reason there is a conflict between the JavaScript that is being included from strike in the JavaScript file that comes built in with little if we open the layout file. This is including a JavaScript file called Abdullah Yes, which is located inside the public Js folder. This file was generated by level when we did make out from the termina which scaffold it all of the code required for authentication. Unfortunately, we cannot edit this file because his men, if I if we try to open it, it's just gonna have one long, ugly line off JavaScript code. From my understanding, what this violence doing is loading some common JavaScript library such as J Query in Bootstrapped. Yes, but since this project is not making any use of those JavaScript libraries, we can solve the problem at hand by simply removing this script back. Having removed that script from our Lady of File, let's go back to the relative refresh. And if we click the button now, we get the pop up where we can enter the credit card information. Let's use a test email here for the card number stripe, except a test number that is simply for two for two for two, for two, for two, for two, for two for two. You can use any expiration date as long as it is in the future. So January 2019 in any number for the security code. Maybe 123 That's click bait and looks like we used the wrong key when we set up the strip, because it's asking for the publisher. Bulky, not the secret one. So let's go ahead and fix that in here. We change service stripes secret by service stripes to and just let me make sure that it's a case could fix services key. And that comes from Strike Key, which is in the dot Ian Defiled. Yeah, there it is. Let's try that again. I went ahead and refresh the browser and field form here. No, let's click pay and looks like he's not like in the way we're setting the public key in script. So let's try something different. Oh, no, wait. I think I spotted the problem. I was using service instead of services. Let me do that again. And yet that was a problem. By the way, if you see this screen here, you can pretty much dismiss it is just a verification system that stripe has so you can use . Dismiss it by clicking on this hour right here. Let's use the test credit card number. January 2018 went three in pain. All right, that works. Now let's solve these binding resolution exceptions. If you remember from our tests in order to use the fake payment class. Inside our controller, we had two first bind that instance Fake payment to the payment country. Now that we're testing life, we have to do the same. But in this case, we have to buy the payment contract to the stripe payment class. We can do this easily by making the bine inside up providers up service provider within the boot method. Here, we can simply say this up. Bind the abstract will be the payment contract plus which is located in at contracts Damon Country. And here I'm going to bind it not to an instance of a class, but to a class definition in this case, uh, stripe payment. Which means that in the orders controller, when he's trying to instance, she ate the payment contract, he's actually going to use the stripe payment class in Stan Shih ated inside this payment viable and these will be assigned to a private payment feel. Let's go back to the browser and give that another try. I'll go back to the car refresh feeling everything here in click bait. Now we get an interesting error because the total method was not implemented in this tripe payment class. So looks like we are missing one test inside the stripe payment test this at a new test case right below this one. It can make real charges with a valid token in the school. It it has a total churched incense, and I think there is already a test with this name. So let's make it more specific. It has a real total charged incense. Let's take this cold from the previous test copy. Paste it here. We're going to need a payment glass, generate a riel token, charge $10 down here, I'm going to use the's Assert equals 1000 which is $10 bin. Compare that with payment total just justice BHP unit. That's that filter equals it has a real total charged inset. The total method is not find. So let's go ahead. And at that open the stripe came in class, had a new public function called total and similar to the fake payment class. We're going to need a private field, cool, total and I want to make sure that the charge actually goes through. So I'm going to say the results of these charge into something called charge and if everything goes well, then I can say this total equals charge amount. If you check the documentation for these charge, create in the striped documentation pages, you can see that from the response. We are able to get a no object that has the amount that was charged. And from here we simply return this total. Let's test again, and now we get ring back to the browser. Let's give this another try and looks like we didn't have any ever at that time. If we check on the dashboard from stripe, you can see that the payment actually went through. Now, before we finish, I'd like to add a few changes to the test because once that purchase has been done, I'd like to be redirected toe on order confirmation page. So let's go back to the editor. And as you can see, once we perform the purchase here, we simply at the products to the order and that's it. So let's go back to the purchase test. Let's say this response. Let's add one extra assertion here. Let's say response. Yes, sir. Redirect to orders and let's run these tests again. It can purchase products Response Status Co 200 is not a redirect status code. So let's go ahead and fix that from the controller borders right after we add the products to the order, its return redirect to orders. Run the test again and now we get green. Let's see what happens if we do it from the ground said we're gonna go back to the shopping cart, Click pay again. I do get redirected toe orders, but I don't have a route or of you for it. And I'm going to leave this to you as an exercise inside this test. I want you to make another assertion right here to make sure that you can actually visit the order spay judge. And when you do, make sure that you are able to see the order, their email, the product name that you added to the cart, the product price and finally, the order total again. You should be able to see all of this information once you visit the order speech, try to sell that on your own, and we are going to go through the solution in the next video 17. 17 Order Confirmation: So in the last video, we ended up with an exercise that I hope you tried to solve on your own. We need to make sure that when we v. C the order confirmation page, we are able to see all of this information here. The order email, product name for price and the order total. But first of all, let's modify one thing if we want to be able to see the order email we're talking about showing and a specific order the one that just got created to do that instead of being redirected to the generic order speech, we should be redirected to something like orders and then pass the new order I d. And that will show us this order information. Now, how do we find a newly created order? We can copy this line from the test right below the one in it creates orders after purchase . We should make sure that the order is not know, doing something like this, Assert, not know. And since the order is not know, we're able to pass the I d to the redirect assertion and later on, if we visit that page using this, get orders order ready, then we can make assertions for all of this information, starting with the order email assert, see quarter email. You can do it like this or to make it simple, you can just simply pass the text fist at email dot com. Since I didn't provide any product name myself, I'm going to have to do a ser C product name. Same for the price assert. See product get price. But in this case, I do know that the price was $10. So I can you simplify these two $10 in currency for? But this will be pretty much the same as the order total, since I only added one product. So I think we may be able to go by without that assertion. I think just the order email and the product name will suffice. So with all of those changes, let's go ahead in this this again cookie, the name back to tear Amina BHP unit that's that fielded. It can purchase products. It's complaining about the redirection your l because if you remember from the controller were redirected to orders and now we're asking for orders, I d. So let's fix that. Open the orders controller, then let's redirect to orders. Border i d. Best again. They know we're getting a bunch of HTML and we know Weaken Bypassed is temporarily by going back to the editor in opening up exceptions, Handler and from the render method simply re throw the exception using throw exception. And once we're done testing, we will come back and remove this this just again. No, we get a note brownish to DP. Exception, which is better? Let's go ahead and not the missing route This open routes Web. The PH. Bean. Let's had a route. Get orders. Border. They should be handled by order. School Troller on the show Method Just again. Method show does not exist. Open the orders controller. I had a new public function called Show, and since we know we're going to use implicit moral binding, let's go ahead and include that right away. We're going to receive an instance off quarter cold quarter test again failed, asserting Empty stream contains test email. First of all, let's make sure we are returning a view from this. So return do you orders show and we know we're going to need that order. Viable interview So Let's go ahead included at once quarter order just again. Now it's asking for the missing view. Inside Resources views this creating you Folded called orders Inside that folder, let's create a new PHP file called Show that played at PHP just again failed us everything . That empty string contains test at email that come so we're back to the same error. But now it's because we have an empty view. These view is going to be very similar to the card index views, so I'm going to copy the content from that one and make some modifications to it. Joel is open card Index. I'm going to copy all of it back to show the later pH. Being and based it here, starting from the top. We are still extending from the same layout, and we have a content section. We're going to maintain this container and ro, let's change these heading to products. We're not going to need this button. So let's remove this from here in change days, too. 12th. Now for the body, we are going to reiterate over order products pass product. We will have a placeholder image product name in the product price and then for the footer . We're not going to need a check out button, so let's remove that and we will get the total price from the order. Now let's go back to the top. And right before this role, it's at one more row for the order email and maybe some confirmation message. So the class ro, then the class coal dash MD that's 12th. And let's center the text with text center. Then maybe some h R for some separation lines it in each four, and it's a success order for endless. Put the email here. Border email confirmed. Okay, I think that should do the trick. Let's go back to the terminal in tests again. Call two undefined method. Total price. So we're missing a total price method on the order. So let's create a quick unit test for this one inside order test. This had a new test case down here. Let's call it it has a total price, and I think there is another tense that has the same name. So let me at something to be more specific. It has a total price for the order, and I'm going to borrow the code from the previous test, so I'm going to copy that basted. Here we have three products in one order or products are attached to the order. For simplicity sake. Let me create those products with a fixed price of $10. Then we can say these assert equals $30 in currency format. Then compare that to order total price. Let's run this test real quick. BHP unit that field. It has a total price for the order. Total price method not being defined. So let's open the order class for the order model Class had a new public function called Total price, and here we returned number four minutes. These total divided by 100 with two decimal points. Let's test again. And apparently he's looking for $30 returning 10 99. Let me see what happened there. So we have a list of products in Oh, of course. Turns out I don't think we are going to need the least of products here because when we're creating the order we created with a set price, so here I can simply pass that total myself. Let's say that total is actually $3. We won't need to set any product attachments. This this again. Okay, we get green. Let's go back to the future test. It can purchase products, just that one again, and we get a green as well. All right, let's test that in the browser. Let's add when product to the cart. Pay with stripes. And we're right to the order. Confirmation. Just a few tricks that I have to do with this sign because this panel looks to be not aligned with Heather. We can fix start by expanding these instead of eight. Use 12 instead. And yet that looks better. Maybe another H r. Right below the message right here in that looks good. And before we end this video, let's just remember that we have to undo the modification we made two. AP exceptions. Handler, remove this line and we're done. 18. Conclusion: And with that, we get to the end of the scores. Thank you so much for taking the time to watch this. I hope you found the information helpful. Although the project is simple, with the shopping cart being only in the session, we managed to get a project that not only has a list of products in a shopping cart, it also includes an integration with strike that come for processing real payments. And we managed to do all of that using test driven development again. I appreciate you taking the time to watch this course, and it's always if you have any question, don't hesitate to contact me. Send me a message and I reply as soon as I can, Thank you and goodbye.