aihs_devise_invitable 0.4.rc

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. data/.gitignore +27 -0
  2. data/Gemfile +8 -0
  3. data/Gemfile.lock +117 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +187 -0
  6. data/Rakefile +57 -0
  7. data/app/controllers/devise/invitations_controller.rb +47 -0
  8. data/app/views/devise/invitations/edit.html.erb +14 -0
  9. data/app/views/devise/invitations/new.html.erb +12 -0
  10. data/app/views/devise/mailer/invitation.html.erb +8 -0
  11. data/app/views/devise/mailer/invitation_instructions.html.erb +8 -0
  12. data/config/locales/en.yml +9 -0
  13. data/devise_invitable.gemspec +143 -0
  14. data/lib/devise_invitable.rb +16 -0
  15. data/lib/devise_invitable/controllers/helpers.rb +7 -0
  16. data/lib/devise_invitable/controllers/url_helpers.rb +24 -0
  17. data/lib/devise_invitable/mailer.rb +14 -0
  18. data/lib/devise_invitable/model.rb +130 -0
  19. data/lib/devise_invitable/rails.rb +13 -0
  20. data/lib/devise_invitable/routes.rb +13 -0
  21. data/lib/devise_invitable/schema.rb +33 -0
  22. data/lib/devise_invitable/version.rb +3 -0
  23. data/lib/generators/active_record/devise_invitable_generator.rb +13 -0
  24. data/lib/generators/active_record/templates/migration.rb +20 -0
  25. data/lib/generators/devise_invitable/devise_invitable_generator.rb +16 -0
  26. data/lib/generators/devise_invitable/install_generator.rb +35 -0
  27. data/lib/generators/devise_invitable/views_generator.rb +10 -0
  28. data/test/generators_test.rb +45 -0
  29. data/test/integration/invitation_test.rb +107 -0
  30. data/test/integration_tests_helper.rb +58 -0
  31. data/test/mailers/invitation_mail_test.rb +63 -0
  32. data/test/model_tests_helper.rb +41 -0
  33. data/test/models/invitable_test.rb +213 -0
  34. data/test/models_test.rb +32 -0
  35. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  36. data/test/rails_app/app/controllers/application_controller.rb +3 -0
  37. data/test/rails_app/app/controllers/home_controller.rb +4 -0
  38. data/test/rails_app/app/controllers/users_controller.rb +12 -0
  39. data/test/rails_app/app/helpers/application_helper.rb +2 -0
  40. data/test/rails_app/app/models/octopussy.rb +11 -0
  41. data/test/rails_app/app/models/user.rb +4 -0
  42. data/test/rails_app/app/views/home/index.html.erb +0 -0
  43. data/test/rails_app/app/views/layouts/application.html.erb +16 -0
  44. data/test/rails_app/app/views/users/invitations/new.html.erb +15 -0
  45. data/test/rails_app/config.ru +4 -0
  46. data/test/rails_app/config/application.rb +46 -0
  47. data/test/rails_app/config/boot.rb +14 -0
  48. data/test/rails_app/config/database.yml +22 -0
  49. data/test/rails_app/config/environment.rb +5 -0
  50. data/test/rails_app/config/environments/development.rb +26 -0
  51. data/test/rails_app/config/environments/production.rb +49 -0
  52. data/test/rails_app/config/environments/test.rb +35 -0
  53. data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
  54. data/test/rails_app/config/initializers/devise.rb +174 -0
  55. data/test/rails_app/config/initializers/inflections.rb +10 -0
  56. data/test/rails_app/config/initializers/mime_types.rb +5 -0
  57. data/test/rails_app/config/initializers/secret_token.rb +7 -0
  58. data/test/rails_app/config/initializers/session_store.rb +8 -0
  59. data/test/rails_app/config/locales/en.yml +5 -0
  60. data/test/rails_app/config/routes.rb +4 -0
  61. data/test/rails_app/script/rails +6 -0
  62. data/test/routes_test.rb +20 -0
  63. data/test/test_helper.rb +31 -0
  64. metadata +222 -0
@@ -0,0 +1,3 @@
1
+ module DeviseInvitable
2
+ VERSION = '0.4.rc'.freeze
3
+ end
@@ -0,0 +1,13 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ module ActiveRecord
4
+ module Generators
5
+ class DeviseInvitableGenerator < ActiveRecord::Generators::Base
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def copy_devise_migration
9
+ migration_template "migration.rb", "db/migrate/devise_invitable_add_to_#{table_name}"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,20 @@
1
+ class DeviseInvitableAddTo<%= table_name.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ change_table :<%= table_name %> do |t|
4
+ t.string :invitation_token, :limit => 60
5
+ t.datetime :invitation_sent_at
6
+ t.index :invitation_token # for invitable
7
+ end
8
+
9
+ # And allow null encrypted_password and password_salt:
10
+ change_column_null :<%= table_name %>, :encrypted_password, true
11
+ <% if class_name.constantize.columns_hash['password_salt'] -%>
12
+ change_column_null :<%= table_name %>, :password_salt, true
13
+ <% end -%>
14
+ end
15
+
16
+ def self.down
17
+ remove_column :<%= table_name %>, :invitation_sent_at
18
+ remove_column :<%= table_name %>, :invitation_token
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ module DeviseInvitable
2
+ module Generators
3
+ class DeviseInvitableGenerator < Rails::Generators::NamedBase
4
+ namespace "devise_invitable"
5
+
6
+ desc "Add :invitable directive in the given model. Also generate migration for ActiveRecord"
7
+
8
+ def inject_devise_invitable_content
9
+ path = File.join("app", "models", "#{file_path}.rb")
10
+ inject_into_file(path, "invitable, :", :after => "devise :") if File.exists?(path)
11
+ end
12
+
13
+ hook_for :orm
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,35 @@
1
+ module DeviseInvitable
2
+ module Generators
3
+ class InstallGenerator < Rails::Generators::Base
4
+ source_root File.expand_path("../../templates", __FILE__)
5
+ desc "Add DeviseInvitable config variables to the Devise initializer and copy DeviseInvitable locale files to your application."
6
+
7
+ def add_config_options_to_initializer
8
+ devise_initializer_path = "config/initializers/devise.rb"
9
+ if File.exist?(devise_initializer_path)
10
+ old_content = File.read(devise_initializer_path)
11
+
12
+ if old_content.match(Regexp.new(/^\s# ==> Configuration for :invitable\n/))
13
+ false
14
+ else
15
+ inject_into_file(devise_initializer_path, :before => " # ==> Configuration for :confirmable\n") do
16
+ <<-CONTENT
17
+ # ==> Configuration for :invitable
18
+ # The period the generated invitation token is valid, after
19
+ # this period, the invited resource won't be able to accept the invitation.
20
+ # When invite_for is 0 (the default), the invitation won't expire.
21
+ # config.invite_for = 2.weeks
22
+
23
+ CONTENT
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ def copy_locale
30
+ copy_file "../../../config/locales/en.yml", "config/locales/devise_invitable.en.yml"
31
+ end
32
+
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,10 @@
1
+ require 'generators/devise/views_generator'
2
+
3
+ module DeviseInvitable
4
+ module Generators
5
+ class ViewsGenerator < Devise::Generators::ViewsGenerator
6
+ source_root File.expand_path("../../../../app/views", __FILE__)
7
+ desc 'Copies all DeviseInvitable views to your application.'
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,45 @@
1
+ require 'test/test_helper'
2
+ require 'rails/generators'
3
+ require 'generators/devise_invitable/devise_invitable_generator'
4
+
5
+ class GeneratorsTest < ActiveSupport::TestCase
6
+ RAILS_APP_PATH = File.expand_path("../rails_app", __FILE__)
7
+
8
+ test "rails g should include the 3 generators" do
9
+ output = `cd #{RAILS_APP_PATH} && rails g`
10
+ assert output.match(%r|DeviseInvitable:\n devise_invitable\n devise_invitable:install\n devise_invitable:views|)
11
+ end
12
+
13
+ test "rails g devise_invitable:install" do
14
+ output = `cd #{RAILS_APP_PATH} && rails g devise_invitable:install -p`
15
+ assert output.match(%r|inject.+ config/initializers/devise\.rb\n|)
16
+ assert output.match(%r|create.+ config/locales/devise_invitable\.en\.yml\n|)
17
+ end
18
+
19
+ test "rails g devise_invitable:views not scoped" do
20
+ output = `cd #{RAILS_APP_PATH} && rails g devise_invitable:views -p`
21
+ assert output.match(%r|create.+ app/views/devise\n|)
22
+ assert output.match(%r|create.+ app/views/devise/invitations/edit\.html\.erb\n|)
23
+ assert output.match(%r|create.+ app/views/devise/invitations/new\.html\.erb\n|)
24
+ assert output.match(%r|create.+ app/views/devise/mailer/invitation_instructions\.html\.erb\n|)
25
+ end
26
+
27
+ test "rails g devise_invitable:views scoped" do
28
+ output = `cd #{RAILS_APP_PATH} && rails g devise_invitable:views octopussies -p`
29
+ assert output.match(%r|create.+ app/views/octopussies\n|)
30
+ assert output.match(%r|create.+ app/views/octopussies/invitations/edit\.html\.erb\n|)
31
+ assert output.match(%r|create.+ app/views/octopussies/invitations/new\.html\.erb\n|)
32
+ assert output.match(%r|create.+ app/views/octopussies/mailer/invitation_instructions\.html\.erb\n|)
33
+ end
34
+
35
+ test "rails g devise_invitable Octopussy" do
36
+ output = `cd #{RAILS_APP_PATH} && rails g devise_invitable Octopussy -p`
37
+ assert output.match(%r|inject.+ app/models/octopussy\.rb\n|)
38
+ assert output.match(%r|invoke.+ #{DEVISE_ORM}\n|)
39
+ if DEVISE_ORM == :active_record
40
+ assert output.match(%r|create.+ db/migrate/\d{14}_devise_invitable_add_to_octopussies\.rb\n|)
41
+ elsif DEVISE_ORM == :mongoid
42
+ assert !output.match(%r|create.+ db/migrate/\d{14}_devise_invitable_add_to_octopussies\.rb\n|)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,107 @@
1
+ require 'test/test_helper'
2
+ require 'test/integration_tests_helper'
3
+
4
+ class InvitationTest < ActionDispatch::IntegrationTest
5
+ def teardown
6
+ Capybara.reset_sessions!
7
+ end
8
+
9
+ def send_invitation(&block)
10
+ visit new_user_invitation_path
11
+
12
+ fill_in 'user_email', :with => 'user@test.com'
13
+ yield if block_given?
14
+ click_button 'Send an invitation'
15
+ end
16
+
17
+ def set_password(options={}, &block)
18
+ unless options[:visit] == false
19
+ visit accept_user_invitation_path(:invitation_token => options[:invitation_token])
20
+ end
21
+
22
+ fill_in 'user_password', :with => '987654321'
23
+ fill_in 'user_password_confirmation', :with => '987654321'
24
+ yield if block_given?
25
+ click_button 'Set my password'
26
+ end
27
+
28
+ test 'not authenticated user should not be able to send an invitation' do
29
+ get new_user_invitation_path
30
+ assert_redirected_to new_user_session_path
31
+ end
32
+
33
+ test 'authenticated user should be able to send an invitation' do
34
+ sign_in_as_user
35
+
36
+ send_invitation
37
+ assert_equal root_path, current_path
38
+ assert page.has_css?('p#notice', :text => 'An invitation email has been sent to user@test.com.')
39
+ end
40
+
41
+ test 'authenticated user with invalid email should receive an error message' do
42
+ user = create_full_user
43
+ sign_in_as_user(user)
44
+ send_invitation do
45
+ fill_in 'user_email', :with => user.email
46
+ end
47
+
48
+ assert_equal user_invitation_path, current_path
49
+ assert page.has_css?("input[type=text][value='#{user.email}']")
50
+ assert page.has_css?('#error_explanation li', :text => 'Email has already been taken')
51
+ end
52
+
53
+ test 'authenticated user should not be able to visit edit invitation page' do
54
+ sign_in_as_user
55
+
56
+ visit accept_user_invitation_path
57
+
58
+ assert_equal root_path, current_path
59
+ end
60
+
61
+ test 'not authenticated user with invalid invitation token should not be able to set his password' do
62
+ user = create_user
63
+ visit accept_user_invitation_path(:invitation_token => 'invalid_token')
64
+
65
+ assert_equal root_path, current_path
66
+ assert page.has_css?('p#alert', :text => 'The invitation token provided is not valid!')
67
+ end
68
+
69
+ test 'not authenticated user with valid invitation token but invalid password should not be able to set his password' do
70
+ user = create_user(false)
71
+ set_password :invitation_token => user.invitation_token do
72
+ fill_in 'Password confirmation', :with => 'other_password'
73
+ end
74
+ assert_equal user_invitation_path, current_path
75
+ assert page.has_css?('#error_explanation li', :text => 'Password doesn\'t match confirmation')
76
+ assert_nil user.encrypted_password
77
+ end
78
+
79
+ test 'not authenticated user with valid data should be able to change his password' do
80
+ user = create_user(false)
81
+ set_password :invitation_token => user.invitation_token
82
+
83
+ assert_equal root_path, current_path
84
+ assert page.has_css?('p#notice', :text => 'Your password was set successfully. You are now signed in.')
85
+ assert user.reload.valid_password?('987654321')
86
+ end
87
+
88
+ test 'after entering invalid data user should still be able to set his password' do
89
+ user = create_user(false)
90
+ set_password :invitation_token => user.invitation_token do
91
+ fill_in 'Password confirmation', :with => 'other_password'
92
+ end
93
+ assert_equal user_invitation_path, current_path
94
+ assert page.has_css?('#error_explanation')
95
+ assert_nil user.encrypted_password
96
+
97
+ set_password :visit => false
98
+ assert page.has_css?('p#notice', :text => 'Your password was set successfully. You are now signed in.')
99
+ assert user.reload.valid_password?('987654321')
100
+ end
101
+
102
+ test 'sign in user automatically after setting it\'s password' do
103
+ user = create_user(false)
104
+ set_password :invitation_token => user.invitation_token
105
+ assert_equal root_path, current_path
106
+ end
107
+ end
@@ -0,0 +1,58 @@
1
+ class ActionController::IntegrationTest
2
+
3
+ def warden
4
+ request.env['warden']
5
+ end
6
+
7
+ def create_full_user
8
+ @user ||= begin
9
+ user = User.create!(
10
+ :username => 'usertest',
11
+ :email => 'fulluser@test.com',
12
+ :password => '123456',
13
+ :password_confirmation => '123456',
14
+ :created_at => Time.now.utc
15
+ )
16
+ user.confirm!
17
+ user
18
+ end
19
+ end
20
+
21
+ def sign_in_as_user(user = nil)
22
+ user ||= create_full_user
23
+ visit new_user_session_path
24
+ fill_in 'user_email', :with => user.email
25
+ fill_in 'user_password', :with => '123456'
26
+ fill_in 'user_password', :with => user.password
27
+ click_button 'Sign in'
28
+ end
29
+
30
+ def create_user(accept_invitation = true)
31
+ user = User.new :email => 'newuser@test.com'
32
+ user.skip_confirmation!
33
+ user.invitation_token = 'token'
34
+ user.invitation_sent_at = Time.now.utc
35
+ user.save(:validate => false)
36
+ user.accept_invitation! if accept_invitation
37
+ user
38
+ end
39
+
40
+ # Fix assert_redirect_to in integration sessions because they don't take into
41
+ # account Middleware redirects.
42
+ #
43
+ def assert_redirected_to(url)
44
+ assert [301, 302].include?(@integration_session.status),
45
+ "Expected status to be 301 or 302, got #{@integration_session.status}"
46
+
47
+ url = prepend_host(url)
48
+ location = prepend_host(@integration_session.headers["Location"])
49
+ assert_equal url, location
50
+ end
51
+
52
+ protected
53
+
54
+ def prepend_host(url)
55
+ url = "http://#{request.host}#{url}" if url[0] == ?/
56
+ url
57
+ end
58
+ end
@@ -0,0 +1,63 @@
1
+ require 'test/test_helper'
2
+ require 'test/model_tests_helper'
3
+
4
+ class InvitationMailTest < ActionMailer::TestCase
5
+
6
+ def setup
7
+ setup_mailer
8
+ Devise.mailer_sender = 'test@example.com'
9
+ end
10
+
11
+ def user
12
+ @user ||= begin
13
+ user = create_user_with_invitation('token')
14
+ user.invite!
15
+ user
16
+ end
17
+ end
18
+
19
+ def mail
20
+ @mail ||= begin
21
+ user
22
+ ActionMailer::Base.deliveries.last
23
+ end
24
+ end
25
+
26
+ test 'email sent after reseting the user password' do
27
+ assert_not_nil mail
28
+ end
29
+
30
+ test 'content type should be set to html' do
31
+ assert_equal 'text/html; charset=UTF-8', mail.content_type
32
+ end
33
+
34
+ test 'send invitation to the user email' do
35
+ assert_equal [user.email], mail.to
36
+ end
37
+
38
+ test 'setup sender from configuration' do
39
+ assert_equal ['test@example.com'], mail.from
40
+ end
41
+
42
+ test 'setup subject from I18n' do
43
+ store_translations :en, :devise => { :mailer => { :invitation_instructions => { :subject => 'Localized Invitation' } } } do
44
+ assert_equal 'Localized Invitation', mail.subject
45
+ end
46
+ end
47
+
48
+ test 'subject namespaced by model' do
49
+ store_translations :en, :devise => { :mailer => { :invitation_instructions => { :user_subject => 'User Invitation' } } } do
50
+ assert_equal 'User Invitation', mail.subject
51
+ end
52
+ end
53
+
54
+ test 'body should have user info' do
55
+ assert_match /#{user.email}/, mail.body
56
+ end
57
+
58
+ test 'body should have link to confirm the account' do
59
+ host = ActionMailer::Base.default_url_options[:host]
60
+ invitation_url_regexp = %r{<a href=\"http://#{host}/users/invitation/accept\?invitation_token=#{user.invitation_token}">}
61
+ assert_match invitation_url_regexp, mail.body
62
+ end
63
+ end
@@ -0,0 +1,41 @@
1
+ class ActiveSupport::TestCase
2
+ def setup_mailer
3
+ ActionMailer::Base.deliveries = []
4
+ end
5
+
6
+ def store_translations(locale, translations, &block)
7
+ begin
8
+ I18n.backend.store_translations locale, translations
9
+ yield
10
+ ensure
11
+ I18n.reload!
12
+ end
13
+ end
14
+
15
+ # Helpers for creating new users
16
+ #
17
+ def generate_unique_email
18
+ @@email_count ||= 0
19
+ @@email_count += 1
20
+ "test#{@@email_count}@email.com"
21
+ end
22
+
23
+ def valid_attributes(attributes={})
24
+ { :email => generate_unique_email,
25
+ :password => '123456',
26
+ :password_confirmation => '123456' }.update(attributes)
27
+ end
28
+
29
+ def new_user(attributes={})
30
+ User.new(valid_attributes(attributes))
31
+ end
32
+
33
+ def create_user_with_invitation(invitation_token, attributes={})
34
+ user = new_user({:password => nil, :password_confirmation => nil}.update(attributes))
35
+ user.skip_confirmation!
36
+ user.invitation_token = invitation_token
37
+ user.invitation_sent_at = Time.now.utc
38
+ user.save(:validate => false)
39
+ user
40
+ end
41
+ end
@@ -0,0 +1,213 @@
1
+ require 'test/test_helper'
2
+ require 'test/model_tests_helper'
3
+
4
+ class InvitableTest < ActiveSupport::TestCase
5
+
6
+ def setup
7
+ setup_mailer
8
+ end
9
+
10
+ test 'should not generate invitation token after creating a record' do
11
+ assert_nil new_user.invitation_token
12
+ end
13
+
14
+ test 'should not regenerate invitation token each time' do
15
+ user = new_user
16
+ user.invite!
17
+ token = user.invitation_token
18
+ assert_not_nil user.invitation_token
19
+ assert_not_nil user.invitation_sent_at
20
+ 3.times do
21
+ user.invite!
22
+ assert_equal token, user.invitation_token
23
+ end
24
+ end
25
+
26
+ test 'should set invitation sent at each time' do
27
+ user = new_user
28
+ user.invite!
29
+ old_invitation_sent_at = 3.days.ago
30
+ user.update_attribute :invitation_sent_at, old_invitation_sent_at
31
+ 3.times do
32
+ user.invite!
33
+ assert_not_equal old_invitation_sent_at, user.invitation_sent_at
34
+ user.update_attribute :invitation_sent_at, old_invitation_sent_at
35
+ end
36
+ end
37
+
38
+ test 'should not regenerate invitation token even after the invitation token is not valid' do
39
+ User.invite_for = 1.day
40
+ user = new_user
41
+ user.invite!
42
+ token = user.invitation_token
43
+ user.invitation_sent_at = 3.days.ago
44
+ user.save
45
+ user.invite!
46
+ assert_equal token, user.invitation_token
47
+ end
48
+
49
+ test 'should test invitation sent at with invite_for configuration value' do
50
+ user = create_user_with_invitation('token')
51
+
52
+ User.stubs(:invite_for).returns(nil)
53
+ user.invitation_sent_at = Time.now.utc
54
+ assert user.valid_invitation?
55
+
56
+ User.stubs(:invite_for).returns(nil)
57
+ user.invitation_sent_at = 1.year.ago
58
+ assert user.valid_invitation?
59
+
60
+ User.stubs(:invite_for).returns(0)
61
+ user.invitation_sent_at = Time.now.utc
62
+ assert user.valid_invitation?
63
+
64
+ User.stubs(:invite_for).returns(0)
65
+ user.invitation_sent_at = 1.day.ago
66
+ assert user.valid_invitation?
67
+
68
+ User.stubs(:invite_for).returns(1.day)
69
+ user.invitation_sent_at = Time.now.utc
70
+ assert user.valid_invitation?
71
+
72
+ User.stubs(:invite_for).returns(1.day)
73
+ user.invitation_sent_at = 1.day.ago
74
+ assert !user.valid_invitation?
75
+ end
76
+
77
+ test 'should never generate the same invitation token for different users' do
78
+ invitation_tokens = []
79
+ 3.times do
80
+ user = new_user
81
+ user.invite!
82
+ token = user.invitation_token
83
+ assert !invitation_tokens.include?(token)
84
+ invitation_tokens << token
85
+ end
86
+ end
87
+
88
+ test 'should set password and password confirmation from params' do
89
+ create_user_with_invitation('valid_token', :password => nil, :password_confirmation => nil)
90
+ user = User.accept_invitation!(:invitation_token => 'valid_token', :password => '123456789', :password_confirmation => '123456789')
91
+ assert user.valid_password?('123456789')
92
+ end
93
+
94
+ test 'should set password and save the record' do
95
+ user = create_user_with_invitation('valid_token', :password => nil, :password_confirmation => nil)
96
+ old_encrypted_password = user.encrypted_password
97
+ user = User.accept_invitation!(:invitation_token => 'valid_token', :password => '123456789', :password_confirmation => '123456789')
98
+ assert_not_equal old_encrypted_password, user.encrypted_password
99
+ end
100
+
101
+ test 'should clear invitation token while setting the password' do
102
+ user = new_user
103
+ user.skip_confirmation!
104
+ user.update_attribute(:invitation_token, 'valid_token')
105
+ assert_present user.invitation_token
106
+ assert user.accept_invitation!
107
+ assert_nil user.invitation_token
108
+ end
109
+
110
+ test 'should not clear invitation token if record is invalid' do
111
+ user = new_user
112
+ user.skip_confirmation!
113
+ user.update_attribute(:invitation_token, 'valid_token')
114
+ assert_present user.invitation_token
115
+ User.accept_invitation!(:invitation_token => 'valid_token', :password => '123456789', :password_confirmation => '987654321')
116
+ user.reload
117
+ assert_present user.invitation_token
118
+ end
119
+
120
+ test 'should reset invitation token and send invitation by email' do
121
+ user = new_user
122
+ assert_difference('ActionMailer::Base.deliveries.size') do
123
+ token = user.invitation_token
124
+ user.invite!
125
+ assert_not_equal token, user.invitation_token
126
+ end
127
+ end
128
+
129
+ test 'should return a record with invitation token and no errors to send invitation by email' do
130
+ invited_user = User.invite!(:email => "valid@email.com")
131
+ assert invited_user.errors.blank?
132
+ assert_present invited_user.invitation_token
133
+ assert_equal 'valid@email.com', invited_user.email
134
+ assert invited_user.persisted?
135
+ end
136
+
137
+ test 'should set all attributes with no errors' do
138
+ invited_user = User.invite!(:email => "valid@email.com", :username => 'first name')
139
+ assert invited_user.errors.blank?
140
+ assert_equal 'first name', invited_user.username
141
+ assert invited_user.persisted?
142
+ end
143
+
144
+ test 'should return a record with errors if user was found by e-mail' do
145
+ user = create_user_with_invitation('')
146
+ user.update_attribute(:invitation_token, nil)
147
+ invited_user = User.invite!(:email => user.email)
148
+ assert_equal invited_user, user
149
+ assert_equal ['has already been taken'], invited_user.errors[:email]
150
+ end
151
+
152
+ test 'should return a new record with errors if e-mail is blank' do
153
+ invited_user = User.invite!(:email => '')
154
+ assert invited_user.new_record?
155
+ assert_equal ["can't be blank"], invited_user.errors[:email]
156
+ end
157
+
158
+ test 'should return a new record with errors if e-mail is invalid' do
159
+ invited_user = User.invite!(:email => 'invalid_email')
160
+ assert invited_user.new_record?
161
+ assert_equal ["is invalid"], invited_user.errors[:email]
162
+ end
163
+
164
+ test 'should set all attributes with errors if e-mail is invalid' do
165
+ invited_user = User.invite!(:email => "invalid_email.com", :username => 'first name')
166
+ assert invited_user.new_record?
167
+ assert_equal 'first name', invited_user.username
168
+ assert invited_user.errors.present?
169
+ end
170
+
171
+ test 'should find a user to set his password based on invitation_token' do
172
+ user = new_user
173
+ user.invite!
174
+
175
+ invited_user = User.accept_invitation!(:invitation_token => user.invitation_token)
176
+ assert_equal invited_user, user
177
+ end
178
+
179
+ test 'should return a new record with errors if no invitation_token is found' do
180
+ invited_user = User.accept_invitation!(:invitation_token => 'invalid_token')
181
+ assert invited_user.new_record?
182
+ assert_equal ['is invalid'], invited_user.errors[:invitation_token]
183
+ end
184
+
185
+ test 'should return a new record with errors if invitation_token is blank' do
186
+ invited_user = User.accept_invitation!(:invitation_token => '')
187
+ assert invited_user.new_record?
188
+ assert_equal ["can't be blank"], invited_user.errors[:invitation_token]
189
+ end
190
+
191
+ test 'should return record with errors if invitation_token has expired' do
192
+ user = create_user_with_invitation('valid_token')
193
+ user.update_attribute(:invitation_sent_at, 1.day.ago)
194
+ User.stubs(:invite_for).returns(10.hours)
195
+ invited_user = User.accept_invitation!(:invitation_token => 'valid_token')
196
+ assert_equal user, invited_user
197
+ assert_equal ["is invalid"], invited_user.errors[:invitation_token]
198
+ end
199
+
200
+ test 'should set successfully user password given the new password and confirmation' do
201
+ user = new_user(:password => nil, :password_confirmation => nil)
202
+ user.invite!
203
+
204
+ invited_user = User.accept_invitation!(
205
+ :invitation_token => user.invitation_token,
206
+ :password => 'new_password',
207
+ :password_confirmation => 'new_password'
208
+ )
209
+ user.reload
210
+
211
+ assert user.valid_password?('new_password')
212
+ end
213
+ end