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 | -# 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 | 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 | 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 | 10 | end | ... | ... |
| ... | ... | @@ -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 @@ |
| 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 @@ |
| 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 @@ |
| 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 @@ |
| 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 @@ |
| 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 | 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 | 2 | def path_to(page_name) |
| 9 | 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 | 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 | 18 | end |
| 24 | 19 | end |
| 25 | 20 | end | ... | ... |
| ... | ... | @@ -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