7 days of WordPress plugins, themes & templates - for free!* Unlimited asset downloads! Start 7-Day Free Trial
FREELessons: 17Length: 2.7 hours

Next lesson playing in 5 seconds

  • Overview
  • Transcript

2.9 Consolidate the Login Process Into the Application, Part 1

Now that the specification is fulfilled in terms of the operations, we need to integrate all of those different components into one single app. As you can see, I already have a test suite in the api_test file. It had to dummy tests, which I just deleted. Let's just start over with the file. We have this include Rack Test Methods, which we'll use to test against the actual Sinatra application. By the way, we should go to the gem file and include the rack_test gem like so. Check the source code that you downloaded. You will have to include the rack_test gem like this. But you will need to acquire it like this. When that's done, just type in the bundle command and you will be able to run the test smoothly. We have a username here and a password along with a service variable. Before we run any test whatsoever, you will need to clear the applications cookies. This is very important to maintain isolation between tests. So, in line 14, we are going to describe a cold login process. There's nothing happening. We're gonna start from the very bottom. The test says that we should be allowed to login. So if you go to the slash login route, we should have a 200 response. Of course that if you go here, you will see that the route is indeed a 404 response. The route doesn't exist. So let's go there, really quick. Let's open the app file, and as you can see here, we don't have that route. Let's start by introducing it. Slash login is just like that. If we run the tests now, the route will indeed exist and the test will pass. That is because we have the second test. The second test asserts that the body of the response should include an input like this one. If you run the tests now, you will see that the body will be empty. We expected the empty response to include that input. So, in order to solve this issue, I am going to plain old create a login template. Lets go ahead and do that. Lets go to lib > api > app > views. Let's create that login.haml template right away. Let's type in a header first. For example, login. And let's just do the entire form. Let's pass in the username and password, and all of the components necessary. So the action for this form should be login the same way but the method should be post. If you read the specification for the protocol, you will know that this is the route to go. Let's create a couple of paragraphs. The first one should contain an input that is of type text, which will hold the username field. So you type in name and then username like so. The next thing should be to provide a password field. So, let's just pass it in. Type equals password and the name should also be password. By the way, we are going to use a username variable because that's what the protocol specifies. However, in the user model, we are using the email field. We're going to map the two together. At the end, we're just going to place a button which will just read login. I think that's appropriate. But most importantly, we should have an input of type hidden and the name for it should be lt. Also, its value should be the contents of the lt instance variable that we're going to create in the actual route. One last thing. We should provide the service parameter as it's told in the specification. So, in here, we'll use the service instance variable. Now, that's out of the way, let's run the tests again. Okay, so, we expected this entire piece of content to include this particular string. You might think, well, it is there, isn't it? Well, one thing is for sure. The name is there, the input of type hidden is there. But the value is different. That means that we need to include this value, the instance variable. Let's go there really quick, and create that lt variable which will be a login ticket that's generated. You know that this login ticket should be provided by a service. So the service will have a login_ticket. Let's go over that really quick. I'm gonna open that service in particular, and then you should know that this generate login_ticket returns a ticket. Oh, not really a login ticket. So let's go back to the app and here we should replace this with service.ticket. This service variable will be instantiated here in the route. So service equals Api, Service, Login.new. And we're going to call the call method. Because it doesn't have any arguments, it's going to generate a ticket for us. Let's run the tests now and the result will be much different. Oh, what do you know. You can see that we are printing the contents of the login ticket object, not really the name. So let's just add in name, and this should be good to go. Okay, there you go. We're reaching a good pace. Let's keep it up. Let's go back to the test. So these two are already in. And let's focus our attention on the following. Oh, by the way, I forgot something. We didn't test for this, but we could go ahead and include that service variable. Let's go there really quick and provide that service instance variable, which will be the result of perams, service. After all, the service will be a parameter in the URL. Also, don't forget that this instance variable is not the same as this service variable. Okay? So let's move on to the test that we were supposed to go. In this one, we are required a username to be passed in. And if you take a look at the other two, we are going to require a password to be passed in, as well as the login ticket. So I'm going to in comment all of these three tests, and run them at once. You can see that all three will fail, well first of all because the route isn't there. Let's go ahead and fix that, by providing a post, slash login route. There you go. Now let's figure out what the next error is. You can see that we get 200 but we should expect a 422. That's because we need to establish a status 422 if there is either no username, or no password, or no login ticket. So let's do that. Let's create a private method down below called all_inputs_present. This method will validate whether there exists a params, username. There you go, and perimeters password. And also, the login ticket, so params, lt. So, we should check whether all of these exist, and they are not empty. So, we'll do something like this. Params, username different than an empty string, and we're going to do this for the remaining ones. So I'll change this to password and this one to lt because there's a chance that you might send an empty piece of content, but it's not nill nonetheless. So we'll do this. Now let's just complement the information on line 16. If all_inputs_present or, rather, unless all inputs are present. Let's run the tests, and it seems that we have a syntax error. Let's see if, okay, let's just pass that to the top and run the test again. Well, what do you know? All tests are passing. We've managed to cover all three tests at once, because these are all very, very similar. Now that these are done, let's move on to the following. Let me push this to the top in order for us to get a better glance at what's coming. So this one is all about the ticket granting ticket on a cookie. Let's see. We are going to instantiate a new user. So just persist a new user on the database so that we can have a successful login. We have a login_ticket that's already been populated. And then, we're going to submit a new request with all three pieces of data. And at the end, we should have a cookie in the cookie_jar. This is a helper method available in back test. The rack_mock_session contains a cookie_jar. And the cookie_jar allows us to fetch a particular cookie based on its name, and all we want to do is assert that it won't be nil, that it exists. So, let's take care of that right away. I'm gonna go ahead and run the tests, and you can see that it expected nil to not be nil. So it means that we don't have a cookie established on a successful authentication attempt. Let's go to the post route and change this a little bit. So, if all inputs are present, then we are going to do something. Otherwise, we are just going to print out the status like you just see here. Okay. Now, if all of the inputs are present, we need to know if they are valid. Were going to create a new service variable which is going to be Api, double colon, Services, double colon, Login.new, and we're going to pass information this time. So username will be username, or rather params, username. Then we're going to establish the password as well. So params, password. And also the login_ticket_name, which will be params, lt. We had this planned all along. Let me just indent this really quick so it is more readable. There you go. Let's call the call method and check whether the service has been successful. So, if the status of the service is okay, then we're going to do something. Let me just put a quick comment and see whether we have any issues. About the integration of everything. You can see that nil is still expected to not be nil. Well, this means that we are still in the good track. It accepted all these arguments, the call method was issued. And, if the service is okay, then we should create a cookie. Because we worked the service all the way to meet our requirements, all we need to do here is to set the cookie. So, we're gonna use the response.set_cookie. And then, the token first so C-A-S-T-G-C, and then the value. Which value should it be? Well we just reach out to the services.ticket_granting_ticket and then the name. Because that's what we need to pass through. Let's run the tests. And there you go. It's passing now. Because of this, we know that the service reached an okay status. And now just so you know, I'm going to create a binding here so that you can see the cookie being sent, or rather let me just base that below. So that we can see all of the cookies in the response and not just the services content. Okay, so as you can see here, I'm able to check the contents of the service. There you go. The service ticket is there on top, the login_ticket_name, and also the ticket_granting_ticket. This is pretty good. Let me just clear this and type in the response method. You can see that the set cookie parameter is set with a CASTGC cookie. The value is the exact same one as we had in the service. So, the cookie's there. And as you can see, the tests are green. So, this means that the cookie is indeed set. This is great news. We should now focus our attention on the remaining tests. Let me just close these up, and focus on this one. We are going to perform the very same kind of requests. We're posting a new login attempt, username, password, and login ticket are present. And we should provide a location header, which should match that ticket. So this just means that the service ticket will be part of the URL to which we should redirect. Let's run this test and you will see that it is going to fail because it expected that. Now let's go to the application and in here, in the service status condition of being okay, we should provide the location. But how do we do that? Well, we use the redirect option. That's part of Sinatra, as you are aware. So, we should pass a string here which is going to match the new location. But, which strain should it be? Well, that's easy. Since we are aware of the params service value here, we should also provide the ticket, so we use end ticket equals, and then the value of the ticket in the service as well. Because we have that generated in this service, we can just shot that in, like so, service.service_ticket.name. Let's see if this works by running the tests, again. Well, we now have two different failing expectations. We're gonna work these out in part two. Stick around.

Back to the top