Define registration requirements0:00
All right, let's review another example using the Laracast codebase. How about the registration page you filled out when you signed up for the site? Let's get started. We'll begin by outlining what is necessary. What should the registration page do? Well, of course, I often say it works, but if you want to be specific, it allows a User to sign up, sure. It also does things like it displays username validation errors or messages. So if you sign up with a username that already exists, we need to let you know about that. So we would need that.
So if you sign up with a username that already exists, we need to let you know about that. So we would need that. Let's see. We have a username and an email. It displays email validation messages. Let's bring it back to errors. What about things like what if you visit the registration page, but you're already signed in with an account? It doesn't really make sense. So how about it redirects authenticated users elsewhere?
Test page loads1:36
I'll show you two ways. Of course, you've learned that we can go visit, sign up, and then we could assert that something's on the page. So, for example, here's Firefox. How about pick a subscription? Yeah. So let's say contains pick a subscription. And let's give it a shot. npx cypress open. And here we go.
Okay. So yes, it loads the signup page. And of course, if I'm only interested in working on that method, I could add the only flag. So now I'm only working on that one and it works. However, in situations where you mostly want to assert that a 200 status was returned, it seems a shame to load all of the assets. So in these cases, you can instead reach for cyprus.request, sort of like a curl request. So request this page, we're not going to load it in the browser, but make a request for it. And then let's grab its status.
for it. And then let's grab its status. So the its method allows you to grab a property from a yielded response from a Promise. Say that three times fast. So when we request the signup, we'll grab a response or a response will be yielded rather. And then we're going to grab the status property off of that. That's the status code. So then I could continue chaining by saying it should equal 200 and this would be an option as well. And it still passes.
as well. And it still passes. But don't forget, you could also just say then. So once we have the response, then we could do a standard expect call. expect response.status to equal 200. This is functionally identical to what we had earlier. So let's just keep it with what I had. And that test is now done. Okay. It allows the User to sign up.
Add username/email validation tests3:41
Okay. It allows the User to sign up. And we'll come back to that in a minute. How about validation? Okay. So let's say we're going to visit the signup page. And then I'm going to get the input. Now I already know what these are. But we're going to grab this input and it has an ID of username. This one has an ID of email and this one has an ID of password.
But we're going to grab this input and it has an ID of username. This one has an ID of email and this one has an ID of password. So username type. And how about username that already exists. Now this doesn't exist in my database, but we're going to assume it does. And we're going to set up the world where it does in just a minute. Next though, I kind of want to say, well, when I hit the tab key, I already know that validation will take place. We make an AJAX request to check if that username exists. Unfortunately, at the time of this recording,
Enable tab key support4:26
We make an AJAX request to check if that username exists. Unfortunately, at the time of this recording, Cypress doesn't have support for the tab key. It can do lots of things like enter and plenty of others, but not tab. So I believe that is in the works, but until then, we can pull in a package to allow for that. Let's have a look, cypress-npm-tab. Here it is, and let's see. So we pull it in through npm, and then we require it in our support file. Let's do that now.
So we pull it in through npm, and then we require it in our support file. Let's do that now. Pull it in, and then come on back to our cypress-support-index file. Require cypress-plugin-tab, or let's be consistent and say import. There we go, and I think we're all set to go. So now, if I come back to my registration.spec, this allows me to say type this text and then press tab. So this is the functionality we just pulled in. Okay, so when we do that, I now expect the page to say something like username taken, let's see if that works.
Seed users for validation5:23
Okay, so when we do that, I now expect the page to say something like username taken, let's see if that works. We give it another run, and here we go. Yeah, so we're expecting to see a validation error, but we don't. And that would make sense. I haven't yet seeded the users table with a user with that name. Okay, so this is where that laracasts/cypress package comes into play. Let's go ahead and say cypress.create a user. Here's the model, and I'm going to set the username equal to that username. And let's also do an email.
Here's the model, and I'm going to set the username equal to that username. And let's also do an email. So we'll say email that doesn't exist at example.com. All right, so remember, this is going to create a model factory. All right, so now our users table has a record with that username, which means hopefully this should now pass. We come on back, we give it a run, excuse me, and there we go. You can see that error, and the test passes. All right, let's do the same thing. We'll duplicate it one more time, and we'll do this for the email.
All right, let's do the same thing. We'll duplicate it one more time, and we'll do this for the email. So this time, if I provide an email of one that already exists, then it should say email taken. So we come on back, and yeah, it fails with a 500 error. And this makes sense when you think about it. Right up here, we created a User, and then we tried to create that exact same User again. We weren't refreshing the database before every test. So instead, why don't we grab all of that and do it a single time?
We weren't refreshing the database before every test. So instead, why don't we grab all of that and do it a single time? because I think it's only necessary once for all of these tests. So I will put it in a before block. This will run a single time before all of these tests, whereas beforeEach will run once before every single test. Okay, so now we only create it once, but think about it. It's still going to fail because we haven't yet refreshed the database. If I come on back, it's still failing. Okay, let's say right up here, before any of these run,
If I come on back, it's still failing. Okay, let's say right up here, before any of these run, let's refresh my database. And again, for my project, I also need to seed the database. Okay, so now, let's give it another run, and there we go. Everything's passing, and there is the email taken validation error. Okay, let's come on back. What else can we work on? It redirects authenticated users. So let's say if I already have this User signed in,
Redirect authenticated users7:44
It redirects authenticated users. So let's say if I already have this User signed in, then when they visit the signup page, I'm going to assert that they are redirected to somewhere else. Now, we should have an assertions file in your Cypress support directory. I include one. This gives us a more familiar assertRedirect command. But if you don't want to use that, you're just saying Cypress, get the current location object, give me the path name, and I just want to make sure that equals the path I provide you.
get the current location object, give me the pathname, and I just want to make sure that equals the path I provide you. Same thing. You could also use the URL. So if I come on back, I could say assertRedirect, and the URL, I believe, is something like, it goes to your plan page. Maybe that. Let's give it a shot. So here we go, and yeah, we can see everything's running. And that redirects authenticatedUser test does work as well.
So here we go, and yeah, we can see everything's running. And that redirects authenticated User test does work as well. You'll see it redirected us to your subscription page. Great. So now, let's see, it redirects, that works, it loads the signup page. We haven't done the full happy path yet, but we do have the validation checks. We could even wrap those within a describe block, just to make it crystal clear, and then it displays an error message if the card is declined. Okay, so I'm going to put that up here, just to clean things up a little bit. Okay, so this is going to be our happy path.
Happy path with Stripe iframe9:30
I'm going to show you how to deal with iframest being loaded in. And then of course, we need to provide the email, the username, the password, and click register. Okay, so we'll start with these. We can say getUsername, you already know how to do this. Type John Doe, and then get the email address, and type johndoeatexample.com. Then get the password, and type something. And then we want to press the register button. So one way to do this, is if you have an ID on there, of course do that. But you can also say, find the button that says register,
because this is nested within an iframe that a stripe is loading. So just to make it crystal clear, if I were to say, get the input with a name of cardNumber, and type this, that is not going to work. It won't be able to track it down. Let's do only that test and give it a shot. So it's running. And yeah, you'll see right up here, it wasn't able to fill out that input at all. And in fact, it couldn't even track it down. So we'll need to give that special attention. Until then, I have a helper called enterStripeCard.
Your card was declined. Okay, so at this point, I think we're mostly good to go. Let's have a look. It redirects authenticated users elsewhere. Works. It loads the signup page. Of course, that works. It allows a User to sign up the happy path. It works. It displays an error message if the card is declined.
It works. It displays an error message if the card is declined. That works. And then for validation, it displays username and email validation errors. So now the only remaining thing you got to be careful of is, think about it. Can you see the issue here? It allows the User to sign up. The happy path is working. So that means we are creating a User in our system named John Doe. But then down here, we try to create another User named John Doe.
So that means we are creating a User in our system named John Doe. But then down here, we try to create another User named John Doe. But think about it. One already exists, and we're not refreshing the database before every single test. So you would either need to clear that out or use a unique username. And this is where you have to be careful, and you sort of have to measure it. Yes, we could solve this problem completely by saying beforeEach. But it also comes with the cost of longer tests, especially for a large project. If you're going to refresh the database and seed it, it takes a little bit of time. So just make sure you're thoughtful here.
You would never again have a test that visits the registration page, signs up, provides the details, submits it, and then you begin your test. Don't do that anymore. Just log in.
