whew!!!, last chapter is a long one!
now, we are going to implement sign out.
1. no wonders, we will start from TDD.
describe "DELETE 'destroy'" do
it "should sign a user out" do
test_sign_in(Factory(:user))
delete :destroy
controller.should_not be_signed_in
response.should redirect_to(root_path)
end
end
now we define the test_sign_in method in the spec_helper.
RSpec.configure do |config|
def test_sign_in(user)
controller.sign_in(user)
end
end
2. the destroy function in controller:
def destroy
sign_out
redirect_to root_path
end
3. the sign_out fuction in sessions_helper.rb
def sign_out
cookies.delete(:remember_token)
self.current_user = nil
end
4. sign in upon sign up.
let's first write a test to test that a signup user is auto signed in.
describe Usercontroller do
describe "POST 'create'" do
it "should sign the user in" do
post :create, :user => @attr
controller.should be_signed_in
end
end
end
then we just need to add a line of code to the User models create method:
if @user.save
sign_in @user
flash[:success] = "Welcom....."
redirect_to @user
else
.....
end
5. next, we will change the layout links, so that after user signed in, the link text change to "sign out"
although what we want to change is views, we can still strat from TDD of integration test.
luckily, we already have Layout links integration test.
describe "Layout links" do
describe "when not signed in" do
it "should have a sign in link" do
visit root_path
response.should have_selector("a", :href => signin_path, :content => "Sign in")
end
end
describe "when signed in" do
before(:each) do
@user = Factory(:user)
visit signin_path
fill_in :email, :with => @user.email
.....
click_button
end
it "should have a sign out link" do
visit root_path
reponse.should have_selector("a", :href => signout_path, :content => "Sign out")
end
it "should have a profile link" do
visit root_path
response.should have_selector("a", :href => user_path(@user), :content => "Profile")
end
end
now it is time the change the layout header, to change the link according to signed in or not.
<% if signed_in? %>
<li><%= link_to "Sign out", signout_path, :method => :delete %></li>
<%else%>
<li><%= link_to "Sign in", signin_path%></li>
<%end%>
for the view, need to add the profile link:
link_to "Profile", current_user
you can see that rails allow to specify a object to stand for the url
6. now we can add a integration test for both sign in and sign out.
I'll put this test in to users_spec.rb integration test.
describe "sign in/out" do
describe "failure" do
it "should not sign a user in" do
visit signin_path
fill_in :email, :with =>""
fill_in :password, :with => ""
click_button
response.should have_selector("div.flash.error", :content => "Invalid")
end
end
describe "success" do
it "should sign user in and out" do
user = Factory(:user)
visit signin_path
fill_in :email, :wtih => user.email
fill_in :password, :with => user.password
click_button
controller.should be_signed_in
click_link "Sign out"
controller.should_not be_signed_in
end
end
end
please take special attention to the code:
click_link "Sign out"
by this singly line of code, it actuall tested the route, the link text, the url, and the changing of the layout link,
I like this test method very much!!
click_link "Sign out"