Merge branch 'master' into flask-login-again

This commit is contained in:
Chris Hill-Scott
2020-04-01 14:29:16 +01:00
committed by GitHub
81 changed files with 3384 additions and 739 deletions
+10
View File
@@ -44,6 +44,16 @@ MockRecipients = namedtuple(
'email',
['fix 3 email addresses']
),
(
{2}, [], [], [],
'letter',
['fix 1 address']
),
(
{2, 4}, [], [], [],
'letter',
['fix 2 addresses']
),
(
{2}, {3}, [], [],
'sms',
+2
View File
@@ -384,6 +384,7 @@ def test_service_navigation_for_org_user(
(
'Templates',
'Sent messages',
'Uploads',
'Team members',
),
403,
@@ -393,6 +394,7 @@ def test_service_navigation_for_org_user(
(
'Templates',
'Sent messages',
'Uploads',
'Team members',
'Usage',
),
+1 -1
View File
@@ -36,7 +36,7 @@ def test_valid_email_not_in_valid_domains(
):
form = RegisterUserForm(email_address="test@test.com", mobile_number='441231231231')
assert not form.validate()
assert "Enter a government email address" in form.errors['email_address'][0]
assert "Enter a public sector email address" in form.errors['email_address'][0]
def test_valid_email_in_valid_domains(
+2 -2
View File
@@ -149,7 +149,7 @@ def test_accepting_invite_removes_invite_from_session(
mock_get_billable_units,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
fake_uuid,
user,
landing_page_title,
@@ -477,7 +477,7 @@ def test_new_invited_user_verifies_and_added_to_service(
mock_get_service_statistics,
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
mock_create_event,
mocker,
):
+1 -2
View File
@@ -272,12 +272,11 @@ def test_accept_agreement_page_populates(
(
{
'version': '',
'who': '',
'on_behalf_of_name': '',
'on_behalf_of_email': '',
},
[
'This field is required.',
'Not a valid choice',
'Must be a number',
],
),
+44 -139
View File
@@ -1,7 +1,6 @@
import copy
import json
from datetime import datetime
from unittest.mock import call
import pytest
from bs4 import BeautifulSoup
@@ -144,7 +143,7 @@ def test_get_started(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
mocker.patch(
'app.template_statistics_client.get_template_statistics_for_service',
@@ -169,7 +168,7 @@ def test_get_started_is_hidden_once_templates_exist(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
mocker.patch(
'app.template_statistics_client.get_template_statistics_for_service',
@@ -195,7 +194,7 @@ def test_inbound_messages_not_visible_to_service_without_permissions(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
service_one['permissions'] = []
@@ -220,7 +219,7 @@ def test_inbound_messages_shows_count_of_messages_when_there_are_messages(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
service_one['permissions'] = ['inbound_sms']
page = client_request.get(
@@ -247,7 +246,7 @@ def test_inbound_messages_shows_count_of_messages_when_there_are_no_messages(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary_with_no_messages,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
service_one['permissions'] = ['inbound_sms']
page = client_request.get(
@@ -489,7 +488,7 @@ def test_returned_letters_not_visible_if_service_has_no_returned_letters(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
page = client_request.get(
'main.service_dashboard',
@@ -512,21 +511,11 @@ def test_returned_letters_shows_count_of_recently_returned_letters(
mock_get_inbound_sms_summary,
):
mocker.patch(
'app.service_api_client.get_returned_letter_summary',
return_value=[
# Today (should be counted)
{
'returned_letter_count': 1000, 'reported_at': '2020-01-10'
},
# Just within the last 7 days (should be counted)
{
'returned_letter_count': 3000, 'reported_at': '2020-01-3'
},
# Just after the last 7 days (should not be counted)
{
'returned_letter_count': 2000, 'reported_at': '2020-01-2'
},
],
'app.service_api_client.get_returned_letter_statistics',
return_value={
'returned_letter_count': 4000,
'most_recent_report': '2020-01-10',
},
)
page = client_request.get(
'main.service_dashboard',
@@ -541,29 +530,29 @@ def test_returned_letters_shows_count_of_recently_returned_letters(
)
@pytest.mark.parametrize('reporting_date, expected_message', (
('2020-02-02', (
@pytest.mark.parametrize('reporting_date, count, expected_message', (
('2020-02-02', 1, (
'1 returned letter latest report today'
)),
('2020-02-01', (
('2020-02-01', 1, (
'1 returned letter latest report yesterday'
)),
('2020-01-31', (
('2020-01-31', 1, (
'1 returned letter latest report 2 days ago'
)),
('2020-01-26', (
('2020-01-26', 1, (
'1 returned letter latest report 7 days ago'
)),
('2020-01-25', (
('2020-01-25', 0, (
'0 returned letters latest report 8 days ago'
)),
('2020-01-01', (
('2020-01-01', 0, (
'0 returned letters latest report 1 month ago'
)),
('2019-09-09', (
('2019-09-09', 0, (
'0 returned letters latest report 4 months ago'
)),
('2010-10-10', (
('2010-10-10', 0, (
'0 returned letters latest report 9 years ago'
)),
))
@@ -580,15 +569,15 @@ def test_returned_letters_only_counts_recently_returned_letters(
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary_with_no_messages,
reporting_date,
count,
expected_message,
):
mocker.patch(
'app.service_api_client.get_returned_letter_summary',
return_value=[
{
'returned_letter_count': 1, 'reported_at': reporting_date
},
],
'app.service_api_client.get_returned_letter_statistics',
return_value={
'returned_letter_count': count,
'most_recent_report': reporting_date,
},
)
page = client_request.get(
'main.service_dashboard',
@@ -610,7 +599,7 @@ def test_should_show_recent_templates_on_dashboard(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
mock_template_stats = mocker.patch('app.template_statistics_client.get_template_statistics_for_service',
return_value=copy.deepcopy(stub_template_stats))
@@ -664,7 +653,7 @@ def test_should_not_show_recent_templates_on_dashboard_if_only_one_template_used
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
stats,
):
mock_template_stats = mocker.patch(
@@ -819,7 +808,7 @@ def test_should_show_upcoming_jobs_on_dashboard(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
page = client_request.get(
'main.service_dashboard',
@@ -876,7 +865,7 @@ def test_correct_font_size_for_big_numbers(
mock_get_jobs,
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
service_one,
permissions,
totals,
@@ -903,56 +892,6 @@ def test_correct_font_size_for_big_numbers(
) == 3
@freeze_time("2016-01-01 11:09:00.061258")
def test_should_show_recent_jobs_on_dashboard(
client_request,
mock_get_service_templates,
mock_get_template_statistics,
mock_get_service_statistics,
mock_get_jobs,
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
):
page = client_request.get(
'main.service_dashboard',
service_id=SERVICE_ONE_ID,
)
third_call = mock_get_jobs.call_args_list[2]
assert third_call[0] == (SERVICE_ONE_ID,)
assert third_call[1]['limit_days'] == 7
assert 'scheduled' not in third_call[1]['statuses']
table_rows = page.select_one('tbody').select('tr')
assert len(table_rows) == 4
for index, filename in enumerate((
"export 1/1/2016.xls",
"all email addresses.xlsx",
"applicants.ods",
"thisisatest.csv",
)):
assert filename in table_rows[index].find_all('th')[0].text
assert 'Sent today at 11:09' in table_rows[index].find_all('th')[0].text
assert normalize_spaces(
table_rows[index].select_one('td').text
) == (
'1 sending 0 delivered 0 failed'
)
@pytest.mark.parametrize('extra_permissions', (
pytest.param(
[],
marks=pytest.mark.xfail(raises=AssertionError),
),
pytest.param(
['upload_letters']
),
))
def test_should_not_show_jobs_on_dashboard_for_users_with_uploads_page(
client_request,
service_one,
@@ -963,10 +902,8 @@ def test_should_not_show_jobs_on_dashboard_for_users_with_uploads_page(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
extra_permissions,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
service_one['permissions'] += extra_permissions
page = client_request.get(
'main.service_dashboard',
service_id=SERVICE_ONE_ID,
@@ -1160,7 +1097,7 @@ def test_menu_send_messages(
mock_get_usage,
mock_get_inbound_sms_summary,
mock_get_free_sms_fragment_limit,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
service_one['permissions'] = ['email', 'sms', 'letter', 'upload_letters']
@@ -1196,7 +1133,7 @@ def test_menu_send_messages_when_service_does_not_have_upload_letters_permission
mock_get_usage,
mock_get_inbound_sms_summary,
mock_get_free_sms_fragment_limit,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
with app_.test_request_context():
resp = _test_dashboard_menu(
@@ -1221,7 +1158,7 @@ def test_menu_manage_service(
mock_get_service_statistics,
mock_get_usage,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
mock_get_free_sms_fragment_limit,
):
with app_.test_request_context():
@@ -1253,7 +1190,7 @@ def test_menu_manage_api_keys(
mock_get_service_statistics,
mock_get_usage,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
mock_get_free_sms_fragment_limit,
):
with app_.test_request_context():
@@ -1283,7 +1220,7 @@ def test_menu_all_services_for_platform_admin_user(
mock_get_service_statistics,
mock_get_usage,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
mock_get_free_sms_fragment_limit,
):
with app_.test_request_context():
@@ -1316,7 +1253,7 @@ def test_route_for_service_permissions(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
with app_.test_request_context():
validate_route_permission(
@@ -1370,7 +1307,7 @@ def test_service_dashboard_updates_gets_dashboard_totals(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
mocker.patch('app.main.views.dashboard.get_dashboard_totals', return_value={
'email': {'requested': 123, 'delivered': 0, 'failed': 0},
@@ -1546,38 +1483,6 @@ def test_get_tuples_of_financial_years_defaults_to_2015():
))[0]
@freeze_time("2016-01-01 11:09:00.061258")
def test_should_show_all_jobs_with_valid_statuses(
logged_in_client,
mock_get_template_statistics,
mock_get_service_statistics,
mock_get_service_templates_when_no_templates_exist,
mock_get_jobs,
mock_get_usage,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_free_sms_fragment_limit,
):
logged_in_client.get(url_for('main.service_dashboard', service_id=SERVICE_ONE_ID))
first_call = mock_get_jobs.call_args_list[0]
# first call - checking for any jobs
assert first_call == call(SERVICE_ONE_ID)
second_call = mock_get_jobs.call_args_list[1]
# second call - scheduled jobs only
assert second_call == call(SERVICE_ONE_ID, statuses=['scheduled'])
# third call - everything but scheduled and cancelled
third_call = mock_get_jobs.call_args_list[2]
assert third_call == call(SERVICE_ONE_ID, limit_days=7, statuses={
'pending',
'in progress',
'finished',
'sending limits exceeded',
'ready to send',
'sent to dvla'
})
def test_org_breadcrumbs_do_not_show_if_service_has_no_org(
client_request,
mock_get_template_statistics,
@@ -1585,7 +1490,7 @@ def test_org_breadcrumbs_do_not_show_if_service_has_no_org(
mock_get_jobs,
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
page = client_request.get('main.service_dashboard', service_id=SERVICE_ONE_ID)
@@ -1600,7 +1505,7 @@ def test_org_breadcrumbs_do_not_show_if_user_is_not_an_org_member(
active_caseworking_user,
client_request,
mock_get_template_folders,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
):
# active_caseworking_user is not an org member
@@ -1623,7 +1528,7 @@ def test_org_breadcrumbs_show_if_user_is_a_member_of_the_services_org(
mock_get_jobs,
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
active_user_with_permissions,
client_request,
):
@@ -1651,7 +1556,7 @@ def test_org_breadcrumbs_do_not_show_if_user_is_a_member_of_the_services_org_but
mock_get_jobs,
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
active_user_with_permissions,
client_request,
):
@@ -1676,7 +1581,7 @@ def test_org_breadcrumbs_show_if_user_is_platform_admin(
mock_get_jobs,
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
platform_admin_user,
platform_admin_client,
):
@@ -1708,7 +1613,7 @@ def test_should_show_usage_on_dashboard(
mock_get_jobs,
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters,
permissions,
):
service_one['permissions'] = permissions
+226 -122
View File
@@ -6,11 +6,11 @@ from bs4 import BeautifulSoup, element
from flask import url_for
from freezegun import freeze_time
from app.main.views.feedback import (
from app.main.views.feedback import has_live_services, in_business_hours
from app.models.feedback import (
GENERAL_TICKET_TYPE,
PROBLEM_TICKET_TYPE,
QUESTION_TICKET_TYPE,
has_live_services,
in_business_hours,
)
from tests.conftest import normalize_spaces
@@ -19,18 +19,48 @@ def no_redirect():
return lambda _external=True: None
@pytest.mark.parametrize('endpoint', [
'main.old_feedback',
'main.support',
])
def test_get_support_index_page(
client,
endpoint,
client_request,
):
response = client.get(url_for('main.support'), follow_redirects=True)
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == 'Support'
page = client_request.get('.support')
assert page.select_one('form')['method'] == 'post'
assert 'action' not in page.select_one('form')
assert normalize_spaces(page.select_one('h1').text) == 'Support'
assert normalize_spaces(
page.select_one('form label[for=support_type-0]').text
) == 'Report a problem'
assert page.select_one('form input#support_type-0')['value'] == 'report-problem'
assert normalize_spaces(
page.select_one('form label[for=support_type-1]').text
) == 'Ask a question or give feedback'
assert page.select_one('form input#support_type-1')['value'] == 'ask-question-give-feedback'
assert normalize_spaces(
page.select_one('form button[type=submit]').text
) == 'Continue'
def test_get_support_index_page_when_signed_out(
client_request,
):
client_request.logout()
page = client_request.get('.support')
assert page.select_one('form')['method'] == 'post'
assert 'action' not in page.select_one('form')
assert normalize_spaces(
page.select_one('form label[for=who-0]').text
) == (
'I work in the public sector and need to send emails, text messages or letters'
)
assert page.select_one('form input#who-0')['value'] == 'public-sector'
assert normalize_spaces(
page.select_one('form label[for=who-1]').text
) == (
'Im a member of the public with a question for the government'
)
assert page.select_one('form input#who-1')['value'] == 'public'
assert normalize_spaces(
page.select_one('form button[type=submit]').text
) == 'Continue'
@freeze_time('2016-12-12 12:00:00.000000')
@@ -38,34 +68,59 @@ def test_get_support_index_page(
(PROBLEM_TICKET_TYPE, 'Report a problem'),
(QUESTION_TICKET_TYPE, 'Ask a question or give feedback'),
])
@pytest.mark.parametrize('logged_in, expected_form_field, expected_contact_details', [
(True, type(None), 'Well reply to test@user.gov.uk'),
(False, element.Tag, None),
])
def test_choose_support_type(
client,
api_user_active,
mock_get_user,
mock_get_services,
logged_in,
expected_form_field,
expected_contact_details,
client_request,
support_type,
expected_h1
):
if logged_in:
client.login(api_user_active)
response = client.post(
url_for('main.support'),
data={'support_type': support_type}, follow_redirects=True
page = client_request.post(
'main.support',
_data={'support_type': support_type},
_follow_redirects=True,
)
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == expected_h1
assert isinstance(page.find('input', {'name': 'name'}), expected_form_field)
assert isinstance(page.find('input', {'name': 'email_address'}), expected_form_field)
if expected_contact_details:
assert page.find('form').find('p').text.strip() == expected_contact_details
assert not page.select_one('input[name=name]')
assert not page.select_one('input[name=email_address]')
assert page.find('form').find('p').text.strip() == (
'Well reply to test@user.gov.uk'
)
@freeze_time('2016-12-12 12:00:00.000000')
def test_get_support_as_someone_in_the_public_sector(
client_request,
):
client_request.logout()
page = client_request.post(
'main.support',
_data={'who': 'public-sector'},
_follow_redirects=True,
)
assert normalize_spaces(page.select('h1')) == (
'Contact GOV.UK Notify support'
)
assert page.select_one('form textarea[name=feedback]')
assert page.select_one('form input[name=name]')
assert page.select_one('form input[name=email_address]')
assert page.select_one('form button[type=submit]')
def test_get_support_as_member_of_public(
client_request,
):
client_request.logout()
page = client_request.post(
'main.support',
_data={'who': 'public'},
_follow_redirects=True,
)
assert normalize_spaces(page.select('h1')) == (
'The GOV.UK Notify service is for people who work in the government'
)
assert len(page.select('h2 a')) == 3
assert not page.select('form')
assert not page.select('input')
assert not page.select('form [type=submit]')
@freeze_time('2016-12-12 12:00:00.000000')
@@ -79,50 +134,6 @@ def test_get_feedback_page(client, ticket_type, expected_status_code):
assert response.status_code == expected_status_code
@pytest.mark.parametrize('prefilled_body, expected_textarea', [
(
'agreement',
(
'Please can you tell me if theres an agreement in place '
'between GOV.UK Notify and my organisation?'
)
),
(
'foo',
''
),
])
@freeze_time('2016-12-12 12:00:00.000000')
def test_get_feedback_page_with_prefilled_body(
client_request,
mocker,
fake_uuid,
prefilled_body,
expected_textarea,
active_user_with_permissions,
):
active_user_with_permissions['email_address'] = 'test@marinemanagement.org.uk'
mocker.patch('app.user_api_client.get_user', return_value=active_user_with_permissions)
mock_post = mocker.patch('app.main.views.feedback.zendesk_client.create_ticket')
page = client_request.get(
'main.feedback',
ticket_type=QUESTION_TICKET_TYPE,
body=prefilled_body,
)
assert page.select_one('textarea').text == (
expected_textarea
)
client_request.post(
'main.feedback',
ticket_type=QUESTION_TICKET_TYPE,
body='agreement',
_data={'feedback': 'blah', 'name': 'Example', 'email_address': 'test@example.com'}
)
message = mock_post.call_args[1]['message']
assert message.startswith('blah')
assert 'Please send' not in message
@freeze_time('2016-12-12 12:00:00.000000')
@pytest.mark.parametrize('ticket_type', [PROBLEM_TICKET_TYPE, QUESTION_TICKET_TYPE])
def test_passed_non_logged_in_user_details_through_flow(client, mocker, ticket_type):
@@ -204,34 +215,15 @@ def test_passes_user_details_through_flow(
{'feedback': 'blah', 'name': 'Fred'},
{'feedback': 'blah'},
])
@pytest.mark.parametrize('ticket_type, expected_response, expected_redirect, expected_error', [
(
PROBLEM_TICKET_TYPE,
200,
lambda: None,
element.Tag,
),
(
QUESTION_TICKET_TYPE,
302,
partial(
url_for,
'.thanks',
email_address_provided=False,
out_of_hours_emergency=False,
_external=True,
),
type(None),
),
@pytest.mark.parametrize('ticket_type', [
PROBLEM_TICKET_TYPE,
QUESTION_TICKET_TYPE,
])
def test_email_address_required_for_problems(
def test_email_address_required_for_problems_and_questions(
client_request,
mocker,
data,
ticket_type,
expected_response,
expected_redirect,
expected_error
):
mocker.patch('app.main.views.feedback.zendesk_client')
client_request.logout()
@@ -239,10 +231,9 @@ def test_email_address_required_for_problems(
'main.feedback',
ticket_type=ticket_type,
_data=data,
_expected_status=expected_response,
_expected_redirect=expected_redirect(),
_expected_status=200
)
assert isinstance(page.find('span', {'class': 'error-message'}), expected_error)
assert isinstance(page.find('span', {'class': 'error-message'}), element.Tag)
@freeze_time('2016-12-12 12:00:00.000000')
@@ -314,8 +305,8 @@ def test_urgency(
ids, params = zip(*[
('non-logged in users always have to triage', (
PROBLEM_TICKET_TYPE, False, False, True,
302, partial(url_for, 'main.triage')
GENERAL_TICKET_TYPE, False, False, True,
302, partial(url_for, 'main.triage', ticket_type=GENERAL_TICKET_TYPE)
)),
('trial services are never high priority', (
PROBLEM_TICKET_TYPE, False, True, False,
@@ -331,7 +322,7 @@ ids, params = zip(*[
)),
('should triage out of hours', (
PROBLEM_TICKET_TYPE, False, True, True,
302, partial(url_for, 'main.triage')
302, partial(url_for, 'main.triage', ticket_type=PROBLEM_TICKET_TYPE)
))
])
@@ -365,6 +356,21 @@ def test_redirects_to_triage(
assert response.location == expected_redirect(_external=True)
@pytest.mark.parametrize('ticket_type, expected_h1', (
(PROBLEM_TICKET_TYPE, 'Report a problem'),
(GENERAL_TICKET_TYPE, 'Contact GOV.UK Notify support'),
))
def test_options_on_triage_page(
client_request,
ticket_type,
expected_h1,
):
page = client_request.get('main.triage', ticket_type=ticket_type)
assert normalize_spaces(page.select_one('h1').text) == expected_h1
assert page.select('form input[type=radio]')[0]['value'] == 'yes'
assert page.select('form input[type=radio]')[1]['value'] == 'no'
def test_doesnt_lose_message_if_post_across_closing(
client_request,
mocker,
@@ -378,7 +384,7 @@ def test_doesnt_lose_message_if_post_across_closing(
ticket_type=PROBLEM_TICKET_TYPE,
_data={'feedback': 'foo'},
_expected_status=302,
_expected_redirect=url_for('.triage', _external=True),
_expected_redirect=url_for('.triage', ticket_type=PROBLEM_TICKET_TYPE, _external=True),
)
with client_request.session_transaction() as session:
assert session['feedback_message'] == 'foo'
@@ -428,19 +434,64 @@ def test_in_business_hours(when, is_in_business_hours):
assert in_business_hours() == is_in_business_hours
@pytest.mark.parametrize('ticket_type', (
GENERAL_TICKET_TYPE,
PROBLEM_TICKET_TYPE,
))
@pytest.mark.parametrize('choice, expected_redirect_param', [
('yes', 'yes'),
('no', 'no'),
])
def test_triage_redirects_to_correct_url(client, choice, expected_redirect_param):
response = client.post(url_for('main.triage'), data={'severe': choice})
assert response.status_code == 302
assert response.location == url_for(
def test_triage_redirects_to_correct_url(
client_request,
ticket_type,
choice,
expected_redirect_param,
):
client_request.post(
'main.triage',
ticket_type=ticket_type,
_data={'severe': choice},
_expected_status=302,
_expected_redirect=url_for(
'main.feedback',
ticket_type=ticket_type,
severe=expected_redirect_param,
_external=True,
),
)
@pytest.mark.parametrize('extra_args, expected_back_link', [
(
{'severe': 'yes'},
partial(url_for, 'main.triage', ticket_type=PROBLEM_TICKET_TYPE)
),
(
{'severe': 'no'},
partial(url_for, 'main.triage', ticket_type=PROBLEM_TICKET_TYPE)
),
(
{'severe': 'foo'}, # hacking the URL
partial(url_for, 'main.support')
),
(
{},
partial(url_for, 'main.support')
),
])
def test_back_link_from_form(
client_request,
extra_args,
expected_back_link,
):
page = client_request.get(
'main.feedback',
ticket_type=PROBLEM_TICKET_TYPE,
severe=expected_redirect_param,
_external=True,
**extra_args
)
assert page.select_one('.govuk-back-link')['href'] == expected_back_link()
assert normalize_spaces(page.select_one('h1').text) == 'Report a problem'
@pytest.mark.parametrize(
@@ -469,15 +520,15 @@ def test_triage_redirects_to_correct_url(client, choice, expected_redirect_param
# Treat empty query param as mangled URL ask question again
(
False, '',
302, partial(url_for, 'main.triage'),
302, partial(url_for, 'main.triage'),
302, partial(url_for, 'main.triage', ticket_type=PROBLEM_TICKET_TYPE),
302, partial(url_for, 'main.triage', ticket_type=PROBLEM_TICKET_TYPE),
),
# User hasnt answered the triage question
(
False, None,
302, partial(url_for, 'main.triage'),
302, partial(url_for, 'main.triage'),
302, partial(url_for, 'main.triage', ticket_type=PROBLEM_TICKET_TYPE),
302, partial(url_for, 'main.triage', ticket_type=PROBLEM_TICKET_TYPE),
),
# Escalation is needed for non-logged-in users
@@ -518,6 +569,57 @@ def test_should_be_shown_the_bat_email(
assert logged_in_response.location == expected_redirect_when_logged_in(_external=True)
@pytest.mark.parametrize(
(
'severe,'
'expected_status_code, expected_redirect,'
'expected_status_code_when_logged_in, expected_redirect_when_logged_in'
),
[
# User hasnt answered the triage question
(
None,
302, partial(url_for, 'main.triage', ticket_type=GENERAL_TICKET_TYPE),
302, partial(url_for, 'main.triage', ticket_type=GENERAL_TICKET_TYPE),
),
# Escalation is needed for non-logged-in users
(
'yes',
302, partial(url_for, 'main.bat_phone'),
200, no_redirect(),
),
]
)
def test_should_be_shown_the_bat_email_for_general_questions(
client,
active_user_with_permissions,
mocker,
service_one,
mock_get_services,
severe,
expected_status_code,
expected_redirect,
expected_status_code_when_logged_in,
expected_redirect_when_logged_in,
):
mocker.patch('app.main.views.feedback.in_business_hours', return_value=False)
feedback_page = url_for('main.feedback', ticket_type=GENERAL_TICKET_TYPE, severe=severe)
response = client.get(feedback_page)
assert response.status_code == expected_status_code
assert response.location == expected_redirect(_external=True)
# logged in users should never be redirected to the bat email page
client.login(active_user_with_permissions, mocker, service_one)
logged_in_response = client.get(feedback_page)
assert logged_in_response.status_code == expected_status_code_when_logged_in
assert logged_in_response.location == expected_redirect_when_logged_in(_external=True)
def test_bat_email_page(
client,
active_user_with_permissions,
@@ -530,9 +632,11 @@ def test_bat_email_page(
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.select('main a')[1].text == 'Fill in this form'
assert page.select('main a')[1]['href'] == url_for('main.feedback', ticket_type=PROBLEM_TICKET_TYPE, severe='no')
next_page_response = client.get(page.select('main a')[1]['href'])
assert page.select('main a')[0].text == 'Back'
assert page.select('main a')[0]['href'] == url_for('main.support')
assert page.select('main a')[2].text == 'Fill in this form'
assert page.select('main a')[2]['href'] == url_for('main.feedback', ticket_type=PROBLEM_TICKET_TYPE, severe='no')
next_page_response = client.get(page.select('main a')[2]['href'])
next_page = BeautifulSoup(next_page_response.data.decode('utf-8'), 'html.parser')
assert next_page.h1.text.strip() == 'Report a problem'
+1 -1
View File
@@ -83,7 +83,7 @@ def test_robots(client):
'features_letters', 'how_to_pay', 'get_started',
'guidance_index', 'branding_and_customisation',
'create_and_send_messages', 'edit_and_format_messages',
'send_files_by_email', 'upload_a_letter',
'send_files_by_email', 'upload_a_letter', 'who_its_for',
])
def test_static_pages(
client_request,
+11 -123
View File
@@ -18,131 +18,19 @@ from tests.conftest import (
)
@pytest.mark.parametrize('user, expected_rows', [
(create_active_user_with_permissions(), (
(
'File Status'
),
(
'export 1/1/2016.xls '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
(
'all email addresses.xlsx '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
(
'applicants.ods '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
(
'thisisatest.csv '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
)),
(create_active_caseworking_user(), (
(
'File Messages to be sent'
),
(
'even_later.csv '
'Sending 1 January 2016 at 11:09pm 1'
),
(
'send_me_later.csv '
'Sending 1 January 2016 at 11:09am 1'
),
(
'File Status'
),
(
'export 1/1/2016.xls '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
(
'all email addresses.xlsx '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
(
'applicants.ods '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
(
'thisisatest.csv '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
)),
])
@freeze_time("2012-12-12 12:12")
def test_jobs_page_shows_scheduled_jobs_if_user_doesnt_have_dashboard(
def test_old_jobs_hub_redirects(
client_request,
service_one,
active_user_with_permissions,
mock_get_jobs,
user,
expected_rows,
):
client_request.login(user)
page = client_request.get('main.view_jobs', service_id=service_one['id'])
for index, row in enumerate(expected_rows):
assert normalize_spaces(page.select('tr')[index].text) == row
@pytest.mark.parametrize('user', [
create_active_user_with_permissions(),
create_active_caseworking_user(),
])
def test_get_jobs_shows_page_links(
client_request,
active_user_with_permissions,
mock_get_jobs,
user,
):
client_request.login(user)
page = client_request.get('main.view_jobs', service_id=SERVICE_ONE_ID)
assert 'Next page' in page.find('li', {'class': 'next-page'}).text
assert 'Previous page' in page.find('li', {'class': 'previous-page'}).text
@pytest.mark.parametrize('user', [
create_active_user_with_permissions(),
create_active_caseworking_user(),
])
@freeze_time("2012-12-12 12:12")
def test_jobs_page_doesnt_show_scheduled_on_page_2(
client_request,
service_one,
active_user_with_permissions,
mock_get_jobs,
user,
):
client_request.login(user)
page = client_request.get('main.view_jobs', service_id=service_one['id'], page=2)
for index, row in enumerate((
(
'File Status'
),
(
'export 1/1/2016.xls '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
(
'all email addresses.xlsx '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
(
'applicants.ods '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
(
'thisisatest.csv '
'Sent today at 12:12pm 1 sending 0 delivered 0 failed'
),
)):
assert normalize_spaces(page.select('tr')[index].text) == row
client_request.get(
'main.view_jobs',
service_id=SERVICE_ONE_ID,
_expected_status=302,
_expected_redirect=url_for(
'main.uploads',
service_id=SERVICE_ONE_ID,
_external=True,
)
)
@pytest.mark.parametrize('user', [
+1 -1
View File
@@ -1192,7 +1192,7 @@ def test_edit_user_email_cannot_change_a_gov_email_address_to_a_non_gov_email_ad
},
_expected_status=200,
)
assert 'Enter a government email address.' in page.find('span', class_='error-message').text
assert 'Enter a public sector email address' in page.select_one('.error-message').text
with client_request.session_transaction() as session:
assert 'team_member_email_change-'.format(active_user_with_permissions['id']) not in session
+29 -4
View File
@@ -37,6 +37,7 @@ def test_should_redirect_if_not_logged_in(
@pytest.mark.parametrize('endpoint', [
'main.platform_admin',
'main.platform_admin_splash_page',
'main.live_services',
'main.trial_services',
])
@@ -589,6 +590,20 @@ def test_get_tech_failure_status_box_data_removes_percentage_data():
assert 'percentage' not in tech_failure_data
def test_platform_admin_splash_doesnt_talk_to_api(
client_request,
platform_admin_user,
):
client_request.login(platform_admin_user)
page = client_request.get('main.platform_admin_splash_page')
assert page.select_one('main .govuk-body a')['href'] == url_for(
'main.platform_admin',
)
def test_platform_admin_with_start_and_end_dates_provided(mocker, platform_admin_client):
start_date = '2018-01-01'
end_date = '2018-06-01'
@@ -691,9 +706,10 @@ def test_platform_admin_submit_returned_letters(mocker, platform_admin_client):
)
mock_client.assert_called_once_with(['REF1', 'REF2'])
redis.delete_cache_keys_by_pattern.assert_called_once_with(
'service-????????-????-????-????-????????????-returned-letters-summary'
)
assert redis.delete_cache_keys_by_pattern.call_args_list == [
call('service-????????-????-????-????-????????????-returned-letters-statistics'),
call('service-????????-????-????-????-????????????-returned-letters-summary'),
]
assert response.status_code == 302
assert response.location == url_for('main.platform_admin_returned_letters', _external=True)
@@ -734,6 +750,15 @@ def test_clear_cache_shows_form(client_request, platform_admin_user, mocker):
call('template-????????-????-????-????-????????????-version-*'),
call('template-????????-????-????-????-????????????-versions'),
], 'Removed 3 template objects from redis'),
('service', [
call('has_jobs-????????-????-????-????-????????????'),
call('service-????????-????-????-????-????????????'),
call('service-????????-????-????-????-????????????-templates'),
call('service-????????-????-????-????-????????????-data-retention'),
call('service-????????-????-????-????-????????????-template-folders'),
call('service-????????-????-????-????-????????????-returned-letters-statistics'),
call('service-????????-????-????-????-????????????-returned-letters-summary'),
], 'Removed 3 service objects from redis'),
('organisation', [
call('organisations'),
call('domains'),
@@ -749,7 +774,7 @@ def test_clear_cache_submits_and_tells_you_how_many_things_were_deleted(
expected_confirmation,
):
redis = mocker.patch('app.main.views.platform_admin.redis_client')
redis.delete_cache_keys_by_pattern.side_effect = [0, 3, 1]
redis.delete_cache_keys_by_pattern.side_effect = [0, 3, 1, 0, 0, 0, 0, 0]
client_request.login(platform_admin_user)
page = client_request.post('main.clear_cache', _data={'model_type': model_type}, _expected_status=200)
+19 -11
View File
@@ -7,6 +7,7 @@ from flask import session, url_for
from flask_login import current_user
from app.models.user import InvitedUser
from tests.conftest import normalize_spaces
def test_render_register_returns_template_with_form(client):
@@ -97,20 +98,27 @@ def test_process_register_returns_200_when_mobile_number_is_invalid(
def test_should_return_200_when_email_is_not_gov_uk(
client,
mock_send_verify_code,
mock_get_user_by_email,
client_request,
mock_get_organisations,
mock_login,
):
response = client.post(url_for('main.register'),
data={'name': 'Bad Mobile',
'email_address': 'bad_mobile@example.not.right',
'mobile_number': '+44123412345',
'password': 'validPassword!'})
client_request.logout()
page = client_request.post(
'main.register',
_data={
'name': 'Firstname Lastname',
'email_address': 'bad_mobile@example.not.right',
'mobile_number': '07900900123',
'password': 'validPassword!'
},
_expected_status=200,
)
assert response.status_code == 200
assert 'Enter a government email address' in response.get_data(as_text=True)
assert normalize_spaces(page.select_one('.error-message').text) == (
'Enter a public sector email address or find out who can use Notify'
)
assert page.select_one('.error-message a')['href'] == url_for(
'main.who_its_for'
)
@pytest.mark.parametrize('email_address', (
+504 -21
View File
@@ -6,12 +6,14 @@ from glob import glob
from io import BytesIO
from itertools import repeat
from os import path
from unittest.mock import ANY
from uuid import uuid4
from zipfile import BadZipFile
import pytest
from bs4 import BeautifulSoup
from flask import url_for
from freezegun import freeze_time
from notifications_python_client.errors import HTTPError
from notifications_utils.recipients import RecipientCSV
from notifications_utils.template import (
@@ -36,6 +38,7 @@ from tests.conftest import (
create_active_user_with_permissions,
create_multiple_email_reply_to_addresses,
create_multiple_sms_senders,
create_platform_admin_user,
create_template,
mock_get_service_email_template,
mock_get_service_letter_template,
@@ -776,6 +779,7 @@ def test_upload_valid_csv_only_sets_meta_if_filename_known(
mock_get_job_doesnt_exist,
mock_get_jobs,
mock_s3_set_metadata,
mock_template_preview,
fake_uuid,
):
@@ -787,10 +791,6 @@ def test_upload_valid_csv_only_sets_meta_if_filename_known(
'app.main.views.send.get_page_count_for_letter',
return_value=5,
)
mocker.patch(
'app.main.views.send.TemplatePreview.from_utils_template',
return_value='foo'
)
client_request.get(
'no_cookie.check_messages_preview',
@@ -1063,6 +1063,7 @@ def test_send_test_step_redirects_if_session_not_setup(
mock_get_service_statistics,
mock_get_users_by_service,
mock_has_no_jobs,
mock_get_no_contact_lists,
fake_uuid,
user,
endpoint,
@@ -1177,6 +1178,7 @@ def test_send_one_off_or_test_has_correct_page_titles(
logged_in_client,
service_one,
mock_has_no_jobs,
mock_get_no_contact_lists,
fake_uuid,
mocker,
template_type,
@@ -1238,6 +1240,7 @@ def test_send_one_off_or_test_shows_placeholders_in_correct_order(
client_request,
fake_uuid,
mock_has_no_jobs,
mock_get_no_contact_lists,
mock_get_service_template_with_multiple_placeholders,
endpoint,
step_index,
@@ -1289,6 +1292,7 @@ def test_send_one_off_has_skip_link(
fake_uuid,
mock_get_service_email_template,
mock_has_no_jobs,
mock_get_no_contact_lists,
mocker,
template_type,
expected_link_text,
@@ -1308,32 +1312,34 @@ def test_send_one_off_has_skip_link(
_follow_redirects=True,
)
skip_links = page.select('a.top-gutter-4-3')
skip_links = page.select('form a')
if expected_link_text and expected_link_url:
assert skip_links[0].text.strip() == expected_link_text
assert skip_links[0]['href'] == expected_link_url(
assert skip_links[1].text.strip() == expected_link_text
assert skip_links[1]['href'] == expected_link_url(
service_id=service_one['id'],
template_id=fake_uuid,
)
else:
assert not skip_links
with pytest.raises(IndexError):
skip_links[1]
@pytest.mark.parametrize('template_type, expected_sticky', [
('sms', False),
('email', True),
('letter', True),
('letter', False),
])
def test_send_one_off_has_sticky_header_for_email_and_letter(
def test_send_one_off_has_sticky_header_for_email(
mocker,
client_request,
fake_uuid,
mock_has_no_jobs,
mock_get_no_contact_lists,
template_type,
expected_sticky,
):
template_data = create_template(template_type=template_type)
template_data = create_template(template_type=template_type, content='((body))')
mocker.patch('app.service_api_client.get_service_template', return_value={'data': template_data})
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=9)
@@ -1348,6 +1354,39 @@ def test_send_one_off_has_sticky_header_for_email_and_letter(
assert bool(page.select('.js-stick-at-top-when-scrolling')) == expected_sticky
def test_send_one_off_has_sticky_header_for_letter_on_non_address_placeholders(
mocker,
client_request,
fake_uuid,
mock_get_live_service,
):
template_data = create_template(template_type='letter', content='((body))')
mocker.patch('app.service_api_client.get_service_template', return_value={'data': template_data})
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=9)
with client_request.session_transaction() as session:
session['send_test_letter_page_count'] = 1
session['recipient'] = ''
session['placeholders'] = {
'address line 1': 'foo',
'address line 2': 'bar',
'address line 3': '',
'address line 4': '',
'address line 5': '',
'address line 6': '',
'postcode': 'SW1 1AA',
}
page = client_request.get(
'main.send_one_off_step',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
step_index=7, # letter template has 7 placeholders were at the end
_follow_redirects=True,
)
assert page.select('.js-stick-at-top-when-scrolling')
@pytest.mark.parametrize('user', (
create_active_user_with_permissions(),
create_active_caseworking_user(),
@@ -1358,6 +1397,7 @@ def test_skip_link_will_not_show_on_sms_one_off_if_service_has_no_mobile_number(
fake_uuid,
mock_get_service_template,
mock_has_no_jobs,
mock_get_no_contact_lists,
mocker,
user,
):
@@ -1374,17 +1414,17 @@ def test_skip_link_will_not_show_on_sms_one_off_if_service_has_no_mobile_number(
assert not skip_links
@pytest.mark.parametrize('user, link_index', (
(create_active_user_with_permissions(), 2),
(create_active_caseworking_user(), 1),
@pytest.mark.parametrize('user', (
create_active_user_with_permissions(),
create_active_caseworking_user(),
))
def test_send_one_off_offers_link_to_upload(
client_request,
fake_uuid,
mock_get_service_template,
mock_has_jobs,
mock_get_no_contact_lists,
user,
link_index,
):
client_request.login(user)
@@ -1396,7 +1436,7 @@ def test_send_one_off_offers_link_to_upload(
)
back_link = page.select('main a')[0]
link = page.select('main a')[link_index]
link = page.select_one('form a')
assert back_link.text.strip() == 'Back'
@@ -1408,6 +1448,76 @@ def test_send_one_off_offers_link_to_upload(
)
def test_send_one_off_has_link_to_use_existing_list(
client_request,
mock_get_service_template,
mock_has_jobs,
mock_get_contact_lists,
fake_uuid,
):
page = client_request.get(
'main.send_one_off',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_follow_redirects=True,
)
assert [
(link.text, link['href']) for link in page.select('form a')
] == [
(
'Upload a list of phone numbers',
url_for(
'main.send_messages',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
),
),
(
'Use a saved list',
url_for(
'main.choose_from_contact_list',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
),
),
(
'Use my phone number',
url_for(
'main.send_test',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
),
),
]
def test_no_link_to_use_existing_list_for_service_without_lists(
mocker,
client_request,
mock_get_service_template,
mock_has_jobs,
fake_uuid,
):
mocker.patch(
'app.models.contact_list.ContactLists.client_method',
return_value=[],
)
client_request.login(create_platform_admin_user())
page = client_request.get(
'main.send_one_off',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_follow_redirects=True,
)
assert [
link.text for link in page.select('form a')
] == [
'Upload a list of phone numbers',
'Use my phone number',
]
@pytest.mark.parametrize('user', (
create_active_user_with_permissions(),
create_active_caseworking_user(),
@@ -2066,6 +2176,180 @@ def test_send_test_clears_session(
assert session['placeholders'] == {}
def test_send_one_off_redirects_to_letter_address(client_request, fake_uuid, mock_get_service_letter_template):
with client_request.session_transaction() as session:
session['placeholders'] = {'foo': 'some old data that we dont care about'}
client_request.get(
'main.send_one_off',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_expected_redirect=url_for(
'main.send_one_off_letter_address',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_external=True,
)
)
# make sure it cleared session first
with client_request.session_transaction() as session:
assert session['recipient'] is None
assert session['placeholders'] == {}
def test_send_one_off_letter_address_shows_form(
client_request,
fake_uuid,
mock_get_service_letter_template,
mock_template_preview,
):
with client_request.session_transaction() as session:
session['recipient'] = None
session['placeholders'] = {}
page = client_request.get(
'main.send_one_off_letter_address',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid
)
assert page.select_one('h1').text.strip() == 'Send Two week reminder'
form = page.select_one('form')
assert form.select_one('label').text.strip() == 'Address'
assert form.select_one('textarea').attrs['name'] == 'address'
upload_link = form.select_one('a')
assert upload_link.text.strip() == 'Upload a list of addresses'
assert upload_link['href'] == url_for(
'main.send_messages',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
)
assert (
page.find_all('a', {'class': 'govuk-back-link'})[0]['href']
) == url_for('main.view_template', service_id=SERVICE_ONE_ID, template_id=fake_uuid)
@pytest.mark.parametrize(['form_data', 'expected_placeholders'], [
# minimal
('\n'.join(['a', 'b', 'c']), {
'address line 1': 'a',
'address line 2': 'b',
'address line 3': '',
'address line 4': '',
'address line 5': '',
'address line 6': '',
'postcode': 'c',
}),
# maximal
('\n'.join(['a', 'b', 'c', 'd', 'e', 'f', 'g']), {
'address line 1': 'a',
'address line 2': 'b',
'address line 3': 'c',
'address line 4': 'd',
'address line 5': 'e',
'address line 6': 'f',
'postcode': 'g',
}),
# it ignores empty lines and strips whitespace from each line.
# It also strips extra whitespace from the middle of lines.
('\n a\ta \n\n\n \n\n\n\nb b \r\nc', {
'address line 1': 'a\ta',
'address line 2': 'b b',
'address line 3': '',
'address line 4': '',
'address line 5': '',
'address line 6': '',
'postcode': 'c',
}),
])
def test_send_one_off_letter_address_populates_address_fields_in_session(
client_request,
fake_uuid,
mock_get_service_letter_template,
mock_template_preview,
form_data,
expected_placeholders
):
with client_request.session_transaction() as session:
session['recipient'] = None
session['placeholders'] = {}
client_request.post(
'main.send_one_off_letter_address',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_data={'address': form_data},
# there are no additional placeholders so go straight to the check page
_expected_redirect=url_for(
'main.check_notification',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_external=True,
),
)
with client_request.session_transaction() as session:
assert session['placeholders'] == expected_placeholders
@pytest.mark.parametrize(['form_data', 'expected_error_message'], [
('', 'Cannot be empty'),
('a\n\n\n\nb', 'Address must be at least 3 lines long'),
('\n'.join(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']), 'Address must be no more than 7 lines long'),
])
def test_send_one_off_letter_address_rejects_bad_addresses(
client_request,
fake_uuid,
mock_get_service_letter_template,
mock_template_preview,
form_data,
expected_error_message
):
with client_request.session_transaction() as session:
session['recipient'] = None
session['placeholders'] = {}
page = client_request.post(
'main.send_one_off_letter_address',
_data={'address': form_data},
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_expected_status=200
)
error = page.select('form .error-message')
assert normalize_spaces(error[0].text) == expected_error_message
def test_send_one_off_letter_address_goes_to_next_placeholder(client_request, mock_template_preview, mocker):
with client_request.session_transaction() as session:
session['recipient'] = None
session['placeholders'] = {}
template_data = create_template(template_type='letter', content='((foo))')
mocker.patch('app.service_api_client.get_service_template', return_value={'data': template_data})
client_request.post(
'main.send_one_off_letter_address',
service_id=SERVICE_ONE_ID,
template_id=template_data['id'],
_data={'address': 'a\nb\nc'},
# step 0-6 represent address line 1-6 and postcode. step 7 is the first non address placeholder
_expected_redirect=url_for(
'main.send_one_off_step',
service_id=SERVICE_ONE_ID,
template_id=template_data['id'],
step_index=7,
_external=True,
)
)
def test_download_example_csv(
logged_in_client,
mocker,
@@ -2180,6 +2464,31 @@ def test_upload_csvfile_with_international_validates(
assert mock_recipients.call_args[1]['international_sms'] == should_allow_international
def test_job_from_contact_list_knows_where_its_come_from(
client_request,
mocker,
service_one,
mock_get_service_template,
mock_s3_download,
mock_get_users_by_service,
mock_get_service_statistics,
mock_get_job_doesnt_exist,
mock_get_jobs,
mock_s3_set_metadata,
fake_uuid
):
page = client_request.get(
'main.check_messages',
service_id=service_one['id'],
upload_id=fake_uuid,
template_id=fake_uuid,
contact_list_id=unchanging_fake_uuid,
)
assert page.select_one(
'form input[type=hidden][name=contact_list_id]'
)['value'] == str(unchanging_fake_uuid)
def test_test_message_can_only_be_sent_now(
client_request,
mocker,
@@ -2216,7 +2525,10 @@ def test_letter_can_only_be_sent_now(
mock_get_jobs,
fake_uuid,
):
mocker.patch('app.main.views.send.s3download', return_value="addressline1, addressline2, postcode\na,b,c")
mocker.patch(
'app.main.views.send.s3download',
return_value="addressline1, addressline2, postcode\na,b,sw1 1aa"
)
mocker.patch('app.main.views.send.set_metadata_on_csv_upload')
mocker.patch('app.main.views.send.get_page_count_for_letter', return_value=1)
@@ -2268,6 +2580,9 @@ def test_send_button_is_correctly_labelled(
@pytest.mark.parametrize('when', [
'', '2016-08-25T13:04:21.767198'
])
@pytest.mark.parametrize('contact_list_id', [
'', unchanging_fake_uuid,
])
def test_create_job_should_call_api(
client_request,
mock_create_job,
@@ -2277,7 +2592,8 @@ def test_create_job_should_call_api(
mock_get_service_data_retention,
mocker,
fake_uuid,
when
when,
contact_list_id,
):
data = mock_get_job(SERVICE_ONE_ID, fake_uuid)['data']
job_id = data['id']
@@ -2298,7 +2614,10 @@ def test_create_job_should_call_api(
service_id=SERVICE_ONE_ID,
upload_id=job_id,
original_file_name=original_file_name,
_data={'scheduled_for': when},
_data={
'scheduled_for': when,
'contact_list_id': contact_list_id,
},
_follow_redirects=True,
_expected_status=200,
)
@@ -2309,6 +2628,7 @@ def test_create_job_should_call_api(
job_id,
SERVICE_ONE_ID,
scheduled_for=when,
contact_list_id=str(contact_list_id),
)
@@ -2908,8 +3228,8 @@ def test_check_messages_shows_data_errors_before_trial_mode_errors_for_letters(
mocker.patch('app.main.views.send.s3download', return_value='\n'.join(
['address_line_1,address_line_2,postcode,'] +
[' , ,11SW1 1AA'] +
[' , ,11SW1 1AA']
[' , ,SW1 1AA'] +
[' , ,SW1 1AA']
))
mocker.patch(
@@ -3670,6 +3990,7 @@ def test_reply_to_is_previewed_if_chosen(
mock_get_service_statistics,
mock_get_job_doesnt_exist,
mock_get_jobs,
mock_get_no_contact_lists,
get_default_reply_to_email_address,
fake_uuid,
endpoint,
@@ -3721,6 +4042,7 @@ def test_sms_sender_is_previewed(
mock_get_service_statistics,
mock_get_job_doesnt_exist,
mock_get_jobs,
mock_get_no_contact_lists,
get_default_sms_sender,
fake_uuid,
endpoint,
@@ -3780,3 +4102,164 @@ def test_redirects_to_template_if_job_exists_already(
_external=True,
)
)
@pytest.mark.parametrize((
'template_type, '
'expected_list_id, '
'expected_filename, '
'expected_time, '
'expected_count'
), (
(
'email',
'6ce466d0-fd6a-11e5-82f5-e0accb9d11a6',
'EmergencyContactList.xls',
'Uploaded today at 10:59am',
'100 email addresses',
),
(
'sms',
'd7b0bd1a-d1c7-4621-be5c-3c1b4278a2ad',
'phone number list.csv',
'Uploaded today at 1:00pm',
'123 phone numbers',
),
))
@freeze_time('2020-03-13 13:00')
def test_choose_from_contact_list(
mocker,
client_request,
mock_get_contact_lists,
fake_uuid,
template_type,
expected_list_id,
expected_filename,
expected_time,
expected_count,
):
template = create_template(template_type=template_type)
mocker.patch(
'app.service_api_client.get_service_template',
return_value={'data': template},
)
page = client_request.get(
'main.choose_from_contact_list',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
)
assert len(page.select('.file-list-filename-large')) == 1
assert normalize_spaces(page.select_one('.file-list-filename-large').text) == (
expected_filename
)
assert page.select_one('a.file-list-filename-large')['href'] == url_for(
'main.send_from_contact_list',
service_id=SERVICE_ONE_ID,
template_id=template['id'],
contact_list_id=expected_list_id,
)
assert normalize_spaces(page.select_one('.file-list-hint-large').text) == (
expected_time
)
assert normalize_spaces(page.select_one('.big-number-smallest').text) == (
expected_count
)
def test_choose_from_contact_list_with_personalised_template(
mocker,
client_request,
mock_get_contact_lists,
fake_uuid,
):
template = create_template(
content="Hey ((name)) ((thing)) is happening"
)
mocker.patch(
'app.service_api_client.get_service_template',
return_value={'data': template},
)
page = client_request.get(
'main.choose_from_contact_list',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
)
assert [
normalize_spaces(p.text) for p in page.select('main p')
] == [
'You cannot use a saved contact list with this template because '
'it is personalised with ((name)) and ((thing)).',
'Saved contact lists can only store email addresses or phone numbers.',
]
assert not page.select('table')
def test_choose_from_contact_list_with_no_lists(
mocker,
client_request,
mock_get_service_template,
fake_uuid,
):
mocker.patch(
'app.models.contact_list.ContactLists.client_method',
return_value=[],
)
page = client_request.get(
'main.choose_from_contact_list',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
)
assert [
normalize_spaces(p.text) for p in page.select('main p')
] == [
'You have not saved any lists of phone numbers yet.',
'To upload and save a new contact list, go to the uploads page.',
]
assert page.select_one('main p a')['href'] == url_for(
'main.uploads',
service_id=SERVICE_ONE_ID,
)
assert not page.select('table')
def test_send_from_contact_list(
mocker,
client_request,
fake_uuid,
mock_get_contact_list,
):
new_uuid = uuid.uuid4()
mock_download = mocker.patch('app.models.contact_list.s3download', return_value='contents')
mock_get_metadata = mocker.patch('app.models.contact_list.get_csv_metadata', return_value={
'example_key': 'example value',
})
mock_upload = mocker.patch('app.models.contact_list.s3upload', return_value=new_uuid)
mock_set_metadata = mocker.patch('app.models.contact_list.set_metadata_on_csv_upload')
client_request.get(
'main.send_from_contact_list',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
contact_list_id=fake_uuid,
_expected_status=302,
_expected_redirect=url_for(
'main.check_messages',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
upload_id=new_uuid,
original_file_name='EmergencyContactList.xls',
contact_list_id=fake_uuid,
_external=True,
)
)
mock_download.assert_called_once_with(
SERVICE_ONE_ID, fake_uuid, bucket='test-contact-list'
)
mock_get_metadata.assert_called_once_with(
SERVICE_ONE_ID, fake_uuid, bucket='test-contact-list'
)
mock_upload.assert_called_once_with(
SERVICE_ONE_ID, {'data': 'contents'}, ANY
)
mock_set_metadata.assert_called_once_with(
SERVICE_ONE_ID, new_uuid, example_key='example value'
)
+1 -1
View File
@@ -31,7 +31,7 @@ def test_sign_out_user(
mock_get_usage,
mock_get_free_sms_fragment_limit,
mock_get_inbound_sms_summary,
mock_get_returned_letter_summary_with_no_returned_letters,
mock_get_returned_letter_statistics_with_no_returned_letters
):
with client_request.session_transaction() as session:
assert session.get('user_id') is not None
+6
View File
@@ -1,3 +1,4 @@
import pytest
from bs4 import BeautifulSoup
from flask import url_for
from freezegun import freeze_time
@@ -107,6 +108,9 @@ def test_should_login_user_and_not_redirect_to_external_url(
assert response.location == url_for('main.show_accounts_or_dashboard', _external=True)
@pytest.mark.parametrize('platform_admin', (
True, False,
))
@freeze_time('2020-01-27T12:00:00')
def test_should_login_user_and_redirect_to_show_accounts(
client,
@@ -115,12 +119,14 @@ def test_should_login_user_and_redirect_to_show_accounts(
mock_get_user_by_email,
mock_check_verify_code,
mock_create_event,
platform_admin,
):
with client.session_transaction() as session:
session['user_details'] = {
'id': api_user_active['id'],
'email': api_user_active['email_address']}
api_user_active['email_access_validated_at'] = '2020-01-23T11:35:21.726132Z'
api_user_active['platform_admin'] = platform_admin
response = client.post(url_for('main.two_factor'),
data={'sms_code': '12345'})
+623 -10
View File
@@ -1,6 +1,8 @@
import re
import urllib
from unittest.mock import Mock
import uuid
from io import BytesIO
from unittest.mock import ANY, Mock
import pytest
from flask import make_response, url_for
@@ -13,36 +15,61 @@ from tests.conftest import (
SERVICE_ONE_ID,
create_active_caseworking_user,
create_active_user_with_permissions,
create_platform_admin_user,
)
@pytest.mark.parametrize('extra_permissions', (
[],
['letter'],
['upload_letters'],
pytest.param(
['letter', 'upload_letters'],
[],
marks=pytest.mark.xfail(raises=AssertionError),
),
pytest.param(
['upload_letters'],
marks=pytest.mark.xfail(raises=AssertionError),
),
['letter'],
['letter', 'upload_letters'],
))
def test_no_upload_letters_button_without_permission(
def test_upload_letters_button_only_with_letters_permission(
client_request,
service_one,
mock_get_uploads,
mock_get_jobs,
mock_get_no_contact_lists,
extra_permissions,
):
service_one['permissions'] += extra_permissions
page = client_request.get('main.uploads', service_id=SERVICE_ONE_ID)
assert not page.find('a', text=re.compile('Upload a letter'))
assert page.find('a', text=re.compile('Upload a letter'))
@pytest.mark.parametrize('user', (
create_platform_admin_user(),
create_active_user_with_permissions(),
))
def test_all_users_have_upload_contact_list(
client_request,
mock_get_uploads,
mock_get_jobs,
mock_get_no_contact_lists,
user,
):
client_request.login(user)
page = client_request.get('main.uploads', service_id=SERVICE_ONE_ID)
button = page.find('a', text=re.compile('Upload an emergency contact list'))
assert button
assert button['href'] == url_for(
'main.upload_contact_list', service_id=SERVICE_ONE_ID,
)
@pytest.mark.parametrize('extra_permissions, expected_empty_message', (
(['letter'], (
([], (
'You have not uploaded any files recently. '
'To upload a list of contact details, first choose a template.'
)),
(['letter', 'upload_letters'], (
(['letter'], (
'You have not uploaded any files recently. '
'Upload a letter and Notify will print, pack and post it for you. '
'To upload a list of contact details, first choose a template.'
@@ -53,6 +80,7 @@ def test_get_upload_hub_with_no_uploads(
client_request,
service_one,
mock_get_no_uploads,
mock_get_no_contact_lists,
extra_permissions,
expected_empty_message,
):
@@ -70,6 +98,7 @@ def test_get_upload_hub_page(
client_request,
service_one,
mock_get_uploads,
mock_get_no_contact_lists,
):
mocker.patch('app.job_api_client.get_jobs', return_value={'data': []})
service_one['permissions'] += ['letter', 'upload_letters']
@@ -97,7 +126,7 @@ def test_get_upload_hub_page(
'123 Example Street'
)
assert normalize_spaces(str(uploads[1].select_one('.govuk-body'))) == (
'<p class="govuk-body govuk-!-margin-bottom-1"> '
'<p class="govuk-body letter-recipient-summary"> '
'Firstname Lastname<br/> '
'123 Example Street<br/> '
'</p>'
@@ -656,6 +685,7 @@ def test_uploads_page_shows_scheduled_jobs(
client_request,
mock_get_no_uploads,
mock_get_jobs,
mock_get_no_contact_lists,
user,
):
client_request.login(user)
@@ -681,11 +711,56 @@ def test_uploads_page_shows_scheduled_jobs(
assert not page.select('.table-empty-message')
@freeze_time('2020-03-15')
def test_uploads_page_shows_contact_lists_first(
mocker,
client_request,
mock_get_no_uploads,
mock_get_jobs,
mock_get_contact_lists,
):
page = client_request.get('main.uploads', service_id=SERVICE_ONE_ID)
assert [
normalize_spaces(row.text) for row in page.select('tr')
] == [
(
'File Status'
),
(
'phone number list.csv '
'Uploaded 13 March at 1:00pm '
'123 saved phone numbers'
),
(
'EmergencyContactList.xls '
'Uploaded 13 March at 10:59am '
'100 saved email addresses'
),
(
'even_later.csv '
'Sending 1 January 2016 at 11:09pm '
'1 text message waiting to send'
),
(
'send_me_later.csv '
'Sending 1 January 2016 at 11:09am '
'1 text message waiting to send'
),
]
assert page.select_one('.file-list-filename-large')['href'] == url_for(
'main.contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id='d7b0bd1a-d1c7-4621-be5c-3c1b4278a2ad',
)
def test_get_uploads_shows_pagination(
client_request,
active_user_with_permissions,
mock_get_jobs,
mock_get_uploads,
mock_get_no_contact_lists,
):
page = client_request.get('main.uploads', service_id=SERVICE_ONE_ID)
@@ -697,3 +772,541 @@ def test_get_uploads_shows_pagination(
'Previous page '
'page 0'
)
def test_upload_contact_list_page(client_request):
page = client_request.get(
'main.upload_contact_list',
service_id=SERVICE_ONE_ID,
)
assert 'action' not in page.select_one('form')
assert page.select_one('form input')['name'] == 'file'
assert page.select_one('form input')['type'] == 'file'
assert normalize_spaces(page.select('.spreadsheet')[0].text) == (
'Example A '
'1 email address '
'2 test@example.gov.uk'
)
assert normalize_spaces(page.select('.spreadsheet')[1].text) == (
'Example A '
'1 phone number '
'2 07700 900123'
)
@pytest.mark.parametrize('file_contents, expected_error, expected_thead, expected_tbody,', [
(
"""
telephone,name
+447700900986
""",
(
'Your file has too many columns '
'It needs to have 1 column, called email address or phone number. '
'Right now it has 2 columns called telephone and name. '
'Skip to file contents'
),
'Row in file 1 telephone name',
'2 +447700900986',
),
(
"""
phone number, email address
+447700900986, test@example.com
""",
(
'Your file has too many columns '
'It needs to have 1 column, called email address or phone number. '
'Right now it has 2 columns called phone number and email address. '
'Skip to file contents'
),
'Row in file 1 phone number email address',
'2 +447700900986 test@example.com',
),
(
"""
email address
+447700900986
""",
(
'Theres a problem with invalid.csv '
'You need to fix 1 email address. '
'Skip to file contents'
),
'Row in file 1 email address',
'2 Not a valid email address +447700900986',
),
(
"""
phone number
test@example.com
""",
(
'Theres a problem with invalid.csv '
'You need to fix 1 phone number. '
'Skip to file contents'
),
'Row in file 1 phone number',
'2 Must not contain letters or symbols test@example.com',
),
(
"""
phone number, phone number, PHONE_NUMBER
+447700900111,+447700900222,+447700900333,
""",
(
'Your file has too many columns '
'It needs to have 1 column, called email address or phone number. '
'Right now it has 3 columns called phone number, phone number and PHONE_NUMBER. '
'Skip to file contents'
),
'Row in file 1 phone number phone number PHONE_NUMBER',
'2 +447700900333 +447700900333 +447700900333',
),
(
"""
phone number
""",
(
'Your file is missing some rows '
'It needs at least one row of data. '
'Skip to file contents'
),
'Row in file 1 phone number',
'',
),
(
"+447700900986",
(
'Your file is missing some rows '
'It needs at least one row of data, in a column called '
'email address or phone number. '
'Skip to file contents'
),
'Row in file 1 +447700900986',
'',
),
(
"",
(
'Your file is missing some rows '
'It needs at least one row of data, in a column called '
'email address or phone number. '
'Skip to file contents'
),
'Row in file 1',
'',
),
(
"""
phone number
+447700900986
+447700900986
""",
(
'Theres a problem with invalid.csv '
'You need to enter missing data in 1 row. '
'Skip to file contents'
),
'Row in file 1 phone number',
(
'3 Missing'
)
),
(
"""
phone number
+447700900
""",
(
'Theres a problem with invalid.csv '
'You need to fix 1 phone number. '
'Skip to file contents'
),
'Row in file 1 phone number',
'2 Not enough digits +447700900',
),
(
"""
email address
ok@example.com
bad@example1
bad@example2
""",
(
'Theres a problem with invalid.csv '
'You need to fix 2 email addresses. '
'Skip to file contents'
),
'Row in file 1 email address',
(
'3 Not a valid email address bad@example1 '
'4 Not a valid email address bad@example2'
),
),
])
def test_upload_csv_file_shows_error_banner(
client_request,
mocker,
mock_s3_upload,
mock_get_job_doesnt_exist,
mock_get_users_by_service,
fake_uuid,
file_contents,
expected_error,
expected_thead,
expected_tbody,
):
mock_upload = mocker.patch(
'app.models.contact_list.s3upload',
return_value=fake_uuid,
)
mock_download = mocker.patch(
'app.models.contact_list.s3download',
return_value=file_contents,
)
page = client_request.post(
'main.upload_contact_list',
service_id=SERVICE_ONE_ID,
_data={'file': (BytesIO(''.encode('utf-8')), 'invalid.csv')},
_follow_redirects=True,
)
mock_upload.assert_called_once_with(
SERVICE_ONE_ID,
{'data': '', 'file_name': 'invalid.csv'},
ANY,
bucket='test-contact-list',
)
mock_download.assert_called_once_with(
SERVICE_ONE_ID,
fake_uuid,
bucket='test-contact-list',
)
assert normalize_spaces(page.select_one('.banner-dangerous').text) == expected_error
assert page.select_one('form')['action'] == url_for(
'main.upload_contact_list',
service_id=SERVICE_ONE_ID,
)
assert page.select_one('form input')['type'] == 'file'
assert normalize_spaces(page.select_one('thead').text) == expected_thead
assert normalize_spaces(page.select_one('tbody').text) == expected_tbody
def test_upload_csv_file_shows_error_banner_for_too_many_rows(
client_request,
mocker,
mock_s3_upload,
mock_get_job_doesnt_exist,
mock_get_users_by_service,
fake_uuid,
):
mocker.patch('app.models.contact_list.s3upload', return_value=fake_uuid)
mocker.patch('app.models.contact_list.s3download', return_value='\n'.join(
['phone number'] + (['07700900986'] * 50001)
))
page = client_request.post(
'main.upload_contact_list',
service_id=SERVICE_ONE_ID,
_data={'file': (BytesIO(''.encode('utf-8')), 'invalid.csv')},
_follow_redirects=True,
)
assert normalize_spaces(page.select_one('.banner-dangerous').text) == (
'Your file has too many rows '
'Notify can store files up to 50,000 rows in size. '
'Your file has 50,001 rows. '
'Skip to file contents'
)
assert len(page.select('tbody tr')) == 50
assert normalize_spaces(page.select_one('.table-show-more-link').text) == (
'Only showing the first 50 rows'
)
def test_upload_csv_shows_trial_mode_error(
client_request,
mock_get_users_by_service,
mock_get_job_doesnt_exist,
fake_uuid,
mocker
):
mocker.patch('app.models.contact_list.s3upload', return_value=fake_uuid)
mocker.patch('app.models.contact_list.s3download', return_value=(
'phone number\n'
'07900900321' # Not in team
))
page = client_request.get(
'main.check_contact_list',
service_id=SERVICE_ONE_ID,
upload_id=fake_uuid,
_test_page_title=False,
)
assert normalize_spaces(page.select_one('.banner-dangerous').text) == (
'You cannot save this phone number '
'In trial mode you can only send to yourself and members of your team '
'Skip to file contents'
)
assert page.select_one('.banner-dangerous a')['href'] == url_for(
'main.trial_mode_new'
)
def test_upload_csv_shows_ok_page(
client_request,
mock_get_live_service,
mock_get_users_by_service,
mock_get_job_doesnt_exist,
fake_uuid,
mocker
):
mocker.patch('app.models.contact_list.s3download', return_value='\n'.join(
['email address'] + ['test@example.com'] * 51
))
mock_metadata_set = mocker.patch('app.models.contact_list.set_metadata_on_csv_upload')
page = client_request.get(
'main.check_contact_list',
service_id=SERVICE_ONE_ID,
upload_id=fake_uuid,
original_file_name='good times.xlsx',
_test_page_title=False,
)
mock_metadata_set.assert_called_once_with(
SERVICE_ONE_ID,
fake_uuid,
bucket='test-contact-list',
row_count=51,
original_file_name='good times.xlsx',
template_type='email',
valid=True,
)
assert normalize_spaces(page.select_one('h1').text) == (
'good times.xlsx'
)
assert normalize_spaces(page.select_one('main p').text) == (
'51 email addresses found'
)
assert page.select_one('form')['action'] == url_for(
'main.save_contact_list',
service_id=SERVICE_ONE_ID,
upload_id=fake_uuid,
)
assert normalize_spaces(page.select_one('form [type=submit]').text) == (
'Save contact list'
)
assert normalize_spaces(page.select_one('thead').text) == (
'Row in file 1 email address'
)
assert len(page.select('tbody tr')) == 50
assert normalize_spaces(page.select_one('tbody tr').text) == (
'2 test@example.com'
)
assert normalize_spaces(page.select_one('.table-show-more-link').text) == (
'Only showing the first 50 rows'
)
def test_save_contact_list(
mocker,
client_request,
fake_uuid,
mock_create_contact_list,
):
mock_get_metadata = mocker.patch('app.models.contact_list.get_csv_metadata', return_value={
'row_count': 999,
'valid': True,
'original_file_name': 'example.csv',
'template_type': 'email'
})
client_request.post(
'main.save_contact_list',
service_id=SERVICE_ONE_ID,
upload_id=fake_uuid,
_expected_status=302,
_expected_redirect=url_for(
'main.uploads',
service_id=SERVICE_ONE_ID,
_external=True,
)
)
mock_get_metadata.assert_called_once_with(
SERVICE_ONE_ID,
fake_uuid,
bucket='test-contact-list',
)
mock_create_contact_list.assert_called_once_with(
service_id=SERVICE_ONE_ID,
upload_id=fake_uuid,
original_file_name='example.csv',
row_count=999,
template_type='email',
)
def test_cant_save_bad_contact_list(
mocker,
client_request,
fake_uuid,
mock_create_contact_list,
):
mocker.patch('app.models.contact_list.get_csv_metadata', return_value={
'row_count': 999,
'valid': False,
'original_file_name': 'example.csv',
'template_type': 'email'
})
client_request.post(
'main.save_contact_list',
service_id=SERVICE_ONE_ID,
upload_id=fake_uuid,
_expected_status=403,
)
assert mock_create_contact_list.called is False
@freeze_time('2020-03-13 16:51:56')
def test_view_contact_list(
mocker,
client_request,
mock_get_contact_list,
fake_uuid,
):
mocker.patch('app.models.contact_list.s3download', return_value='\n'.join(
['email address'] + ['test@example.com'] * 51
))
page = client_request.get(
'main.contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
)
assert normalize_spaces(page.select_one('h1').text) == (
'EmergencyContactList.xls'
)
assert normalize_spaces(page.select('main p')[0].text) == (
'Uploaded by Test User today at 10:59am'
)
assert normalize_spaces(page.select('main p')[1].text) == (
'Download this list 51 email addresses'
)
assert page.select_one('a[download]')['href'] == url_for(
'main.download_contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
)
assert normalize_spaces(page.select_one('table').text).startswith(
'Email addresses '
'1 email address '
'2 test@example.com '
'3 test@example.com '
)
assert normalize_spaces(page.select_one('table').text).endswith(
'50 test@example.com '
'51 test@example.com'
)
assert normalize_spaces(page.select_one('.table-show-more-link').text) == (
'Only showing the first 50 rows'
)
def test_view_contact_list_404s_for_non_existing_list(
client_request,
mock_get_no_contact_list,
fake_uuid,
):
client_request.get(
'main.contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=uuid.uuid4(),
_expected_status=404,
)
def test_download_contact_list(
mocker,
logged_in_client,
fake_uuid,
mock_get_contact_list,
):
mocker.patch(
'app.models.contact_list.s3download',
return_value='phone number\n07900900321'
)
response = logged_in_client.get(url_for(
'main.download_contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
))
assert response.status_code == 200
assert response.headers['Content-Type'] == (
'text/csv; '
'charset=utf-8'
)
assert response.headers['Content-Disposition'] == (
'attachment; '
'filename=EmergencyContactList.csv'
)
assert response.get_data(as_text=True) == (
'phone number\n'
'07900900321'
)
def test_confirm_delete_contact_list(
mocker,
client_request,
fake_uuid,
mock_get_contact_list,
):
mocker.patch(
'app.models.contact_list.s3download',
return_value='phone number\n07900900321'
)
page = client_request.get(
'main.delete_contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
)
assert normalize_spaces(page.select_one('.banner-dangerous').text) == (
'Are you sure you want to delete EmergencyContactList.xls? '
'Yes, delete'
)
assert 'action' not in page.select_one('form')
assert page.select_one('form')['method'] == 'post'
assert page.select_one('form button')['type'] == 'submit'
def test_delete_contact_list(
mocker,
client_request,
fake_uuid,
mock_get_contact_list,
):
mock_delete = mocker.patch(
'app.models.contact_list.contact_list_api_client.delete_contact_list'
)
client_request.post(
'main.delete_contact_list',
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
_expected_redirect=url_for(
'main.uploads',
service_id=SERVICE_ONE_ID,
_external=True,
)
)
mock_delete.assert_called_once_with(
service_id=SERVICE_ONE_ID,
contact_list_id=fake_uuid,
)
@@ -50,6 +50,21 @@ def test_client_schedules_job(mocker, fake_uuid):
assert mock_post.call_args[1]['data']['scheduled_for'] == when
def test_client_links_job_to_contact_list(mocker, fake_uuid):
mocker.patch('app.notify_client.current_user', id='1')
contact_list_id = uuid.uuid4()
mock_post = mocker.patch('app.notify_client.job_api_client.JobApiClient.post')
JobApiClient().create_job(
fake_uuid, 1, contact_list_id=contact_list_id
)
assert mock_post.call_args[1]['data']['contact_list_id'] == contact_list_id
def test_client_gets_job_by_service_and_job(mocker):
service_id = 'service_id'
job_id = 'job_id'
@@ -335,6 +335,25 @@ def test_client_returns_count_of_service_templates(
],
{'data_from': 'api'},
),
(
service_api_client.get_returned_letter_statistics,
[SERVICE_ONE_ID],
[
call('service-{}-returned-letters-statistics'.format(SERVICE_ONE_ID))
],
None,
[
call('service/{}/returned-letter-statistics'.format(SERVICE_ONE_ID))
],
[
call(
'service-{}-returned-letters-statistics'.format(SERVICE_ONE_ID),
'{"data_from": "api"}',
ex=604800,
)
],
{'data_from': 'api'},
),
]
)
def test_returns_value_from_cache(
+1 -1
View File
@@ -12,7 +12,7 @@ def test_sets_metadata(client, mocker):
set_metadata_on_csv_upload('1234', '5678', foo='bar', baz=True)
mocked_get_s3_object.assert_called_once_with('1234', '5678')
mocked_get_s3_object.assert_called_once_with('1234', '5678', bucket=None)
mocked_s3_object.copy_from.assert_called_once_with(
CopySource='test-notifications-csv-upload/service-1234-notify/5678.csv',
Metadata={'baz': 'True', 'foo': 'bar'},
+1 -1
View File
@@ -191,7 +191,7 @@ def test_caseworkers_get_caseworking_navigation(
)
page = client_request.get('main.choose_template', service_id=SERVICE_ONE_ID)
assert normalize_spaces(page.select_one('header + .govuk-width-container nav').text) == (
'Templates Sent messages Team members'
'Templates Sent messages Uploads Team members'
)