Commit f30baf85a361a5bc424ce259784a9f5755364854
1 parent
67628f5f
Exists in
master
and in
1 other branch
added clearance, including cucumber features. removed test/mocks.
Showing
17 changed files
with
301 additions
and
55 deletions
Show diff stats
app/controllers/application_controller.rb
config/initializers/action_mailer_configs.rb
config/initializers/mocks.rb
| @@ -1,10 +0,0 @@ | @@ -1,10 +0,0 @@ | ||
| 1 | -# Rails 2 doesn't like mocks | ||
| 2 | - | ||
| 3 | -# This callback will run before every request to a mock in development mode, | ||
| 4 | -# or before the first server request in production. | ||
| 5 | - | ||
| 6 | -Rails.configuration.to_prepare do | ||
| 7 | - Dir[File.join(RAILS_ROOT, 'test', 'mocks', RAILS_ENV, '*.rb')].each do |f| | ||
| 8 | - load f | ||
| 9 | - end | ||
| 10 | -end |
config/routes.rb
| 1 | ActionController::Routing::Routes.draw do |map| | 1 | ActionController::Routing::Routes.draw do |map| |
| 2 | 2 | ||
| 3 | - # Sample resource route (maps HTTP verbs to controller actions automatically): | ||
| 4 | - # map.resources :products | ||
| 5 | - | ||
| 6 | - # Sample resource route with options: | ||
| 7 | - # map.resources :products, :member => { :short => :get, :toggle => :post }, :collection => { :sold => :get } | ||
| 8 | - | ||
| 9 | - # Sample resource route with sub-resources: | ||
| 10 | - # map.resources :products, :has_many => [ :comments, :sales ], :has_one => :seller | ||
| 11 | - | ||
| 12 | - # Sample resource route within a namespace: | ||
| 13 | - # map.namespace :admin do |admin| | ||
| 14 | - # # Directs /admin/products/* to Admin::ProductsController (app/controllers/admin/products_controller.rb) | ||
| 15 | - # admin.resources :products | ||
| 16 | - # end | ||
| 17 | - | ||
| 18 | - # You can have the root of your site routed with map.root -- just remember to delete public/index.html. | ||
| 19 | - # map.root :controller => "welcome" | 3 | + map.root :controller => "clearance/users", :action => "new" |
| 20 | 4 | ||
| 21 | # See how all your routes lay out with "rake routes" | 5 | # See how all your routes lay out with "rake routes" |
| 22 | 6 | ||
| 23 | - # map.home '', :controller => 'home', :action => 'dashboard' | ||
| 24 | - # map.with_options :controller => 'sessions' do |m| | ||
| 25 | - # m.login '/login', :action => 'new' | ||
| 26 | - # m.logout '/logout', :action => 'destroy' | ||
| 27 | - # end | 7 | + # For more information on routes, read: |
| 8 | + # http://guides.rubyonrails.org/routing.html | ||
| 28 | 9 | ||
| 29 | end | 10 | end |
| @@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
| 1 | +class ClearanceCreateUsers < ActiveRecord::Migration | ||
| 2 | + def self.up | ||
| 3 | + create_table(:users) do |t| | ||
| 4 | + t.string :email | ||
| 5 | + t.string :encrypted_password, :limit => 128 | ||
| 6 | + t.string :salt, :limit => 128 | ||
| 7 | + t.string :token, :limit => 128 | ||
| 8 | + t.datetime :token_expires_at | ||
| 9 | + t.boolean :email_confirmed, :default => false, :null => false | ||
| 10 | + end | ||
| 11 | + | ||
| 12 | + add_index :users, [:id, :token] | ||
| 13 | + add_index :users, :email | ||
| 14 | + add_index :users, :token | ||
| 15 | + end | ||
| 16 | + | ||
| 17 | + def self.down | ||
| 18 | + drop_table :users | ||
| 19 | + end | ||
| 20 | +end |
| @@ -0,0 +1,33 @@ | @@ -0,0 +1,33 @@ | ||
| 1 | +Feature: Password reset | ||
| 2 | + In order to sign in even if user forgot their password | ||
| 3 | + A user | ||
| 4 | + Should be able to reset it | ||
| 5 | + | ||
| 6 | + Scenario: User is not signed up | ||
| 7 | + Given no user exists with an email of "email@person.com" | ||
| 8 | + When I request password reset link to be sent to "email@person.com" | ||
| 9 | + Then I should see "Unknown email" | ||
| 10 | + | ||
| 11 | + Scenario: User is signed up and requests password reset | ||
| 12 | + Given I signed up with "email@person.com/password" | ||
| 13 | + When I request password reset link to be sent to "email@person.com" | ||
| 14 | + Then I should see "instructions for changing your password" | ||
| 15 | + And a password reset message should be sent to "email@person.com" | ||
| 16 | + | ||
| 17 | + Scenario: User is signed up updated his password and types wrong confirmation | ||
| 18 | + Given I signed up with "email@person.com/password" | ||
| 19 | + When I follow the password reset link sent to "email@person.com" | ||
| 20 | + And I update my password with "newpassword/wrongconfirmation" | ||
| 21 | + Then I should see error messages | ||
| 22 | + And I should be signed out | ||
| 23 | + | ||
| 24 | + Scenario: User is signed up and updates his password | ||
| 25 | + Given I signed up with "email@person.com/password" | ||
| 26 | + When I follow the password reset link sent to "email@person.com" | ||
| 27 | + And I update my password with "newpassword/newpassword" | ||
| 28 | + Then I should be signed in | ||
| 29 | + When I sign out | ||
| 30 | + Then I should be signed out | ||
| 31 | + And I sign in as "email@person.com/newpassword" | ||
| 32 | + Then I should be signed in | ||
| 33 | + |
| @@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
| 1 | +Feature: Sign in | ||
| 2 | + In order to get access to protected sections of the site | ||
| 3 | + A user | ||
| 4 | + Should be able to sign in | ||
| 5 | + | ||
| 6 | + Scenario: User is not signed up | ||
| 7 | + Given no user exists with an email of "email@person.com" | ||
| 8 | + When I go to the sign in page | ||
| 9 | + And I sign in as "email@person.com/password" | ||
| 10 | + Then I should see "Bad email or password" | ||
| 11 | + And I should be signed out | ||
| 12 | + | ||
| 13 | + Scenario: User is not confirmed | ||
| 14 | + Given I signed up with "email@person.com/password" | ||
| 15 | + When I go to the sign in page | ||
| 16 | + And I sign in as "email@person.com/password" | ||
| 17 | + Then I should see "User has not confirmed email" | ||
| 18 | + And I should be signed out | ||
| 19 | + | ||
| 20 | + Scenario: User enters wrong password | ||
| 21 | + Given I am signed up and confirmed as "email@person.com/password" | ||
| 22 | + When I go to the sign in page | ||
| 23 | + And I sign in as "email@person.com/wrongpassword" | ||
| 24 | + Then I should see "Bad email or password" | ||
| 25 | + And I should be signed out | ||
| 26 | + | ||
| 27 | + Scenario: User signs in successfully | ||
| 28 | + Given I am signed up and confirmed as "email@person.com/password" | ||
| 29 | + When I go to the sign in page | ||
| 30 | + And I sign in as "email@person.com/password" | ||
| 31 | + Then I should see "Signed in" | ||
| 32 | + And I should be signed in | ||
| 33 | + | ||
| 34 | + Scenario: User signs in and checks "remember me" | ||
| 35 | + Given I am signed up and confirmed as "email@person.com/password" | ||
| 36 | + When I go to the sign in page | ||
| 37 | + And I sign in with "remember me" as "email@person.com/password" | ||
| 38 | + Then I should see "Signed in" | ||
| 39 | + And I should be signed in | ||
| 40 | + When I return next time | ||
| 41 | + Then I should be signed in | ||
| 42 | + |
| @@ -0,0 +1,23 @@ | @@ -0,0 +1,23 @@ | ||
| 1 | +Feature: Sign out | ||
| 2 | + To protect my account from unauthorized access | ||
| 3 | + A signed in user | ||
| 4 | + Should be able to sign out | ||
| 5 | + | ||
| 6 | + Scenario: User signs out | ||
| 7 | + Given I am signed up and confirmed as "email@person.com/password" | ||
| 8 | + When I sign in as "email@person.com/password" | ||
| 9 | + Then I should be signed in | ||
| 10 | + And I sign out | ||
| 11 | + Then I should see "Signed out" | ||
| 12 | + And I should be signed out | ||
| 13 | + | ||
| 14 | + Scenario: User who was remembered signs out | ||
| 15 | + Given I am signed up and confirmed as "email@person.com/password" | ||
| 16 | + When I sign in with "remember me" as "email@person.com/password" | ||
| 17 | + Then I should be signed in | ||
| 18 | + And I sign out | ||
| 19 | + Then I should see "Signed out" | ||
| 20 | + And I should be signed out | ||
| 21 | + When I return next time | ||
| 22 | + Then I should be signed out | ||
| 23 | + |
| @@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
| 1 | +Feature: Sign up | ||
| 2 | + In order to get access to protected sections of the site | ||
| 3 | + A user | ||
| 4 | + Should be able to sign up | ||
| 5 | + | ||
| 6 | + Scenario: User signs up with invalid data | ||
| 7 | + When I go to the sign up page | ||
| 8 | + And I fill in "Email" with "invalidemail" | ||
| 9 | + And I fill in "Password" with "password" | ||
| 10 | + And I fill in "Confirm password" with "" | ||
| 11 | + And I press "Sign Up" | ||
| 12 | + Then I should see error messages | ||
| 13 | + | ||
| 14 | + Scenario: User signs up with valid data | ||
| 15 | + When I go to the sign up page | ||
| 16 | + And I fill in "Email" with "email@person.com" | ||
| 17 | + And I fill in "Password" with "password" | ||
| 18 | + And I fill in "Confirm password" with "password" | ||
| 19 | + And I press "Sign Up" | ||
| 20 | + Then I should see "instructions for confirming" | ||
| 21 | + And a confirmation message should be sent to "email@person.com" | ||
| 22 | + | ||
| 23 | + Scenario: User confirms his account | ||
| 24 | + Given I signed up with "email@person.com/password" | ||
| 25 | + When I follow the confirmation link sent to "email@person.com" | ||
| 26 | + Then I should see "Confirmed email and signed in" | ||
| 27 | + And I should be signed in | ||
| 28 | + |
| @@ -0,0 +1,110 @@ | @@ -0,0 +1,110 @@ | ||
| 1 | +# General | ||
| 2 | + | ||
| 3 | +Then /^I should see error messages$/ do | ||
| 4 | + assert_match /error(s)? prohibited/m, response.body | ||
| 5 | +end | ||
| 6 | + | ||
| 7 | +# Database | ||
| 8 | + | ||
| 9 | +Given /^no user exists with an email of "(.*)"$/ do |email| | ||
| 10 | + assert_nil User.find_by_email(email) | ||
| 11 | +end | ||
| 12 | + | ||
| 13 | +Given /^I signed up with "(.*)\/(.*)"$/ do |email, password| | ||
| 14 | + user = Factory :user, | ||
| 15 | + :email => email, | ||
| 16 | + :password => password, | ||
| 17 | + :password_confirmation => password | ||
| 18 | +end | ||
| 19 | + | ||
| 20 | +Given /^I am signed up and confirmed as "(.*)\/(.*)"$/ do |email, password| | ||
| 21 | + user = Factory :email_confirmed_user, | ||
| 22 | + :email => email, | ||
| 23 | + :password => password, | ||
| 24 | + :password_confirmation => password | ||
| 25 | +end | ||
| 26 | + | ||
| 27 | +# Session | ||
| 28 | + | ||
| 29 | +Then /^I should be signed in$/ do | ||
| 30 | + assert controller.signed_in? | ||
| 31 | +end | ||
| 32 | + | ||
| 33 | +Then /^I should be signed out$/ do | ||
| 34 | + assert ! controller.signed_in? | ||
| 35 | +end | ||
| 36 | + | ||
| 37 | +When /^session is cleared$/ do | ||
| 38 | + request.reset_session | ||
| 39 | + controller.instance_variable_set(:@_current_user, nil) | ||
| 40 | +end | ||
| 41 | + | ||
| 42 | +# Emails | ||
| 43 | + | ||
| 44 | +Then /^a confirmation message should be sent to "(.*)"$/ do |email| | ||
| 45 | + user = User.find_by_email(email) | ||
| 46 | + sent = ActionMailer::Base.deliveries.first | ||
| 47 | + assert_equal [user.email], sent.to | ||
| 48 | + assert_match /confirm/i, sent.subject | ||
| 49 | + assert !user.token.blank? | ||
| 50 | + assert_match /#{user.token}/, sent.body | ||
| 51 | +end | ||
| 52 | + | ||
| 53 | +When /^I follow the confirmation link sent to "(.*)"$/ do |email| | ||
| 54 | + user = User.find_by_email(email) | ||
| 55 | + visit new_user_confirmation_path(:user_id => user, :token => user.token) | ||
| 56 | +end | ||
| 57 | + | ||
| 58 | +Then /^a password reset message should be sent to "(.*)"$/ do |email| | ||
| 59 | + user = User.find_by_email(email) | ||
| 60 | + sent = ActionMailer::Base.deliveries.first | ||
| 61 | + assert_equal [user.email], sent.to | ||
| 62 | + assert_match /password/i, sent.subject | ||
| 63 | + assert !user.token.blank? | ||
| 64 | + assert_match /#{user.token}/, sent.body | ||
| 65 | +end | ||
| 66 | + | ||
| 67 | +When /^I follow the password reset link sent to "(.*)"$/ do |email| | ||
| 68 | + user = User.find_by_email(email) | ||
| 69 | + visit edit_user_password_path(:user_id => user, :token => user.token) | ||
| 70 | +end | ||
| 71 | + | ||
| 72 | +When /^I try to change the password of "(.*)" without token$/ do |email| | ||
| 73 | + user = User.find_by_email(email) | ||
| 74 | + visit edit_user_password_path(:user_id => user) | ||
| 75 | +end | ||
| 76 | + | ||
| 77 | +Then /^I should be forbidden$/ do | ||
| 78 | + assert_response :forbidden | ||
| 79 | +end | ||
| 80 | + | ||
| 81 | +# Actions | ||
| 82 | + | ||
| 83 | +When /^I sign in( with "remember me")? as "(.*)\/(.*)"$/ do |remember, email, password| | ||
| 84 | + When %{I go to the sign in page} | ||
| 85 | + And %{I fill in "Email" with "#{email}"} | ||
| 86 | + And %{I fill in "Password" with "#{password}"} | ||
| 87 | + And %{I check "Remember me"} if remember | ||
| 88 | + And %{I press "Sign In"} | ||
| 89 | +end | ||
| 90 | + | ||
| 91 | +When /^I sign out$/ do | ||
| 92 | + visit '/session', :delete | ||
| 93 | +end | ||
| 94 | + | ||
| 95 | +When /^I request password reset link to be sent to "(.*)"$/ do |email| | ||
| 96 | + When %{I go to the password reset request page} | ||
| 97 | + And %{I fill in "Email address" with "#{email}"} | ||
| 98 | + And %{I press "Reset password"} | ||
| 99 | +end | ||
| 100 | + | ||
| 101 | +When /^I update my password with "(.*)\/(.*)"$/ do |password, confirmation| | ||
| 102 | + And %{I fill in "Choose password" with "#{password}"} | ||
| 103 | + And %{I fill in "Confirm password" with "#{confirmation}"} | ||
| 104 | + And %{I press "Save this password"} | ||
| 105 | +end | ||
| 106 | + | ||
| 107 | +When /^I return next time$/ do | ||
| 108 | + When %{session is cleared} | ||
| 109 | + And %{I go to the homepage} | ||
| 110 | +end |
features/support/paths.rb
| 1 | module NavigationHelpers | 1 | module NavigationHelpers |
| 2 | - # Maps a name to a path. Used by the | ||
| 3 | - # | ||
| 4 | - # When /^I go to (.+)$/ do |page_name| | ||
| 5 | - # | ||
| 6 | - # step definition in webrat_steps.rb | ||
| 7 | - # | ||
| 8 | def path_to(page_name) | 2 | def path_to(page_name) |
| 9 | case page_name | 3 | case page_name |
| 10 | - | ||
| 11 | - when /the homepage/ | ||
| 12 | - '/' | ||
| 13 | - | ||
| 14 | - # Add more mappings here. | ||
| 15 | - # Here is a more fancy example: | ||
| 16 | - # | ||
| 17 | - # when /^(.*)'s profile page$/i | ||
| 18 | - # user_profile_path(User.find_by_login($1)) | 4 | + |
| 5 | + when /the homepage/i | ||
| 6 | + root_path | ||
| 7 | + when /the sign up page/i | ||
| 8 | + new_user_path | ||
| 9 | + when /the sign in page/i | ||
| 10 | + new_session_path | ||
| 11 | + when /the password reset request page/i | ||
| 12 | + new_password_path | ||
| 13 | + | ||
| 14 | + # Add more page name => path mappings here | ||
| 19 | 15 | ||
| 20 | else | 16 | else |
| 21 | - raise "Can't find mapping from \"#{page_name}\" to a path.\n" + | ||
| 22 | - "Now, go and add a mapping in #{__FILE__}" | 17 | + raise "Can't find mapping from \"#{page_name}\" to a path." |
| 23 | end | 18 | end |
| 24 | end | 19 | end |
| 25 | end | 20 | end |
| @@ -0,0 +1,13 @@ | @@ -0,0 +1,13 @@ | ||
| 1 | +Factory.sequence :email do |n| | ||
| 2 | + "user#{n}@example.com" | ||
| 3 | +end | ||
| 4 | + | ||
| 5 | +Factory.define :user do |user| | ||
| 6 | + user.email { Factory.next :email } | ||
| 7 | + user.password { "password" } | ||
| 8 | + user.password_confirmation { "password" } | ||
| 9 | +end | ||
| 10 | + | ||
| 11 | +Factory.define :email_confirmed_user, :parent => :user do |user| | ||
| 12 | + user.email_confirmed { true } | ||
| 13 | +end |
test/mocks/development/.keep
test/mocks/test/.keep