authpwn_rails 0.10.5 → 0.10.6

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 (47) hide show
  1. data/Gemfile +8 -8
  2. data/Gemfile.lock +1 -1
  3. data/VERSION +1 -1
  4. data/app/models/credentials/email.rb +12 -4
  5. data/app/models/credentials/token.rb +106 -0
  6. data/app/models/tokens/email_verification.rb +42 -0
  7. data/app/models/tokens/one_time.rb +16 -0
  8. data/app/models/tokens/password_reset.rb +27 -0
  9. data/authpwn_rails.gemspec +36 -11
  10. data/lib/authpwn_rails.rb +2 -0
  11. data/lib/authpwn_rails/generators/all_generator.rb +20 -2
  12. data/lib/authpwn_rails/generators/templates/credentials.yml +21 -0
  13. data/lib/authpwn_rails/generators/templates/session/new.html.erb +10 -5
  14. data/lib/authpwn_rails/generators/templates/session/password_change.html.erb +37 -0
  15. data/lib/authpwn_rails/generators/templates/session_controller.rb +20 -2
  16. data/lib/authpwn_rails/generators/templates/session_controller_test.rb +71 -0
  17. data/lib/authpwn_rails/generators/templates/session_mailer.rb +26 -0
  18. data/lib/authpwn_rails/generators/templates/session_mailer/email_verification_email.html.erb +23 -0
  19. data/lib/authpwn_rails/generators/templates/session_mailer/email_verification_email.text.erb +11 -0
  20. data/lib/authpwn_rails/generators/templates/session_mailer/reset_password_email.html.erb +23 -0
  21. data/lib/authpwn_rails/generators/templates/session_mailer/reset_password_email.text.erb +11 -0
  22. data/lib/authpwn_rails/generators/templates/session_mailer_test.rb +37 -0
  23. data/lib/authpwn_rails/routes.rb +50 -0
  24. data/lib/authpwn_rails/session_controller.rb +129 -0
  25. data/lib/authpwn_rails/session_mailer.rb +66 -0
  26. data/test/{email_credential_test.rb → credentials/email_credential_test.rb} +1 -1
  27. data/test/credentials/email_verification_token_test.rb +78 -0
  28. data/test/{facebook_credential_test.rb → credentials/facebook_credential_test.rb} +1 -1
  29. data/test/credentials/one_time_token_credential_test.rb +84 -0
  30. data/test/{password_credential_test.rb → credentials/password_credential_test.rb} +1 -1
  31. data/test/credentials/password_reset_token_test.rb +72 -0
  32. data/test/credentials/token_crendential_test.rb +102 -0
  33. data/test/fixtures/bare_session/forbidden.html.erb +20 -0
  34. data/test/fixtures/bare_session/home.html.erb +5 -0
  35. data/test/fixtures/bare_session/new.html.erb +32 -0
  36. data/test/fixtures/bare_session/password_change.html.erb +30 -0
  37. data/test/fixtures/bare_session/welcome.html.erb +5 -0
  38. data/test/helpers/action_mailer.rb +8 -0
  39. data/test/helpers/routes.rb +8 -2
  40. data/test/routes_test.rb +31 -0
  41. data/test/session_controller_api_test.rb +310 -15
  42. data/test/session_mailer_api_test.rb +67 -0
  43. data/test/test_helper.rb +3 -1
  44. data/test/{email_field_test.rb → user_extensions/email_field_test.rb} +1 -1
  45. data/test/{facebook_fields_test.rb → user_extensions/facebook_fields_test.rb} +1 -1
  46. data/test/{password_field_test.rb → user_extensions/password_field_test.rb} +1 -1
  47. metadata +49 -24
@@ -0,0 +1,5 @@
1
+ <p>
2
+ This view gets displayed when the user is logged in. Right now,
3
+ user <%= current_user.exuid %> is logged in. You should allow the user to
4
+ <%= link_to 'Log out', session_path, :method => :destroy %>.
5
+ </p>
@@ -0,0 +1,32 @@
1
+ <p>This is a sample login form. You should customize it for your users.</p>
2
+
3
+ <% if flash[:notice] %>
4
+ <p class="notice"><%= flash[:notice] %></p>
5
+ <% end %>
6
+
7
+ <% if @redirect_url %>
8
+ <p>
9
+ We need you to log in before we can show you the page that you are trying to
10
+ view.
11
+ </p>
12
+ <% end %>
13
+
14
+ <%= form_tag session_path do %>
15
+ <div class="field">
16
+ <%= label_tag :email, 'Email Address' %><br />
17
+ <%= email_field_tag :email, @email %>
18
+ </div>
19
+
20
+ <div class="field">
21
+ <%= label_tag :password %><br />
22
+ <%= password_field_tag :password %>
23
+ </div>
24
+
25
+ <div class="actions">
26
+ <%= submit_tag 'Log in' %>
27
+
28
+ <% if @redirect_url %>
29
+ <%= hidden_field_tag :redirect_url, @redirect_url %>
30
+ <% end %>
31
+ </div>
32
+ <% end %>
@@ -0,0 +1,30 @@
1
+ <%= form_for @credential, :url => change_password_session_path do |f| %>
2
+ <section class="fields">
3
+ <% unless @credential.new_record? %>
4
+ <div class="field">
5
+ <%= label_tag :old_password, 'Current Password' %><br />
6
+ <span class="value">
7
+ <%= password_field_tag :old_password %>
8
+ </span>
9
+ </div>
10
+ <% end %>
11
+
12
+ <div class="field">
13
+ <%= f.label :password, 'New Password' %><br />
14
+ <span class="value">
15
+ <%= f.password_field :password %>
16
+ </span
17
+ </div>
18
+
19
+ <div class="field">
20
+ <%= f.label :password_confirmation, 'Re-enter New Password' %><br />
21
+ <span class="value">
22
+ <%= f.password_field :password_confirmation %>
23
+ </span
24
+ </div>
25
+ </section>
26
+
27
+ <p class="action">
28
+ <%= submit_tag 'Log in' %>
29
+ </p>
30
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <p>
2
+ This view gets displayed when the user is not logged in. Entice the user to
3
+ sign up for your application, and allow them to
4
+ <%= link_to 'Log in', new_session_path %>.
5
+ </p>
@@ -0,0 +1,8 @@
1
+ # :nodoc: add our views to the path
2
+ class ActionMailer::Base
3
+ prepend_view_path File.expand_path(
4
+ '../../../lib/authpwn_rails/generators/templates', __FILE__)
5
+
6
+ self.delivery_method = :test
7
+ self.perform_deliveries = true
8
+ end
@@ -7,11 +7,17 @@ class ActionController::TestCase
7
7
  collection { get :bouncer }
8
8
  end
9
9
  resource :facebook, :controller => 'facebook'
10
- # NOTE: this route should be kept in sync with the session template.
11
- resource :session, :controller => 'session'
10
+ authpwn_session :controller => 'bare_session',
11
+ :method_names => 'bare_session'
12
+ authpwn_session :controller => 'bare_session2',
13
+ :method_names => 'bare_session2'
12
14
  root :to => 'session#index'
15
+
16
+ # NOTE: this route should be kept in sync with the session template.
17
+ authpwn_session
13
18
  end
14
19
  ApplicationController.send :include, @routes.url_helpers
20
+ ActionMailer::Base.send :include, @routes.url_helpers
15
21
  end
16
22
 
17
23
  setup :setup_routes
@@ -0,0 +1,31 @@
1
+ require File.expand_path('../test_helper', __FILE__)
2
+
3
+ require 'authpwn_rails/generators/templates/session_controller.rb'
4
+
5
+ # Tests the routes created by authpwn_session.
6
+ class RoutesTest < ActionController::TestCase
7
+ tests SessionController
8
+
9
+ test "authpwn_session routes" do
10
+ assert_routing({:path => "/session", :method => :get},
11
+ {:controller => 'session', :action => 'show'})
12
+ assert_routing({:path => "/session/new", :method => :get},
13
+ {:controller => 'session', :action => 'new'})
14
+ assert_routing({:path => "/session", :method => :post},
15
+ {:controller => 'session', :action => 'create'})
16
+ assert_routing({:path => "/session", :method => :delete},
17
+ {:controller => 'session', :action => 'destroy'})
18
+ assert_routing({:path => "/session", :method => :delete},
19
+ {:controller => 'session', :action => 'destroy'})
20
+ assert_routing({:path => "/session/change_password", :method => :get},
21
+ {:controller => 'session', :action => 'password_change'})
22
+ assert_routing({:path => "/session/change_password", :method => :post},
23
+ {:controller => 'session', :action => 'change_password'})
24
+ assert_routing({:path => "/session/reset_password", :method => :post},
25
+ {:controller => 'session', :action => 'reset_password'})
26
+
27
+ code = 'YZ-Fo8HX6_NyU6lVZXYi6cMDLV5eAgt35UTF5l8bD6A'
28
+ assert_routing({:path => "/session/token/#{code}", :method => :get},
29
+ {:controller => 'session', :action => 'token', :code => code})
30
+ end
31
+ end
@@ -5,50 +5,55 @@ require 'authpwn_rails/generators/templates/session_controller.rb'
5
5
  # Run the tests in the generator, to make sure they pass.
6
6
  require 'authpwn_rails/generators/templates/session_controller_test.rb'
7
7
 
8
+ class BareSessionController < ApplicationController
9
+ include Authpwn::SessionController
10
+ self.append_view_path File.expand_path('../fixtures', __FILE__)
11
+ end
12
+
8
13
  # Tests the methods injected by authpwn_session_controller.
9
14
  class SessionControllerApiTest < ActionController::TestCase
10
- tests SessionController
15
+ tests BareSessionController
11
16
 
12
17
  setup do
13
18
  @user = users(:john)
14
19
  @email_credential = credentials(:john_email)
20
+ @password_credential = credentials(:john_password)
21
+ @token_credential = credentials(:john_token)
15
22
  end
16
23
 
17
24
  test "show renders welcome without a user" do
25
+ flexmock(@controller).should_receive(:welcome).once.and_return(nil)
18
26
  get :show
19
27
  assert_template :welcome
20
28
  assert_nil assigns(:current_user)
21
- assert_equal User.count, assigns(:user_count),
22
- 'welcome controller method not called'
23
29
  end
24
30
 
25
31
  test "show json renders empty object without a user" do
32
+ flexmock(@controller).should_receive(:welcome).once.and_return(nil)
26
33
  get :show, :format => 'json'
27
34
  assert_response :ok
28
35
  assert_equal({}, ActiveSupport::JSON.decode(response.body))
29
- assert_equal User.count, assigns(:user_count),
30
- 'welcome controller method not called'
31
36
  end
32
37
 
33
38
  test "show renders home with a user" do
39
+ flexmock(@controller).should_receive(:home).once.and_return(nil)
34
40
  set_session_current_user @user
35
41
  get :show
36
42
  assert_template :home
37
43
  assert_equal @user, assigns(:current_user)
38
- assert_equal @user, assigns(:user), 'home controller method not called'
39
44
  end
40
45
 
41
46
  test "show json renders user when logged in" do
42
47
  set_session_current_user @user
48
+ flexmock(@controller).should_receive(:home).once.and_return(nil)
43
49
  get :show, :format => 'json'
44
50
  assert_response :ok
45
51
  data = ActiveSupport::JSON.decode response.body
46
52
  assert_equal @user.exuid, data['user']['exuid']
47
53
  assert_equal session[:_csrf_token], data['csrf']
48
- assert_equal @user, assigns(:user), 'home controller method not called'
49
54
  end
50
55
 
51
- test "new redirects homes with a user" do
56
+ test "new redirects to session#show when a user is logged in" do
52
57
  set_session_current_user @user
53
58
  get :new
54
59
  assert_redirected_to session_url
@@ -58,12 +63,6 @@ class SessionControllerApiTest < ActionController::TestCase
58
63
  get :new
59
64
  assert_template :new
60
65
  assert_nil assigns(:current_user), 'current_user should not be set'
61
-
62
- assert_select 'form[action="/session"]' do
63
- assert_select 'input#email'
64
- assert_select 'input#password'
65
- assert_select 'input[type=submit]'
66
- end
67
66
  end
68
67
 
69
68
  test "new renders redirect_url when present in flash" do
@@ -78,9 +77,9 @@ class SessionControllerApiTest < ActionController::TestCase
78
77
 
79
78
  test "create logs in with good account details" do
80
79
  post :create, :email => @email_credential.email, :password => 'password'
81
- assert_redirected_to session_url
82
80
  assert_equal @user, assigns(:current_user), 'instance variable'
83
81
  assert_equal @user, session_current_user, 'session'
82
+ assert_redirected_to session_url
84
83
  end
85
84
 
86
85
  test "create by json logs in with good account details" do
@@ -160,6 +159,79 @@ class SessionControllerApiTest < ActionController::TestCase
160
159
  assert_not_nil flash[:notice]
161
160
  end
162
161
 
162
+ test "token logs in with good token" do
163
+ flexmock(@controller).should_receive(:home_with_token).once.
164
+ with(@token_credential).and_return(nil)
165
+ assert_difference 'Credential.count', -1, 'one-time credential is spent' do
166
+ get :token, :code => @token_credential.code
167
+ end
168
+ assert_redirected_to session_url
169
+ assert_equal @user, assigns(:current_user), 'instance variable'
170
+ assert_equal @user, session_current_user, 'session'
171
+ end
172
+
173
+ test "token by json logs in with good token" do
174
+ flexmock(@controller).should_receive(:home_with_token).once.
175
+ with(@token_credential).and_return(nil)
176
+ assert_difference 'Credential.count', -1, 'one-time credential is spent' do
177
+ get :token, :code => @token_credential.code, :format => 'json'
178
+ end
179
+ assert_response :ok
180
+ data = ActiveSupport::JSON.decode response.body
181
+ assert_equal @user.exuid, data['user']['exuid']
182
+ assert_equal session[:_csrf_token], data['csrf']
183
+ assert_equal @user, assigns(:current_user), 'instance variable'
184
+ assert_equal @user, session_current_user, 'session'
185
+ end
186
+
187
+ test "token does not log in with random token" do
188
+ assert_no_difference 'Credential.count', 'no credential is spent' do
189
+ get :token, :code => 'no-such-token'
190
+ end
191
+ assert_redirected_to new_session_url
192
+ assert_nil assigns(:current_user), 'instance variable'
193
+ assert_nil session_current_user, 'session'
194
+ assert_match(/Invalid/, flash[:notice])
195
+ end
196
+
197
+ test "token does not log in blocked accounts" do
198
+ with_blocked_credential @token_credential do
199
+ assert_no_difference 'Credential.count', 'no credential is spent' do
200
+ get :token, :code => @token_credential.code
201
+ end
202
+ end
203
+ assert_redirected_to new_session_url
204
+ assert_nil assigns(:current_user), 'instance variable'
205
+ assert_nil session_current_user, 'session'
206
+ assert_match(/ blocked/, flash[:notice])
207
+ end
208
+
209
+ test "token by json does not log in with random token" do
210
+ assert_no_difference 'Credential.count', 'no credential is spent' do
211
+ get :token, :code => 'no-such-token', :format => 'json'
212
+ end
213
+ assert_response :ok
214
+ data = ActiveSupport::JSON.decode response.body
215
+ assert_equal 'invalid', data['error']
216
+ assert_match(/invalid/i , data['text'])
217
+ assert_nil assigns(:current_user), 'instance variable'
218
+ assert_nil session_current_user, 'session'
219
+ end
220
+
221
+ test "token by json does not log in blocked accounts" do
222
+ with_blocked_credential @token_credential do
223
+ assert_no_difference 'Credential.count', 'no credential is spent' do
224
+ get :token, :code => @token_credential.code, :format => 'json'
225
+ end
226
+ end
227
+ assert_response :ok
228
+ data = ActiveSupport::JSON.decode response.body
229
+ assert_equal 'blocked', data['error']
230
+ assert_match(/blocked/i , data['text'])
231
+ assert_nil assigns(:current_user), 'instance variable'
232
+ assert_nil session_current_user, 'session'
233
+ end
234
+
163
235
  test "logout" do
164
236
  set_session_current_user @user
165
237
  delete :destroy
@@ -175,4 +247,227 @@ class SessionControllerApiTest < ActionController::TestCase
175
247
  assert_response :ok
176
248
  assert_nil assigns(:current_user)
177
249
  end
250
+
251
+ test "password_change bounces without logged in user" do
252
+ get :password_change
253
+ assert_response :forbidden
254
+ end
255
+
256
+ test "password_change renders correct form" do
257
+ set_session_current_user @user
258
+ get :password_change
259
+ assert_response :ok
260
+ assert_template :password_change
261
+ assert_equal @password_credential, assigns(:credential)
262
+ end
263
+
264
+ test "change_password bounces without logged in user" do
265
+ post :change_password, :old_password => 'password',
266
+ :credential => { :password => 'hacks',
267
+ :password_confirmation => 'hacks'}
268
+ assert_response :forbidden
269
+ end
270
+
271
+ test "change_password works with correct input" do
272
+ set_session_current_user @user
273
+ post :change_password, :old_password => 'password',
274
+ :credential => { :password => 'hacks',
275
+ :password_confirmation => 'hacks'}
276
+ assert_redirected_to session_url
277
+ assert_equal @password_credential, assigns(:credential)
278
+ assert_equal @user, Credentials::Password.authenticate_email(
279
+ @email_credential.email, 'hacks'), 'password not changed'
280
+ end
281
+
282
+ test "change_password rejects bad old password" do
283
+ set_session_current_user @user
284
+ post :change_password, :old_password => '_password',
285
+ :credential => { :password => 'hacks',
286
+ :password_confirmation => 'hacks'}
287
+ assert_response :ok
288
+ assert_template :password_change
289
+ assert_equal @password_credential, assigns(:credential)
290
+ assert_equal @user, Credentials::Password.authenticate_email(
291
+ @email_credential.email, 'password'), 'password wrongly changed'
292
+ end
293
+
294
+ test "change_password rejects un-confirmed password" do
295
+ set_session_current_user @user
296
+ post :change_password, :old_password => 'password',
297
+ :credential => { :password => 'hacks',
298
+ :password_confirmation => 'hacks_'}
299
+ assert_response :ok
300
+ assert_template :password_change
301
+ assert_equal @password_credential, assigns(:credential)
302
+ assert_equal @user, Credentials::Password.authenticate_email(
303
+ @email_credential.email, 'password'), 'password wrongly changed'
304
+ end
305
+
306
+ test "change_password works for password recovery" do
307
+ set_session_current_user @user
308
+ @password_credential.destroy
309
+ post :change_password,
310
+ :credential => { :password => 'hacks',
311
+ :password_confirmation => 'hacks'}
312
+ assert_redirected_to session_url
313
+ assert_equal @user, Credentials::Password.authenticate_email(
314
+ @email_credential.email, 'hacks'), 'password not changed'
315
+ end
316
+
317
+ test "change_password rejects un-confirmed password on recovery" do
318
+ set_session_current_user @user
319
+ @password_credential.destroy
320
+ assert_no_difference 'Credential.count' do
321
+ post :change_password,
322
+ :credential => { :password => 'hacks',
323
+ :password_confirmation => 'hacks_'}
324
+ end
325
+ assert_response :ok
326
+ assert_template :password_change
327
+ end
328
+
329
+ test "change_password by json bounces without logged in user" do
330
+ post :change_password, :format => 'json', :old_password => 'password',
331
+ :credential => { :password => 'hacks',
332
+ :password_confirmation => 'hacks'}
333
+ assert_response :ok
334
+ data = ActiveSupport::JSON.decode response.body
335
+ assert_equal 'Please sign in', data['error']
336
+ end
337
+
338
+ test "change_password by json works with correct input" do
339
+ set_session_current_user @user
340
+ post :change_password, :format => 'json', :old_password => 'password',
341
+ :credential => { :password => 'hacks',
342
+ :password_confirmation => 'hacks'}
343
+ assert_response :ok
344
+ assert_equal @user, Credentials::Password.authenticate_email(
345
+ @email_credential.email, 'hacks'), 'password not changed'
346
+ end
347
+
348
+ test "change_password by json rejects bad old password" do
349
+ set_session_current_user @user
350
+ post :change_password, :format => 'json', :old_password => '_password',
351
+ :credential => { :password => 'hacks',
352
+ :password_confirmation => 'hacks'}
353
+ assert_response :ok
354
+ data = ActiveSupport::JSON.decode response.body
355
+ assert_equal 'invalid', data['error']
356
+ assert_equal @password_credential, assigns(:credential)
357
+ assert_equal @user, Credentials::Password.authenticate_email(
358
+ @email_credential.email, 'password'), 'password wrongly changed'
359
+ end
360
+
361
+ test "change_password by json rejects un-confirmed password" do
362
+ set_session_current_user @user
363
+ post :change_password, :format => 'json', :old_password => 'password',
364
+ :credential => { :password => 'hacks',
365
+ :password_confirmation => 'hacks_'}
366
+ assert_response :ok
367
+ data = ActiveSupport::JSON.decode response.body
368
+ assert_equal 'invalid', data['error']
369
+ assert_equal @user, Credentials::Password.authenticate_email(
370
+ @email_credential.email, 'password'), 'password wrongly changed'
371
+ end
372
+
373
+ test "change_password by json works for password recovery" do
374
+ set_session_current_user @user
375
+ @password_credential.destroy
376
+ post :change_password, :format => 'json',
377
+ :credential => { :password => 'hacks',
378
+ :password_confirmation => 'hacks'}
379
+ assert_response :ok
380
+ assert_equal @user, Credentials::Password.authenticate_email(
381
+ @email_credential.email, 'hacks'), 'password not changed'
382
+ end
383
+
384
+ test "change_password by json rejects un-confirmed password on recovery" do
385
+ set_session_current_user @user
386
+ @password_credential.destroy
387
+ assert_no_difference 'Credential.count' do
388
+ post :change_password, :format => 'json',
389
+ :credential => { :password => 'hacks',
390
+ :password_confirmation => 'hacks_'}
391
+ end
392
+ assert_response :ok
393
+ data = ActiveSupport::JSON.decode response.body
394
+ assert_equal 'invalid', data['error']
395
+ end
396
+
397
+ test "reset_password for good e-mail" do
398
+ ActionMailer::Base.deliveries = []
399
+ @request.host = 'mail.test.host:1234'
400
+
401
+ assert_difference 'Credential.count', 1 do
402
+ post :reset_password, :email => @email_credential.email
403
+ end
404
+
405
+ token = Credential.last
406
+ assert_operator token, :kind_of?, Tokens::PasswordReset
407
+ assert_equal @user, token.user, 'password reset token user'
408
+
409
+ assert !ActionMailer::Base.deliveries.empty?, 'email generated'
410
+ email = ActionMailer::Base.deliveries.last
411
+ assert_equal '"mail.test.host staff" <admin@mail.test.host>',
412
+ email['from'].to_s
413
+ assert_equal [@email_credential.email], email.to
414
+ assert_match 'http://mail.test.host:1234/', email.encoded
415
+ assert_match token.code, email.encoded
416
+
417
+ assert_redirected_to new_session_url
418
+ end
419
+
420
+ test "reset_password for good e-mail by json" do
421
+ ActionMailer::Base.deliveries = []
422
+
423
+ assert_difference 'Credential.count', 1 do
424
+ post :reset_password, :email => @email_credential.email, :format => 'json'
425
+ end
426
+
427
+ token = Credential.last
428
+ assert_operator token, :kind_of?, Tokens::PasswordReset
429
+ assert_equal @user, token.user, 'password reset token user'
430
+
431
+ assert !ActionMailer::Base.deliveries.empty?, 'email generated'
432
+
433
+ assert_response :ok
434
+ assert_equal '{}', response.body
435
+ end
436
+
437
+ test "reset_password for invalid e-mail" do
438
+ ActionMailer::Base.deliveries = []
439
+
440
+ assert_no_difference 'Credential.count' do
441
+ post :reset_password, :email => 'no@such.email'
442
+ end
443
+ assert ActionMailer::Base.deliveries.empty?, 'no email generated'
444
+
445
+ assert_redirected_to new_session_url
446
+ end
447
+
448
+ test "reset_password for invalid e-mail by json" do
449
+ ActionMailer::Base.deliveries = []
450
+
451
+ assert_no_difference 'Credential.count' do
452
+ post :reset_password, :email => 'no@such.email', :format => 'json'
453
+ end
454
+ assert ActionMailer::Base.deliveries.empty?, 'no email generated'
455
+
456
+ assert_response :ok
457
+ data = ActiveSupport::JSON.decode response.body
458
+ assert_equal 'not_found', data['error']
459
+ end
460
+
461
+ test "create delegation to reset_password" do
462
+ ActionMailer::Base.deliveries = []
463
+
464
+ assert_difference 'Credential.count', 1 do
465
+ post :create, :email => @email_credential.email, :password => '',
466
+ :reset_password => :requested
467
+ end
468
+
469
+ token = Credential.last
470
+ assert_operator token, :kind_of?, Tokens::PasswordReset
471
+ assert_equal @user, token.user, 'password reset token user'
472
+ end
178
473
  end