Group form tests in a directory

This makes it clearer we have tests for the code in forms.py, which
I missed initially. In future we could also split up forms.py in a
similar way, as it's currently _very long_.

As part of grouping tests for code in forms.py, I've extracted some
from test_validators.py, so that what remains is focussed on testing
the code in validators.py.
This commit is contained in:
Ben Thorner
2022-03-11 11:12:26 +00:00
parent 21452649fd
commit e0b62bed70
9 changed files with 98 additions and 93 deletions

View File

@@ -0,0 +1,45 @@
import pytest
from freezegun import freeze_time
from app.main.forms import ChooseTimeForm
@freeze_time("2016-01-01 11:09:00.061258")
def test_form_contains_next_24h(notify_admin):
choices = ChooseTimeForm().scheduled_for.choices
# Friday
assert choices[0] == ('', 'Now')
assert choices[1] == ('2016-01-01T12:00:00', 'Today at midday')
assert choices[13] == ('2016-01-02T00:00:00', 'Today at midnight')
# Saturday
assert choices[14] == ('2016-01-02T01:00:00', 'Tomorrow at 1am')
assert choices[37] == ('2016-01-03T00:00:00', 'Tomorrow at midnight')
# Sunday
assert choices[38] == ('2016-01-03T01:00:00', 'Sunday at 1am')
# Monday
assert choices[84] == ('2016-01-04T23:00:00', 'Monday at 11pm')
assert choices[85] == ('2016-01-05T00:00:00', 'Monday at midnight')
with pytest.raises(IndexError):
assert choices[
12 + # hours left in the day
(3 * 24) + # 3 days
2 # magic number
]
@freeze_time("2016-01-01 11:09:00.061258")
def test_form_defaults_to_now(notify_admin):
assert ChooseTimeForm().scheduled_for.data == ''
@freeze_time("2016-01-01 11:09:00.061258")
def test_form_contains_next_three_days(notify_admin):
assert ChooseTimeForm().scheduled_for.categories == [
'Later today', 'Tomorrow', 'Sunday', 'Monday'
]

View File

@@ -0,0 +1,50 @@
import pytest
from werkzeug.datastructures import MultiDict
from app.main.forms import CreateKeyForm
@pytest.mark.parametrize('expiry_date, expected_errors', (
(None, ['A key with this name already exists']),
('2001-01-01 01:01:01', None),
))
def test_return_validation_error_when_key_name_exists(
client_request,
expiry_date,
expected_errors,
):
_existing_keys = [
{
'name': 'some key',
'expiry_date': expiry_date,
},
{
'name': 'another key',
'expiry_date': None,
},
]
form = CreateKeyForm(
_existing_keys,
formdata=MultiDict([('key_name', 'Some key')])
)
form.key_type.choices = [('a', 'a'), ('b', 'b')]
form.validate()
assert form.errors.get('key_name') == expected_errors
@pytest.mark.parametrize(
'key_type, expected_error', [
('', 'Select the type of key'),
('invalid', 'Select the type of key')
]
)
def test_return_validation_error_when_key_type_not_chosen(client_request, key_type, expected_error):
form = CreateKeyForm(
[],
formdata=MultiDict([('key_name', 'Some key'), ('key_type', key_type)]))
form.key_type.choices = [('a', 'a'), ('b', 'b')]
form.validate()
assert form.errors['key_type'] == [expected_error]

View File

@@ -0,0 +1,71 @@
import pytest
from app.main.forms import get_placeholder_form_instance
def test_form_class_not_mutated(notify_admin):
with notify_admin.test_request_context(
method='POST',
data={'placeholder_value': ''}
):
form1 = get_placeholder_form_instance('name', {}, 'sms')
form2 = get_placeholder_form_instance('city', {}, 'sms')
assert not form1.validate_on_submit()
assert not form2.validate_on_submit()
assert str(form1.placeholder_value.label) == '<label for="placeholder_value">name</label>'
assert str(form2.placeholder_value.label) == '<label for="placeholder_value">city</label>'
@pytest.mark.parametrize('service_can_send_international_sms, placeholder_name, template_type, value, expected_error', [
(False, 'email address', 'email', '', 'Cannot be empty'),
(False, 'email address', 'email', '12345', 'Enter a valid email address'),
(False, 'email address', 'email', '“bad”@email-address.com', 'Enter a valid email address'),
(False, 'email address', 'email', 'test@example.com', None),
(False, 'email address', 'email', 'test@example.gov.uk', None),
(False, 'phone number', 'sms', '', 'Cannot be empty'),
(False, 'phone number', 'sms', '+1-2345-678890', 'Not a UK mobile number'),
(False, 'phone number', 'sms', '07900900123', None),
(False, 'phone number', 'sms', '+44(0)7900 900-123', None),
(True, 'phone number', 'sms', '+123', 'Not enough digits'),
(True, 'phone number', 'sms', '+44(0)7900 900-123', None),
(True, 'phone number', 'sms', '+1-2345-678890', None),
(False, 'anything else', 'sms', '', 'Cannot be empty'),
(False, 'anything else', 'email', '', 'Cannot be empty'),
(True, 'phone number', 'sms', 'invalid', 'Must not contain letters or symbols'),
(True, 'phone number', 'email', 'invalid', None),
(True, 'phone number', 'letter', 'invalid', None),
(True, 'email address', 'sms', 'invalid', None),
])
def test_validates_recipients(
notify_admin,
placeholder_name,
template_type,
value,
service_can_send_international_sms,
expected_error,
):
with notify_admin.test_request_context(
method='POST',
data={'placeholder_value': value}
):
form = get_placeholder_form_instance(
placeholder_name,
{},
template_type,
allow_international_phone_numbers=service_can_send_international_sms,
)
if expected_error:
assert not form.validate_on_submit()
assert form.placeholder_value.errors[0] == expected_error
else:
assert form.validate_on_submit()

View File

@@ -0,0 +1,61 @@
import pytest
from app.main.forms import RegisterUserForm
@pytest.mark.parametrize('password', [
'govuknotify', '11111111', 'kittykat', 'blackbox'
])
def test_should_raise_validation_error_for_password(
client_request,
mock_get_user_by_email,
password,
):
form = RegisterUserForm()
form.name.data = 'test'
form.email_address.data = 'teset@example.gov.uk'
form.mobile_number.data = '441231231231'
form.password.data = password
form.validate()
assert 'Choose a password thats harder to guess' in form.errors['password']
def test_valid_email_not_in_valid_domains(
client_request,
mock_get_organisations,
):
form = RegisterUserForm(email_address="test@test.com", mobile_number='441231231231')
assert not form.validate()
assert "Enter a public sector email address" in form.errors['email_address'][0]
def test_valid_email_in_valid_domains(
client_request,
):
form = RegisterUserForm(
name="test",
email_address="test@my.gov.uk",
mobile_number='4407888999111',
password='an uncommon password')
form.validate()
assert form.errors == {}
def test_invalid_email_address_error_message(
client_request,
mock_get_organisations,
):
form = RegisterUserForm(
name="test",
email_address="test.com",
mobile_number='4407888999111',
password='1234567890')
assert not form.validate()
form = RegisterUserForm(
name="test",
email_address="test.com",
mobile_number='4407888999111',
password='1234567890')
assert not form.validate()

View File

@@ -0,0 +1,92 @@
import pytest
from app.main.forms import ServiceContactDetailsForm
def test_form_fails_validation_with_no_radio_buttons_selected(notify_admin):
with notify_admin.test_request_context(method='POST', data={}):
form = ServiceContactDetailsForm()
assert not form.validate_on_submit()
assert len(form.errors) == 1
assert form.errors['contact_details_type'] == ['Select an option']
@pytest.mark.parametrize('selected_radio_button, selected_text_box, text_box_data', [
('email_address', 'url', 'http://www.example.com'),
('phone_number', 'url', 'http://www.example.com'),
('url', 'email_address', 'user@example.com'),
('phone_number', 'email_address', 'user@example.com'),
('url', 'phone_number', '0207 123 4567'),
('email_address', 'phone_number', '0207 123 4567'),
])
def test_form_fails_validation_when_radio_button_selected_and_text_box_filled_in_do_not_match(
notify_admin,
selected_radio_button,
selected_text_box,
text_box_data
):
data = {'contact_details_type': selected_radio_button, selected_text_box: text_box_data}
with notify_admin.test_request_context(method='POST', data=data):
form = ServiceContactDetailsForm()
assert not form.validate_on_submit()
assert len(form.errors) == 1
assert form.errors[selected_radio_button] == ['This field is required.']
@pytest.mark.parametrize('selected_field, url, email_address, phone_number', [
('url', 'http://www.example.com', 'invalid-email.com', 'phone'),
('email_address', 'www.invalid-url.com', 'me@example.com', 'phone'),
('phone_number', 'www.invalid-url.com', 'invalid-email.com', '0207 123 4567'),
])
def test_form_only_validates_the_field_which_matches_the_selected_radio_button(
notify_admin,
selected_field,
url,
email_address,
phone_number,
):
data = {'contact_details_type': selected_field,
'url': url,
'email_address': email_address,
'phone_number': phone_number}
with notify_admin.test_request_context(method='POST', data=data):
form = ServiceContactDetailsForm()
assert form.validate_on_submit()
def test_form_url_validation_fails_with_invalid_url_field(notify_admin):
data = {'contact_details_type': 'url', 'url': 'www.example.com'}
with notify_admin.test_request_context(method='POST', data=data):
form = ServiceContactDetailsForm()
assert not form.validate_on_submit()
assert len(form.errors) == 1
assert len(form.errors['url']) == 1
def test_form_email_validation_fails_with_invalid_email_address_field(notify_admin):
data = {'contact_details_type': 'email_address', 'email_address': '1@co'}
with notify_admin.test_request_context(method='POST', data=data):
form = ServiceContactDetailsForm()
assert not form.validate_on_submit()
assert len(form.errors) == 1
assert len(form.errors['email_address']) == 2
def test_form_phone_number_validation_fails_with_invalid_phone_number_field(notify_admin):
data = {'contact_details_type': 'phone_number', 'phone_number': '1235 A'}
with notify_admin.test_request_context(method='POST', data=data):
form = ServiceContactDetailsForm()
assert not form.validate_on_submit()
assert len(form.errors) == 1
assert form.errors['phone_number'] == ['Must be a valid phone number']

View File

@@ -0,0 +1,37 @@
import pytest
from app.main.forms import ServiceSmsSenderForm
@pytest.mark.parametrize(
"sms_sender,error_expected,error_message",
[
('', True, 'Cannot be empty'),
('22', True, 'Enter 3 characters or more'),
('333', False, None),
('elevenchars', False, None), # 11 chars
('twelvecharas', True, 'Enter 11 characters or fewer'), # 12 chars
('###', True, 'Use letters and numbers only'),
('00111222333', True, 'Cannot start with 00'),
('UK_GOV', False, None), # Underscores are allowed
('UK.GOV', False, None), # Full stops are allowed
("'UC'", False, None), # Straight single quotes are allowed
]
)
def test_sms_sender_form_validation(
client_request,
mock_get_user_by_email,
sms_sender,
error_expected,
error_message
):
form = ServiceSmsSenderForm()
form.sms_sender.data = sms_sender
form.validate()
if error_expected:
assert form.errors
assert error_message == form.errors['sms_sender'][0]
else:
assert not form.errors

View File

@@ -0,0 +1,32 @@
import pytest
from wtforms import Form, StringField
from app.main.forms import StripWhitespaceForm, StripWhitespaceStringField
class ExampleForm(StripWhitespaceForm):
foo = StringField('Foo')
class ExampleFormSpecialField(Form):
foo = StripWhitespaceStringField('foo')
@pytest.mark.parametrize('submitted_data', [
'bar',
' bar ',
"""
\t bar
""",
' \u180E\u200B \u200C bar \u200D \u2060\uFEFF ',
])
@pytest.mark.parametrize('form', [
ExampleForm,
ExampleFormSpecialField,
])
def test_form_strips_all_whitespace(
notify_admin,
form,
submitted_data,
):
assert form(foo=submitted_data).foo.data == 'bar'

View File

@@ -0,0 +1,80 @@
import pytest
from app import user_api_client
from app.main.forms import TwoFactorForm
def _check_code(code):
return user_api_client.check_verify_code('1', code, "sms")
@pytest.mark.parametrize('post_data', [
{'sms_code': '12345'},
{'sms_code': ' 12345 '},
{'sms_code': '12 34 5'},
{'sms_code': '1-23-45'},
])
def test_form_is_valid_returns_no_errors(
notify_admin,
mock_check_verify_code,
post_data,
):
with notify_admin.test_request_context(method='POST', data=post_data):
form = TwoFactorForm(_check_code)
assert form.validate() is True
assert form.errors == {}
mock_check_verify_code.assert_called_once_with('1', '12345', 'sms')
@pytest.mark.parametrize('post_data, expected_error', (
(
{'sms_code': '1234'},
'Not enough numbers',
),
(
{'sms_code': '123456'},
'Too many numbers',
),
(
{},
'Cannot be empty',
),
(
{'sms_code': '12E45'},
'Numbers only',
),
(
{'sms_code': ' ! 2 3 4 5'},
'Numbers only',
),
))
def test_check_verify_code_returns_errors(
notify_admin,
post_data,
expected_error,
mock_check_verify_code,
):
with notify_admin.test_request_context(method='POST', data=post_data):
form = TwoFactorForm(_check_code)
assert form.validate() is False
assert form.errors == {'sms_code': [expected_error]}
def test_check_verify_code_returns_error_when_code_has_expired(
notify_admin,
mock_check_verify_code_code_expired,
):
with notify_admin.test_request_context(method='POST', data={'sms_code': '99999'}):
form = TwoFactorForm(_check_code)
assert form.validate() is False
assert form.errors == {'sms_code': ['Code has expired']}
def test_check_verify_code_returns_error_when_code_was_not_found(
notify_admin,
mock_check_verify_code_code_not_found,
):
with notify_admin.test_request_context(method='POST', data={'sms_code': '99999'}):
form = TwoFactorForm(_check_code)
assert form.validate() is False
assert form.errors == {'sms_code': ['Code not found']}