تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

Start Dashboard Page Test0:00

Okay, we've finished our second task in the last videos, and now it's time for our next to-do. We could take a purchase a course, but I want to leave this for a little bit later. So the next thing that I want to do is this one, see purchase courses. So this will be about our dashboard when people are locked in, they should see the courses that they bought. And again, since this is about a specific page, the dashboard, we want to start with a new page response test. Let me copy one of the tests here and change the name to it gives back successful response for dashboard page.

Let me copy one of the tests here and change the name to it gives back successful response for dashboard page. Okay, so what do we need? We need first a User, because this is a page which a user needs to log in. Now here we want to act as a specific user so that Livewire knows that we are locked in with this user when we make a request to a page. And then the route would be to the dashboard, and we don't need to provide anything. And then we make an assertion that everything is okay. All right, let's run the test and let's see what we see here. We have not found exception.

Install Jetstream Dashboard1:12

All right, let's run the test and let's see what we see here. We have not found exception. So yeah, we have no route dashboard defined. So what we could do now is add a new route with a dashboard name. But I already know that I want to work with Livewire chat-stream. It's a pretty cool package by Livewire itself. And it comes with some boilerplate for login, registration and the dashboard. So exactly what we're going to need. Okay, so let's require Livewire chat-stream. And now we also need to install Livewire chat-stream.

Okay, so let's require Livewire chat stream. And now we also need to install Livewire chat stream. And here we can also define if we want to work with Livewire or with InertiaJS. I'm a fan of Livewire, so let's use Livewire. And here as a flag, I can also add PEST here so that all tests that come with Livewire chat stream are already created in PEST. And if we run this test again, you can see that now we get a successful response back for the dashboard route, which now comes from Livewire chat stream. So next step here is to create a new feature test for our page dashboard. Okay, and as always, when we start with a new test, let's think about what we want to

Plan Dashboard Feature Tests2:17

So next step here is to create a new feature test for our page/dashboard. Okay, and as always, when we start with a new test, let's think about what we want to test here. First, we want to make sure that a guest cannot see this page. Okay, what else? We want to make sure that it lists purchased courses so that the user can see all the courses that he or she bought. And what's next? We also want to make sure that it does not list any other courses. Then again, similar to our homepage, we also want to make sure that we see the courses

We also want to make sure that it does not list any other courses. Then again, similar to our homepage, we also want to make sure that we see the courses in a specific order. So here in this case, I want to make sure that the User sees latest purchased Course first. And last here, I also want to make sure that for every purchased Course, the User has a way to get to this Course and watch the video. So we need to include some kind of link here that the User can click. Okay, so far so good. Probably we're going to end up with some more tests here, but for now, I think this will

Okay, so far so good. Probably we're going to end up with some more tests here, but for now, I think this will give us a good start. So let's tackle the first one, it cannot be accessed by a guest. So this will be quite a simple one because we don't need any data here. We want to make sure when we make a GET request to the route dashboard, we assert that we get redirected to another route that comes with Jetstream, the login route. Again, this should already work because this should already be included into Jetstream and yeah, it does. Still I want to make sure that it works in my application too.

and yeah, it does. Still I want to make sure that it works in my application too. Next, let's think about what we need in order to show our purchased courses. So first again, I'm going to need a User, so let's create one. But I also know that I also want a User with some courses, so there will be a relationship between User and Course. So let's say a User has a Course, let's say maybe even two, and then now we create a User with already two Courses. And then now let's again act as our new User, acting as our User, and then we will make a GET request to the route dashboard.

And then now let's again act as our new User, acting as our User, and then we will make a GET request to the route dashboard. Again, as we've learned, we're always using assertOk first here. And now we want to see something. We want to see some text so that we can make sure that we see the courses on the dashboard. Okay, but how do we define some text that we can then check here? Because here we don't use a create method, so how can we do this? So next to the create method, there's also a state method, which by the way, does almost the same here. So this means for the course, we could define here some data.

the same here. So this means for the course, we could define here some data. But since if I would here define, let's say, a title with a name course A, for example, then all of our courses would have the same name. So this means this doesn't provide us with much information because then we cannot check that we see both of the courses. So a feature that comes with LevelFactories are sequences. So instead of providing an array to the state method to define the data for every course, we can define them for each of them. And this has been done through the sequence.

we can define them for each of them. And this has been done through the sequence. In the sequence, we define an array and then an array for all the different courses which we want to create. So the first one should have the title course A, and then the second one should have the title course B. Let's now add them here. And this is now how we can check that we see course A and course B on the dashboard. Let's run this and let's check the output. Call to undefined method user course.

Add User-Course Relationship6:23

Let's run this and let's check the output. Call to undefined method User::course. Yeah, that's true because we haven't defined the relationship yet between a User and the Course. So similar as we already did before, when we want to create a new relationship, we are starting this with a new test for the model. So this means this will be a test inside our User model. And the test will have the name, hasCourses. So again, similar to our test here, let me copy some of the code here. We want to make sure that we have here a User, import the classes as well, User and the Course.

So again, similar to our test here, let me copy some of the code here. We want to make sure that we have here a User, import the classes as well, User and the Course. And we want to have a User with two Courses, right? And then we need to create them. So you want to make a new expectation. So when we grab the Courses of the User, we want again to have a count of two. We want to get back to Courses and then each of them should be of the instance of a Course. Like this. All right. So this is not a good start.

All right. So this is not a good start. Let's run this. And it's failing because call to undefined method user course. So that's the same error, which we've already seen before. That's because we haven't defined the relationship yet. So let's go to the User model and let's create a new method here, public function courses. So we want plural because there might be multiple courses which a User has. And we're returning it belongsToMany relationship now because this will need an intermediate table now between courses and users because a User can have multiple courses and a course.

And we're returning it belongs to menu relationship now because this will need an intermediate table now between courses and users because a user can have multiple courses and a course can have multiple users. Okay. Let's run our test again and let's check the output. General error, no such table course_user. So by default Laravel, if there's an intermediate table, it takes the two models and creates a string with those two models. So course_user, but mostly I know that I don't want to name my tables like this because it's not very descriptive.

So course_user, but mostly I know that I don't want to name my tables like this because it's not very descriptive. So a better name would be, for example, purchased_courses. So let's define the name that we want to use for our table here, purchased_courses. I think this is now way better to read. So if someone gets to the database and sees this table, it's very easy to see what this is about than just having a course connected to a user. And then always with those relationships, it's a good idea to use them with timestamps so that timestamps are updated there as well. Okay.

so that timestamps are updated there as well. Okay. Let's run a test again. What about now? No such table purchase_courses and yeah, also this table is not given. So let's create a new one. And I like to do this by creating a model first because we're going to interact with the intermediate table as well. So that's why I like to create a model for the table here too. And let's call this PurchasedCourse and we need a migration as well.

So that's why I like to create a model for the table here too. And let's call this PurchasedCourse and we need a migration as well. Okay. This looks better. We're now creating here this table. Let's see what the test says now. Table purchase_courses has no column named course_id. Yeah. Okay. So this means now we need to fill in some fields here.

Okay. So this means now we need to fill in some fields here. So we have here a foreign ID for a User and we have a foreign ID for a Course. So we already learned about the foreign ID for belongsTo method here, which just creates a new field with user_id and course_id here. Okay. What now? Oh, we have now a passing test. So let's check again, which was the one we were testing. I think it was this one here where we're checking the relationship.

So let's check again, which was the one we were testing. I think it was this one here where we're checking the relationship. Okay. This is now working. So this means we can go back to our dashboard test and let's check about this one. Is this now working as well? No, it's not, but we should see a different error now. Array to string conversion. Okay. Let's see what this is about.

Okay. Let's see what this is about. And yeah, I think it's about this array. I think we don't need the wrapping array. Let's try this again. All right. Yeah. Now we see a different error. We don't see course A on the side where we get quite some content, but not what we are expecting.

Render Purchased Courses11:03

We don't see course A on the side where we get quite some content, but not what we are expecting. And this is true because we haven't defined anything yet on the dashboard page. So here we are on the dashboard page that comes through level chat stream, but it now sits inside our project. So we can easily edit this and let's get rid of this welcome message here and let's provide our purchase courses here. So for each, let's say we get back here from our controller purchase courses and for each of them, let's say we also have a list here to give this a better markup here. And then inside here, I want the list item and the list item should contain maybe for

of them, let's say we also have a list here to give this a better markup here. And then inside here, I want the list item and the list item should contain maybe for now just a paragraph with the purchaseCourse title. All right. And now what about our test now? So we have an undefined variable purchaseCourses and that's true. We are here working with this variable, but we haven't set this yet. So how do we do this now? And here we can see the level chat stream has provided a new route with some middlewares for our route dashboard.

And here we can see the level chat stream has provided a new route with some middlewares for our route dashboard. This also means we can change this now here. We don't want to return a view directly. We want to make use of a controller again. We're going to call it PageDashboardController and we should see now a different error. Yeah. Our action here, PageDashboardController is not given. We noticed already. Let's create one PageDashboardController.

We noticed already. Let's create one page DashboardController. Here we go. I already know that I need to import this here and let's run the test again. And it's now failing with a different error because now the output is empty, but we still don't see our courses yet. Okay. Let's go to our DashboardController. What do we want to return here? We want to return a few called dashboard, which already exists, but we also want to

What do we want to return here? We want to return a few called dashboard, which already exists, but we also want to get here our purchaseCourses. So here we want to grab now all the courses of the authenticated users and we can do this by calling the auth helper method and then the user method on it. And then we want to grab all the courses of this user. Okay. So this only means the only thing left here is to provide the purchaseCourses variable to the view. And now with a little bit of luck, we should see that our test is passing and it does.

to the view. And now with a little bit of luck, we should see that our test is passing and it does. All right. So far, so good. And let's reformat this a little bit since we're already here to keep our structure with arranging first and then acting and asserting afterwards.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟