Merge pull request #293 from alphagov/single-verify-code

Changed registration flow to first send email verification link that
This commit is contained in:
Adam Shimali
2016-03-18 11:03:27 +00:00
23 changed files with 363 additions and 481 deletions

View File

@@ -1,91 +0,0 @@
from datetime import datetime, timedelta
from app.main.forms import VerifyForm
from app.main.dao import users_dao
from tests import create_test_user
def test_form_should_have_error_when_code_is_not_valid(app_,
mock_check_verify_code):
with app_.test_request_context(method='POST',
data={'sms_code': '12345aa', 'email_code': 'abcde'}) as req:
def _check_code(code, code_type):
return users_dao.check_verify_code('1', code, code_type)
form = VerifyForm(_check_code)
assert form.validate() is False
errors = form.errors
assert len(errors) == 2
expected = {'email_code': ['Code must be 5 digits', 'Code does not match'],
'sms_code': ['Code does not match', 'Code must be 5 digits']}
assert 'sms_code' in errors
assert set(errors) == set(expected)
def test_should_return_errors_when_code_missing(app_,
mock_check_verify_code):
with app_.test_request_context(method='POST',
data={}) as req:
def _check_code(code, code_type):
return users_dao.check_verify_code('1', code, code_type)
form = VerifyForm(_check_code)
assert form.validate() is False
errors = form.errors
expected = {'sms_code': ['SMS code can not be empty'],
'email_code': ['Email code can not be empty']}
assert len(errors) == 2
assert set(errors) == set(expected)
def test_should_return_errors_when_code_is_too_short(app_,
mock_check_verify_code):
with app_.test_request_context(method='POST',
data={'sms_code': '123', 'email_code': '123'}) as req:
def _check_code(code, code_type):
return users_dao.check_verify_code('1', code, code_type)
form = VerifyForm(_check_code)
assert form.validate() is False
errors = form.errors
expected = {'sms_code': ['Code must be 5 digits', 'Code does not match'],
'email_code': ['Code must be 5 digits', 'Code does not match']}
assert len(errors) == 2
assert set(errors) == set(expected)
def test_should_return_errors_when_code_does_not_match(app_,
mock_check_verify_code_code_not_found):
with app_.test_request_context(method='POST',
data={'sms_code': '34567', 'email_code': '34567'}) as req:
def _check_code(code, code_type):
return users_dao.check_verify_code('1', code, code_type)
form = VerifyForm(_check_code)
assert form.validate() is False
errors = form.errors
expected = {'sms_code': ['Code not found'],
'email_code': ['Code not found']}
assert len(errors) == 2
assert set(errors) == set(expected)
def test_should_return_errors_when_code_is_expired(app_,
mock_check_verify_code_code_expired):
with app_.test_request_context(method='POST',
data={'sms_code': '23456',
'email_code': '23456'}) as req:
def _check_code(code, code_type):
return users_dao.check_verify_code('1', code, code_type)
form = VerifyForm(_check_code)
assert form.validate() is False
errors = form.errors
expected = {'sms_code': ['Code has expired'],
'email_code': ['Code has expired']}
assert len(errors) == 2
assert set(errors) == set(expected)

View File

@@ -215,6 +215,7 @@ def test_new_user_accept_invite_completes_new_registration_redirects_to_verify(a
api_user_active,
mock_check_invite_token,
mock_dont_get_user_by_email,
mock_is_email_unique,
mock_register_user,
mock_send_verify_code,
mock_get_users_by_service,
@@ -266,6 +267,7 @@ def test_new_invited_user_verifies_and_added_to_service(app_,
api_user_active,
mock_check_invite_token,
mock_dont_get_user_by_email,
mock_is_email_unique,
mock_register_user,
mock_send_verify_code,
mock_check_verify_code,
@@ -299,6 +301,7 @@ def test_new_invited_user_verifies_and_added_to_service(app_,
# when they post codes back to admin user should be added to
# service and sent on to dash board
expected_permissions = ['send_messages', 'manage_service', 'manage_api_keys']
with client.session_transaction() as session:
new_user_id = session['user_id']
mock_add_user_to_service.assert_called_with(data['service'], new_user_id, expected_permissions)

View File

@@ -1,39 +1,30 @@
import pytest
from flask import url_for
from bs4 import BeautifulSoup
def test_should_render_email_verification_resent_show_email_address_and_resend_verify_email(app_,
mocker,
api_user_active,
mock_get_user_by_email,
mock_send_verify_email):
def test_should_render_email_code_not_received_template_and_populate_email_address(app_,
api_user_active,
mock_get_user_by_email,
mock_send_verify_code):
with app_.test_request_context():
with app_.test_client() as client:
with client.session_transaction() as session:
session['user_details'] = {
'id': api_user_active.id,
'email': api_user_active.email_address}
response = client.get(url_for('main.check_and_resend_email_code'))
response = client.get(url_for('main.resend_email_verification'))
assert response.status_code == 200
assert 'Check your email address is correct and then resend the confirmation code' \
in response.get_data(as_text=True)
assert 'value="test@user.gov.uk"' in response.get_data(as_text=True)
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
def test_should_check_and_resend_email_code_redirect_to_verify(app_,
api_user_active,
mock_get_user_by_email,
mock_update_user,
mock_send_verify_code):
with app_.test_request_context():
with app_.test_client() as client:
with client.session_transaction() as session:
session['user_details'] = {
'id': api_user_active.id,
'email': api_user_active.email_address}
response = client.post(url_for('main.check_and_resend_email_code'),
data={'email_address': 'test@user.gov.uk'})
assert response.status_code == 302
assert response.location == url_for('main.verify', _external=True)
assert page.h1.string == 'Check your email'
expected = "In order to verify your email address we've sent a new confirmation link to {}".format(api_user_active.email_address) # noqa
assert page.p.string == expected
mock_send_verify_email.assert_called_with(api_user_active.id, api_user_active.email_address)
def test_should_render_text_code_not_received_template(app_,
@@ -70,23 +61,6 @@ def test_should_check_and_redirect_to_verify(app_,
assert response.location == url_for('main.verify', _external=True)
def test_should_update_email_address_resend_code(app_,
api_user_active,
mock_get_user_by_email,
mock_update_user,
mock_send_verify_code):
with app_.test_request_context():
with app_.test_client() as client:
with client.session_transaction() as session:
session['user_details'] = {
'id': api_user_active.id,
'email': api_user_active.email_address}
response = client.post(url_for('main.check_and_resend_email_code'),
data={'email_address': 'new@address.gov.uk'})
assert response.status_code == 302
assert response.location == url_for('main.verify', _external=True)
def test_should_update_mobile_number_resend_code(app_,
api_user_active,
mock_get_user_by_email,

View File

@@ -1,4 +1,8 @@
from flask import url_for
from flask import (
url_for,
session
)
from bs4 import BeautifulSoup
@@ -24,24 +28,31 @@ def test_logged_in_user_redirects_to_choose_service(app_,
assert response.location == url_for('main.choose_service', _external=True)
def test_process_register_creates_new_user(app_,
mock_send_verify_code,
mock_register_user,
mock_get_user_by_email_not_found,
mock_login):
user_data = {
'name': 'Some One Valid',
'email_address': 'notfound@example.gov.uk',
'mobile_number': '+4407700900460',
'password': 'validPassword!'
}
def test_register_creates_new_user_and_redirects_to_continue_page(app_,
mock_send_verify_code,
mock_register_user,
mock_get_user_by_email_not_found,
mock_is_email_unique,
mock_send_verify_email,
mock_login):
user_data = {'name': 'Some One Valid',
'email_address': 'notfound@example.gov.uk',
'mobile_number': '+4407700900460',
'password': 'validPassword!'
}
with app_.test_request_context():
response = app_.test_client().post(url_for('main.register'),
data=user_data)
response = app_.test_client().post(url_for('main.register'), data=user_data)
assert response.status_code == 302
assert response.location == url_for('main.verify', _external=True)
assert mock_register_user.called
assert response.location == url_for('main.registration_continue', _external=True)
from unittest.mock import ANY
mock_send_verify_email.assert_called_with(ANY, user_data['email_address'])
mock_register_user.assert_called_with(user_data['name'],
user_data['email_address'],
user_data['mobile_number'],
user_data['password'])
def test_process_register_returns_200_when_mobile_number_is_invalid(app_,
@@ -59,7 +70,7 @@ def test_process_register_returns_200_when_mobile_number_is_invalid(app_,
assert 'Must not contain letters or symbols' in response.get_data(as_text=True)
def test_should_return_400_when_email_is_not_gov_uk(app_,
def test_should_return_200_when_email_is_not_gov_uk(app_,
mock_send_verify_code,
mock_get_user_by_email,
mock_login):
@@ -74,11 +85,13 @@ def test_should_return_400_when_email_is_not_gov_uk(app_,
assert 'Enter a gov.uk email address' in response.get_data(as_text=True)
def test_should_add_verify_codes_on_session(app_,
def test_should_add_user_details_to_session(app_,
mock_send_verify_code,
mock_register_user,
mock_get_user,
mock_get_user_by_email_not_found,
mock_is_email_unique,
mock_send_verify_email,
mock_login):
user_data = {
'name': 'Test Codes',
@@ -91,11 +104,12 @@ def test_should_add_verify_codes_on_session(app_,
with app_.test_client() as client:
response = client.post(url_for('main.register'),
data=user_data)
assert response.status_code == 302
assert 'notify_admin_session' in response.headers.get('Set-Cookie')
assert session['user_details']['email'] == user_data['email_address']
def test_should_return_400_if_password_is_blacklisted(app_,
def test_should_return_200_if_password_is_blacklisted(app_,
mock_get_user_by_email,
mock_login):
with app_.test_request_context():

View File

@@ -2,105 +2,109 @@ import json
from flask import url_for
def test_should_show_overview_page(app_,
api_user_active,
mock_login,
mock_get_user):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
response = client.get(url_for('main.user_profile'))
# def test_should_show_overview_page(app_,
# api_user_active,
# mock_login,
# mock_get_user):
# with app_.test_request_context():
# with app_.test_client() as client:
# client.login(api_user_active)
# response = client.get(url_for('main.user_profile'))
assert 'Your profile' in response.get_data(as_text=True)
assert response.status_code == 200
# assert 'Your profile' in response.get_data(as_text=True)
# assert response.status_code == 200
def test_should_show_name_page(app_,
api_user_active,
mock_login,
mock_get_user):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
response = client.get(url_for('main.user_profile_name'))
# def test_should_show_name_page(app_,
# api_user_active,
# mock_login,
# mock_get_user):
# with app_.test_request_context():
# with app_.test_client() as client:
# client.login(api_user_active)
# response = client.get(url_for('main.user_profile_name'))
assert 'Change your name' in response.get_data(as_text=True)
assert response.status_code == 200
# assert 'Change your name' in response.get_data(as_text=True)
# assert response.status_code == 200
def test_should_redirect_after_name_change(app_,
api_user_active,
mock_login,
mock_update_user,
mock_get_user):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
new_name = 'New Name'
data = {'new_name': new_name}
response = client.post(url_for(
'main.user_profile_name'), data=data)
# def test_should_redirect_after_name_change(app_,
# api_user_active,
# mock_login,
# mock_update_user,
# mock_get_user):
# with app_.test_request_context():
# with app_.test_client() as client:
# client.login(api_user_active)
# new_name = 'New Name'
# data = {'new_name': new_name}
# response = client.post(url_for(
# 'main.user_profile_name'), data=data)
assert response.status_code == 302
assert response.location == url_for(
'main.user_profile', _external=True)
api_user_active.name = new_name
assert mock_update_user.called
# assert response.status_code == 302
# assert response.location == url_for(
# 'main.user_profile', _external=True)
# api_user_active.name = new_name
# assert mock_update_user.called
def test_should_show_email_page(app_,
api_user_active,
mock_login,
mock_get_user):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
response = client.get(url_for(
'main.user_profile_email'))
# def test_should_show_email_page(app_,
# api_user_active,
# mock_login,
# mock_get_user):
# with app_.test_request_context():
# with app_.test_client() as client:
# client.login(api_user_active)
# response = client.get(url_for(
# 'main.user_profile_email'))
assert 'Change your email address' in response.get_data(as_text=True)
assert response.status_code == 200
# assert 'Change your email address' in response.get_data(as_text=True)
# assert response.status_code == 200
def test_should_redirect_after_email_change(app_,
api_user_active,
mock_login,
mock_get_user,
mock_get_user_by_email_not_found):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
data = {'email_address': 'new_notify@notify.gov.uk'}
response = client.post(
url_for('main.user_profile_email'),
data=data)
# def test_should_redirect_after_email_change(app_,
# api_user_active,
# mock_login,
# mock_get_user,
# mock_get_user_by_email_not_found,
# mock_is_email_unique):
# with app_.test_request_context():
# with app_.test_client() as client:
# client.login(api_user_active)
# data = {'email_address': 'new_notify@notify.gov.uk'}
# response = client.post(
# url_for('main.user_profile_email'),
# data=data)
assert response.status_code == 302
assert response.location == url_for(
'main.user_profile_email_authenticate', _external=True)
# assert response.status_code == 302
# assert response.location == url_for(
# 'main.user_profile_email_authenticate', _external=True)
def test_should_show_authenticate_after_email_change(app_,
api_user_active,
mock_login,
mock_get_user,
mock_verify_password):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)
with client.session_transaction() as session:
session['new-email'] = 'new_notify@notify.gov.uk'
response = client.get(url_for('main.user_profile_email_authenticate'))
# def test_should_show_authenticate_after_email_change(app_,
# api_user_active,
# mock_login,
# mock_get_user,
# mock_verify_password):
# with app_.test_request_context():
# with app_.test_client() as client:
# client.login(api_user_active)
# with client.session_transaction() as session:
# session['new-email'] = 'new_notify@notify.gov.uk'
# response = client.get(url_for('main.user_profile_email_authenticate'))
assert 'Change your email address' in response.get_data(as_text=True)
assert 'Confirm' in response.get_data(as_text=True)
assert response.status_code == 200
# assert 'Change your email address' in response.get_data(as_text=True)
# assert 'Confirm' in response.get_data(as_text=True)
# assert response.status_code == 200
def test_should_redirect_after_email_change_confirm(app_,
api_user_active,
mock_login,
mock_get_user):
mock_get_user,
mock_verify_password,
mock_send_verify_code,
mock_is_email_unique):
with app_.test_request_context():
with app_.test_client() as client:
client.login(api_user_active)

View File

@@ -1,5 +1,7 @@
from flask import url_for
from bs4 import BeautifulSoup
def test_should_return_verify_template(app_,
api_user_active,
@@ -12,26 +14,28 @@ def test_should_return_verify_template(app_,
session['user_details'] = {'email_address': api_user_active.email_address, 'id': api_user_active.id}
response = client.get(url_for('main.verify'))
assert response.status_code == 200
assert (
"Weve sent you confirmation codes by email and text message."
) in response.get_data(as_text=True)
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.text == 'Text verification'
assert page.p.text == "We've sent you a text message with a verification code."
def test_should_redirect_to_add_service_when_code_are_correct(app_,
api_user_active,
mock_get_user,
mock_update_user,
mock_check_verify_code):
def test_should_redirect_to_add_service_when_sms_code_is_correct(app_,
api_user_active,
mock_get_user,
mock_update_user,
mock_check_verify_code):
with app_.test_request_context():
with app_.test_client() as client:
with client.session_transaction() as session:
session['user_details'] = {'email_address': api_user_active.email_address, 'id': api_user_active.id}
response = client.post(url_for('main.verify'),
data={'sms_code': '12345',
'email_code': '23456'})
data={'sms_code': '12345'})
assert response.status_code == 302
assert response.location == url_for('main.add_service', first='first', _external=True)
mock_check_verify_code.assert_called_once_with(api_user_active.id, '12345', 'sms')
def test_should_activate_user_after_verify(app_,
api_user_active,
@@ -44,45 +48,20 @@ def test_should_activate_user_after_verify(app_,
with client.session_transaction() as session:
session['user_details'] = {'email_address': api_user_active.email_address, 'id': api_user_active.id}
client.post(url_for('main.verify'),
data={'sms_code': '12345',
'email_code': '23456'})
data={'sms_code': '12345'})
assert mock_update_user.called
def test_should_return_200_when_codes_are_wrong(app_,
api_user_active,
mock_get_user,
mock_check_verify_code_code_not_found):
def test_should_return_200_when_sms_code_is_wrong(app_,
api_user_active,
mock_get_user,
mock_check_verify_code_code_not_found):
with app_.test_request_context():
with app_.test_client() as client:
with client.session_transaction() as session:
session['user_details'] = {'email_address': api_user_active.email_address, 'id': api_user_active.id}
response = client.post(url_for('main.verify'),
data={'sms_code': '12345',
'email_code': '23456'})
data={'sms_code': '12345'})
assert response.status_code == 200
resp_data = response.get_data(as_text=True)
assert resp_data.count('Code not found') == 2
def test_should_only_check_codes_in_validation_if_both_are_present(app_,
api_user_active,
mock_get_user,
mock_update_user,
mock_check_verify_code):
with app_.test_request_context():
with app_.test_client() as client:
with client.session_transaction() as session:
session['user_details'] = {'email_address': api_user_active.email_address, 'id': api_user_active.id}
response = client.post(url_for('main.verify'), data={'sms_code': '12345'})
assert response.status_code == 200
assert not mock_check_verify_code.called
response = client.post(url_for('main.verify'), data={'email_code': '12345'})
assert response.status_code == 200
assert not mock_check_verify_code.called
response = client.post(url_for('main.verify'), data={'sms_code': '12345', 'email_code': '12345'})
assert response.status_code == 302
assert mock_check_verify_code.called
assert mock_check_verify_code.call_count == 2
assert resp_data.count('Code not found') == 1

View File

@@ -445,7 +445,12 @@ def mock_update_user(mocker):
@pytest.fixture(scope='function')
def mock_is_email_unique(mocker):
return mocker.patch('app.user_api_client.get_user_by_email', return_value=None)
return mocker.patch('app.user_api_client.is_email_unique', return_value=True)
@pytest.fixture(scope='function')
def mock_is_email_not_unique(mocker):
return mocker.patch('app.user_api_client.is_email_unique', return_value=False)
@pytest.fixture(scope='function')
@@ -518,6 +523,11 @@ def mock_send_verify_code(mocker):
return mocker.patch('app.user_api_client.send_verify_code')
@pytest.fixture(scope='function')
def mock_send_verify_email(mocker):
return mocker.patch('app.user_api_client.send_verify_email')
@pytest.fixture(scope='function')
def mock_check_verify_code(mocker):
def _verify(user_id, code, code_type):