Added browser tests for password reset.

This commit is contained in:
Martin Edenhofer 2014-12-31 10:04:14 +01:00
parent 67b32a0bca
commit 0d9adc0d64
12 changed files with 324 additions and 100 deletions

View file

@ -44,120 +44,156 @@ class Index extends App.ControllerContent
# get data
@ajax(
id: 'password_reset'
type: 'POST'
url: @apiPath + '/users/password_reset'
data: JSON.stringify(params)
id: 'password_reset'
type: 'POST'
url: @apiPath + '/users/password_reset'
data: JSON.stringify(params)
processData: true
success: @success
error: @error
success: @success
)
success: (data, status, xhr) =>
@render( sent: true )
success: (data) =>
if data.message is 'ok'
error: (data, status, xhr) =>
@notify(
type: 'error'
msg: App.i18n.translateContent( 'Username or email address invalid, please try again.' )
)
@formEnable( @el.find('.form-password') )
# if in developer mode, redirect to set new password
if data.token && @Config.get('developer_mode') is true
redirect = =>
@navigate "#password_reset_verify/#{data.token}"
@delay( redirect, 2000 )
@render( sent: true )
else
@$('[name=username]').val('')
@notify(
type: 'error'
msg: App.i18n.translateContent( 'Username or email address invalid, please try again.' )
)
@formEnable( @el.find('.form-password') )
App.Config.set( 'reset_password', Index, 'Routes' )
class Verify extends App.ControllerContent
events:
'submit form': 'submit'
'submit form': 'submit'
'click .submit': 'submit'
constructor: ->
super
@navHide()
# set title
@title 'Reset Password'
@navupdate '#reset_password_verify'
# get data
params = {}
params['token'] = @token
params =
token: @token
@ajax(
id: 'password_reset_verify'
type: 'POST'
url: @apiPath + '/users/password_reset_verify'
data: JSON.stringify(params)
id: 'password_reset_verify'
type: 'POST'
url: @apiPath + '/users/password_reset_verify'
data: JSON.stringify(params)
processData: true
success: @render_success
error: @render_failed
success: @render_change
)
render_success: =>
configure_attributes = [
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 100, null: false, class: 'input span4', },
]
render_change: (data) =>
if data.message is 'ok'
configure_attributes = [
{ name: 'password', display: 'Password', tag: 'input', type: 'password', limit: 100, null: false, class: 'input', },
]
@html App.view('password/reset_change')()
@html App.view('password/reset_change')()
new App.ControllerForm(
el: @el.find('#form-password-change')
model: { configure_attributes: configure_attributes }
autofocus: true
)
render_failed: =>
@html App.view('generic/hero_message')(
head: 'Failed!'
message: 'Token is not valid!'
)
new App.ControllerForm(
el: @el.find('.form-password-change')
model: { configure_attributes: configure_attributes }
autofocus: true
)
else
@html App.view('password/reset_failed')(
head: 'Reset Password failed!'
message: 'Token is invalid!'
)
submit: (e) ->
e.preventDefault()
params = @formParam(e.target)
params = @formParam(e.target)
params['token'] = @token
@password = params['password']
@password = params['password']
# disable form
@formDisable(e)
# validate
if params['password_confirm'] isnt params['password']
@formEnable(e)
@$('[name=password]').val('')
@$('[name=password_confirm]').val('')
@notify
type: 'error'
msg: 'Can\'t update password, your new passwords do not match. Please try again!'
removeAll: true
return
if !params['password']
@formEnable(e)
@notify
type: 'error'
msg: 'Please supply your new password!'
removeAll: true
return
# get data
@ajax(
id: 'password_reset_verify'
type: 'POST'
url: @apiPath + '/users/password_reset_verify'
data: JSON.stringify(params)
id: 'password_reset_verify'
type: 'POST'
url: @apiPath + '/users/password_reset_verify'
data: JSON.stringify(params)
processData: true
success: @render_changed_success
error: @render_changed_failed
success: @render_changed
)
render_changed_success: (data, status, xhr) =>
App.Auth.login(
data:
username: data.user_login
password: @password
success: =>
render_changed: (data, status, xhr) =>
if data.message is 'ok'
App.Auth.login(
data:
username: data.user_login
password: @password
success: =>
# login check
App.Auth.loginCheck()
# login check
App.Auth.loginCheck()
# add notify
@notify
type: 'success'
msg: 'Woo hoo! Your password has been changed!'
removeAll: true
# add notify
@notify
type: 'success'
msg: 'Woo hoo! Your password has been changed!'
removeAll: true
# redirect to #
@navigate '#'
# redirect to #
@navigate '#'
error: =>
error: =>
@formEnable( @$('form') )
# add notify
# add notify
@notify
type: 'error'
msg: 'Something went wrong. Please contact your administrator.'
removeAll: true
)
else
if data.notice
@notify
type: 'error'
msg: 'Something went wrong. Please contact your administrator.'
msg: App.i18n.translateContent( data.notice[0], data.notice[1] )
removeAll: true
)
else
@notify
type: 'error'
msg: 'Unable to set password. Please contact your administrator.'
removeAll: true
@formEnable( @$('form') )
render_changed_failed: =>
@html App.view('generic/hero_message')(
head: 'Failed!'
message: 'Ask your admin!'
)
App.Config.set( 'password_reset_verify/:token', Verify, 'Routes' )
App.Config.set( 'password_reset_verify/:token', Verify, 'Routes' )

View file

@ -1,8 +0,0 @@
<div class="hero-unit">
<h2><%- @T( @head ) %> <small><%- @T( @head_small ) %></small></h2>
<div class="container">
<p>
<%- @message %>
</p>
</div>
</div>

View file

@ -1,8 +1,12 @@
<div class="fullHeight vertical center justified reset_password fit">
<div class="hero-unit">
<h2><%- @T( 'Choose your new password.' ) %><small></small></h2>
<form id="form-password-change">
<button class="btn btn--primary submit"><%- @T( 'Submit' ) %></button>
<form>
<div class="form-password-change"></div>
<div class="form-controls">
<a class="subtle-link standalone pull-left cancel" href="#/"><%- @T( 'Cancel & Go Back' ) %></a>
<button class="btn btn--primary submit pull-right"><%- @T( 'Submit' ) %></button>
</div>
</form>
</div>
</div>
</div>

View file

@ -0,0 +1,9 @@
<div class="reset_password fullscreen">
<div class="fullscreen-center">
<div class="hero-unit fullscreen-body">
<h2><%- @T( @head ) %><small></small></h2>
<p><%- @message %></p>
<a href="#reset_password" class="subtle retry">&raquo; <%- @T('try again') %> &laquo;</a>
</div>
</div>
</div>

View file

@ -367,12 +367,22 @@ curl http://localhost/api/v1/users/password_reset.json -v -u #{login}:#{password
return
end
success = User.password_reset_send( params[:username] )
if success
token = User.password_reset_send( params[:username] )
if token
# only if system is in develop mode, send token back to browser for browser tests
if Setting.get('developer_mode') == true
render :json => { :message => 'ok', :token => token.name }, :status => :ok
return
end
# token sent to user, send ok to browser
render :json => { :message => 'ok' }, :status => :ok
else
render :json => { :message => 'failed' }, :status => :unprocessable_entity
return
end
# unable to generate token
render :json => { :message => 'failed' }, :status => :ok
end
=begin
@ -443,12 +453,12 @@ curl http://localhost/api/v1/users/password_change.json -v -u #{login}:#{passwor
# check old password
if !params[:password_old]
render :json => { :message => 'failed', :notice => ['Old password needed!'] }, :status => :ok
render :json => { :message => 'failed', :notice => ['Current password needed!'] }, :status => :ok
return
end
user = User.authenticate( current_user.login, params[:password_old] )
if !user
render :json => { :message => 'failed', :notice => ['Old password is wrong!'] }, :status => :ok
render :json => { :message => 'failed', :notice => ['Current password is wrong!'] }, :status => :ok
return
end

View file

@ -267,7 +267,7 @@ send reset password email with token to user
returns
result = true|false
result = token
=end
@ -325,7 +325,7 @@ returns
:subject => data[:subject],
:body => data[:body]
)
true
token
end
=begin

View file

@ -0,0 +1,16 @@
class AddDevelopMode < ActiveRecord::Migration
def up
Setting.create_if_not_exists(
:title => 'Develop System',
:name => 'developer_mode',
:area => 'Core::Develop',
:description => 'Defines if application is in developer mode (useful for developer, all users have the same password, password reset will work without email delivery).',
:options => {},
:state => false,
:frontend => true
)
end
def down
end
end

View file

@ -15,6 +15,15 @@ Setting.create_if_not_exists(
:state => false,
:frontend => true
)
Setting.create_if_not_exists(
:title => 'Developer System',
:name => 'developer_mode',
:area => 'Core::Develop',
:description => 'Defines if application is in developer mode (useful for developer, all users have the same password, password reset will work without email delivery).',
:options => {},
:state => false,
:frontend => true
)
Setting.create_if_not_exists(
:title => 'Online Service',
:name => 'system_online_service',

View file

@ -23,7 +23,7 @@ returns
:adapter => 'Auth::Internal',
},
{
:adapter => 'Auth::Test',
:adapter => 'Auth::Developer',
},
]

View file

@ -1,10 +1,10 @@
# Copyright (C) 2012-2013 Zammad Foundation, http://zammad-foundation.org/
module Auth::Test
module Auth::Developer
def self.check( username, password, config, user )
# development systems
if !ENV['RAILS_ENV'] || ENV['RAILS_ENV'] == 'development' || ENV['RAILS_ENV'] == 'test'
if Setting.get('developer_mode') == true
return user if password == 'test'
end

View file

@ -28,8 +28,8 @@ rake db:seed
# modify production.rb to serve assets
cat config/environments/production.rb | sed -e 's/config.serve_static_assets = false/config.serve_static_assets = true/' > /tmp/production.rb && cp /tmp/production.rb config/environments/production.rb
# mofidy auth backend
cat lib/auth/test.rb | sed "s/\] == 'test'/] == 'production'/" > /tmp/test.rb && cp /tmp/test.rb lib/auth/test.rb
# set system to develop mode
rails r "Setting.set('developer_mode', true)"
pumactl --pidfile tmp/pids/puma.pid stop
script/websocket-server.rb stop
@ -42,7 +42,7 @@ sleep 15
#export REMOTE_URL='http://medenhofer:765d0dd4-994b-4e15-9f89-13f3aedeb462@ondemand.saucelabs.com:80/wd/hub' BROWSER_OS='Windows 2012' BROWSER_VERSION=20 BROWSER=firefox
rake test:browser["BROWSER_URL=http://localhost:4444"]
#rake test:browser["BROWSER_URL=http://192.168.178.20:4444"]
#rake test:browser["BROWSER_URL=http://192.168.178.28:4444"]
script/websocket-server.rb stop

View file

@ -1,7 +1,7 @@
# encoding: utf-8
require 'browser_test_helper'
class SignupTest < TestCase
class SignupPasswordChangeAndResetTest < TestCase
def test_signup
signup_user_email = 'signup-test-' + rand(999999).to_s + '@example.com'
tests = [
@ -112,7 +112,7 @@ class SignupTest < TestCase
{
:execute => 'watch_for',
:area => 'body',
:value => 'old password is wrong',
:value => 'current password is wrong',
},
{
:execute => 'set',
@ -198,6 +198,154 @@ class SignupTest < TestCase
:username => signup_user_email,
:password => 'some-pass-new2',
},
{
:execute => 'logout',
},
],
},
{
:name => 'reset password',
:action => [
# got to wrong url
{
:execute => 'navigate',
:to => browser_url + '/#password_reset_verify/not_existing_token',
},
{
:execute => 'watch_for',
:area => 'body',
:value => 'Token is invalid',
},
# correct way
{
:execute => 'click',
:css => 'a[href="#reset_password"]',
},
{
:execute => 'set',
:css => 'input[name="username"]',
:value => 'nonexisiting',
},
{
:execute => 'click',
:css => '.content .btn--primary',
},
{
:execute => 'watch_for',
:area => 'body',
:value => 'address invalid',
},
{
:execute => 'set',
:css => 'input[name="username"]',
:value => signup_user_email,
},
{
:execute => 'click',
:css => '.content .btn--primary',
},
{
:execute => 'watch_for',
:area => 'body',
:value => 'sent password reset instructions',
},
# redirect to "#password_reset_verify/#{token}" url by app, because of "developer_mode"
{
:execute => 'watch_for',
:area => 'body',
:value => 'Choose your new password',
},
# set new password
{
:execute => 'set',
:css => 'input[name="password"]',
:value => 'some',
},
{
:execute => 'set',
:css => 'input[name="password_confirm"]',
:value => 'some2',
},
{
:execute => 'click',
:css => '.content .btn--primary',
},
{
:execute => 'watch_for',
:area => 'body',
:value => 'passwords do not match',
},
{
:execute => 'set',
:css => 'input[name="password"]',
:value => 'some',
},
{
:execute => 'set',
:css => 'input[name="password_confirm"]',
:value => 'some',
},
{
:execute => 'click',
:css => '.content .btn--primary',
},
{
:execute => 'watch_for',
:area => 'body',
:value => 'it must be at least',
},
{
:execute => 'set',
:css => 'input[name="password"]',
:value => 'some-pass-new',
},
{
:execute => 'set',
:css => 'input[name="password_confirm"]',
:value => 'some-pass-new',
},
{
:execute => 'click',
:css => '.content .btn--primary',
},
{
:execute => 'watch_for',
:area => 'body',
:value => 'must contain at least 1 digit',
},
{
:execute => 'set',
:css => 'input[name="password"]',
:value => 'some-pass-new2',
},
{
:execute => 'set',
:css => 'input[name="password_confirm"]',
:value => 'some-pass-new2',
},
{
:execute => 'click',
:css => '.content .btn--primary',
},
{
:execute => 'watch_for',
:area => 'body',
:value => 'Your password has been changed',
},
{
:execute => 'wait',
:value => 5,
},
{
:execute => 'match',
:css => '.user-menu .user a',
:attribute => 'title',
:value => signup_user_email,
:match_result => true,
},
],
},
]