در حال بارگذاری ...

Spec Structure and Aliases0:00

All right, why don't we start with a basic and common test for a blog. We'll call it blogspec.js. Okay, so we can format these in a number of ways. You've already learned that we can use this it function while providing a callback as the second argument. It works, and then perform your expectation. However, if you read some tutorials, you may see things like specify. But don't worry, at and specify are aliases, they do the exact same thing. And the same is going to be true for these wrappers. So often you will want to add context.

And the same is going to be true for these wrappers. So often you will want to add context. So you will describe a feature, and then you will describe a portion of that feature. And then within there, you will perform your expectation. So just like it and specify are aliases, the same is true for describe and context. Exact same thing, use whatever works for you. Or mix and match. Okay, so in our case, we're going to describe our simple blog. And yeah, we can do things like it shows all posts. You could have one for it creates a post for

Acceptance Testing Mindset1:02

And yeah, we can do things like it shows all Posts. You could have one for it creates a Post for testing out the form, everything that your blog does. We'll start with this first one. Now, a quick little note. Your acceptance test will be a little bit different from how you would traditionally validate with a server side level test. So for example, if you're using PHPUnit, you might say something like, if I hit this endpoint to create a Post, then such and such record should exist in the database.

if I hit this endpoint to create a Post, then such and such record should exist in the database. However, when you're writing browser tests and acceptance tests, you're going to validate in the same way an actual person would. So with that example, when I visit this page and I fill out the form, then I should be redirected to the blog where I now see that page. And that's the big difference there. Having said that, sometimes you will mix and match. Case in point, this example. I don't yet have a form to create a Post.

Creating Data with Factories1:55

Case in point, this example. I don't yet have a form to create a Post. So it would be nice if I could say, well, let's just create a world where I have three Posts in the database. And then we begin our test. Now you learned in the last episode that as part of the Laravel commands, we pulled in through the Laracast Cypress package. We have one here called create to create a new factory. And you can see, give it the model, the number of times it should be created, and any necessary overrides.

And you can see, give it the model, the number of times it should be created, and any necessary overrides. So I could say cypress.create a Post. Now note, we don't have a Post yet, but we're writing the code we expect to have. Next for the attributes, and actually real quick, if you don't specify the number of times, then we just make the second argument the attributes, which is pretty common. Anyways, why don't we set the title to my first post? Okay, so now this should give us a new Post in the database once we create the migration and add the functionality.

Okay, so now this should give us a new Post in the database once we create the migration and add the functionality. Now I can begin my test. If I visit the blog, then I expect that page to contain my first Post. All right, let's give it a shot. I will boot it up, npx cypress open. We'll do our blog here, and it should fail, and of course it does. All right, so let's figure out why. We begin by grabbing a token, and then we grab the body from the response. So real quick, if I click on that, it'll print it to the console.

We begin by grabbing a token, and then we grab the body from the response. So real quick, if I click on that, it'll print it to the console. So now if I open up the console, here is that token that was returned. And effectively, the way it works is when we hit these endpoints, they do have CSRF protection in place. So we start by grabbing the token, and then once we have that token, we make a new request, and we include the token as part of the request body. As you can see here. Okay, but it still fails. So we can look in the console here, or of course, it should be down below.

Adding Post Model and Migration3:50

Okay, but it still fails. So we can look in the console here, or of course, it should be down below. Here's the response we got. Okay, class Post not found. And of course, we're trying to create a factory for a Post, but we haven't yet set that up. All right, let's go ahead and make a new model called Post. And I also want a migration and maybe a factory. Let's visit that page, create post table. And this is going to be super simple, we're not even going to have a body.

Let's visit that page, create post table. And this is going to be super simple, we're not even going to have a body. This will be a title, and that's it. Okay, so real quick, remember that we have two .env files, one for your local environment, and then another one for your acceptance testing. For acceptance testing, we've already created a cypress.sqlite database. But for my local environment, I haven't done anything of the sort. So why don't we do this? Let's copy this, and we'll use SQLite for both. I'll paste that in, but in this case, we'll call it database.

Let's copy this, and we'll use SQLite for both. I'll paste that in, but in this case, we'll call it database. Or a little tip, if you go to your config/database.php file, and we scroll down to the SQLite connection, the default database will be in the database folder called database.sqlite, which means I can leave this blank, and it should still work. Okay, so now in our database folder right here, let's add a new one called database.sqlite. Okay, so it's empty, but of course, as soon as I migrate my local database, that'll be populated.

Okay, so it's empty, but of course, as soon as I migrate my local database, that'll be populated. But now keep in mind, cypress.sqlite is still blank. So we haven't yet run our migrations for the acceptance testing environment, and we'll talk about that in just a minute. Okay, but of course, we do have our Post model. So if we go back to cypress, I can hit the letter R to rerun. It's still going to fail, right? We would expect this. Here's the response, and now it's changed, but notice no such table posts.

We would expect this. Here's the response, and now it's changed, but notice no such table posts. So it found the Post model. It tried to insert into the database, but no table exists yet. All right, so we have a couple options here. I'm going to go back to phpStorm, and if I open up my terminal, have a look at php artisan help migrate. So run the database migrations, but notice if we specify the .env file, the environment the command should run under. So what we could do is if I say php artisan migrate,

the environment the command should run under. So what we could do is if I say php artisan migrate, with the environment set to cypress, Laravel will automatically reference this environment file for that command. Okay, so let's give it a shot. If I run this, now it migrated our database specifically for our acceptance environment, as you see there. So now if we switch back and give it a rerun, of course it's still failing and we would expect it, but now notice we did successfully create the Post. And if I click on this, let's go to the console here.

we would expect it, but now notice we did successfully create the Post. And if I click on this, let's go to the console here. Here's what it yielded, okay? So now this is effectively the adjacent form of your post factory or model. And now it moved on to the next step where it tried to visit the blog, but it received a 404. Okay, but actually real quick, I'm going to empty out this database so that we can come back to what we had before. Yeah, so now we're back in that same boat where the table doesn't exist. So yes, you can manually run your migrations.

Refreshing Database Per Test7:10

Yeah, so now we're back in that same boat where the table doesn't exist. So yes, you can manually run your migrations. However, you could also run them as part of your tests. So have a look, right here, I could say before each test, I want to perform an action. So for example, I could say Log::info('hello world'). So this allows you to log something in the UI. So if we give this a run, have a look, right here, before the test runs, we log something. And then if we close this one, right here, before the test runs,

before the test runs, we log something. And then if we close this one, right here, before the test runs, we log something. So yeah, sci.log can be very useful, if only for temporarily spitting out a value for debugging purposes. But yeah, in our case, why don't we call refreshDatabase? Now, if I come back and rerun it, once again, it did successfully create the factory, and now it's trying to load the page. Okay, so let's have a look at what refreshDatabase is doing. In our support file, let's see, refreshDatabase.

Okay, so let's have a look at what refresh database is doing. In our support file, let's see, refresh database. Okay, so this is hitting an endpoint to trigger php artisan migrate:fresh. That's all it's doing. It's dropping your migrations and rerunning them from scratch. And often, that's exactly what you want. Further, if you do this for every test, it's a way to clean your database, so that you don't have state from one test leaking into the state and environment for another test. Okay, so let's move on to the next step.

Building Blog View Route8:37

leaking into the state and environment for another test. Okay, so let's move on to the next step. That blog endpoint doesn't exist. So I could say, when you make a GET request to blog, we will return a view called blog. And next, in my, let's clean this up a little bit, in my resources/views directory, we can add that. And actually, why don't we quickly set up a layout file? I could say components/layout.blade.php. So this will be a standard HTML file.

I could say components layout.blade.php. So this will be a standard HTML file. And then down here, spit out our default slot. So here, I'm creating a Laravel 7 component, but I'm using it for the purposes of layout, which can be useful. Now, I can think from the top down. I could say x-layout, hello world. Okay, so now if I switch back and we give this a rerun, let's see. It did load the blog. Notice again, it took a handful of seconds, because it's allowing for

It did load the blog. Notice again, it took a handful of seconds, because it's allowing for the possibility that the data it's looking for will be loaded in asynchronously. You can imagine, visit a blog, and then we're gonna make a HTTP request to fetch from an API all of the posts, and maybe that'll take a second. So it allows for that by specifying a timeout before it officially fails the test. So in this case, it expected to find our post title, but of course, we're not showing it there. All right, let's come on back.

of course, we're not showing it there. All right, let's come on back. And then, let's see, let's do a Blade for each Post as post. We'll have a div where we spit out the title of the post. Okay, so now if I switch back, it should still fail because we don't have the post variable. Yeah, in this case, we're getting a 500, but now a little tip. You'll notice I don't see the actual error. And if I scroll down to the full stack trace, it's all Cypress specific, and this can sometimes be tricky.

And if I scroll down to the full stack trace, it's all Cypress specific, and this can sometimes be tricky. What specifically was the error? But you will see this option here, failOnStatusCode. So we can temporarily enable that, so that we can see it all the way through to the generated response on the layer of event. Here's what I mean. If I come back to our test, when I perform visit, as the second argument, I can specify a list of options.

If I come back to our test, when I perform visit, as the second argument, I can specify a list of options. failOnStatusCode is false. So now, yeah, if we rerun it, we see it all the way through, rather than failing immediately when the status code is not 200 or 300. So what you may find is that when you're debugging, you will temporarily set this option to false. And then when you're done, you can remove it if you like. Okay, but anyways, we can see the issue is we're not passing posts to the view. All right, let's do that now.

Okay, but anyways, we can see the issue is we're not passing posts to the view. All right, let's do that now. posts will be, use the Post model to fetch everything from the database. And now, I bet it'll work. Give it a rerun, and it does. So again, this is fairly elementary, but I want you to notice that we performed our expectation, or we validated our expectations by going through the UI. Versus, it would be silly in this case, but versus looking in the database. And actually, when it comes to things like that, it's a little bit more tricky, because we don't have access to a Laravel application within this test.

And actually, when it comes to things like that, it's a little bit more tricky, because we don't have access to a Laravel application within this test. So you could do kind of funky things like this. You'll notice there is a cypress.php command. Now, be thoughtful of this, cuz it's basically using a VAL on the backend. Which is okay, because it's your own test, and it's never exposed to the world. But you still wanna be thoughtful, because often, there are better approaches. And often, when you reach for this, it might be an indication that you should really be reaching for something else, if only a database seeder, or something like that.

really be reaching for something else, if only a database seeder, or something like that. But yeah, you can see, you can effectively give it a command. It'll hit an endpoint, it'll execute that code on the server, and then return the result as JSON. You could say, app post count, and then we could say then count. And why don't we use site.log that you learned about? The count of posts is count, okay, just as an example. So we give it a run, and sure enough, right down here, the count of posts is 1. So if I were to create, let's say up here, 3 posts, give it another run,

So we give it a run, and sure enough, right down here, the count of posts is 1. So if I were to create, let's say up here, 3 Posts, give it another run, it should say 3. Yeah, so this is an option, you can use it in scenarios where it's really important. It's paramount that you peek into a database to ensure that a record exists as a result of the test that took place. But again, that should be the exception, not the rule. Still kind of cool, though. Anyways, here we go, we have your first simple test.

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