from datetime import datetime
from unittest.mock import Mock, ANY
import pytest
from bs4 import BeautifulSoup
from flask import url_for
from freezegun import freeze_time
from notifications_python_client.errors import HTTPError
from tests.conftest import service_one as create_sample_service
from tests.conftest import (
mock_get_service_email_template,
mock_get_service_letter_template,
mock_get_service_template,
normalize_spaces,
SERVICE_ONE_ID,
active_user_with_permissions,
platform_admin_user,
)
from tests import validate_route_permission, template_json, single_notification_json
from app.main.views.templates import get_last_use_message, get_human_readable_delta
@pytest.mark.parametrize('extra_args, expected_nav_links, expected_templates', [
(
{},
['Text message', 'Email'],
['sms_template_one', 'sms_template_two', 'email_template_one', 'email_template_two']
),
(
{'template_type': 'sms'},
['All', 'Email'],
['sms_template_one', 'sms_template_two'],
),
(
{'template_type': 'email'},
['All', 'Text message'],
['email_template_one', 'email_template_two'],
),
])
def test_should_show_page_for_choosing_a_template(
client_request,
mock_get_service_templates,
extra_args,
expected_nav_links,
expected_templates,
):
page = client_request.get(
'main.choose_template',
service_id=SERVICE_ONE_ID,
**extra_args
)
assert normalize_spaces(page.select('h1')[0].text) == 'Templates'
links_in_page = page.select('.pill a')
assert len(links_in_page) == len(expected_nav_links)
for index, expected_link in enumerate(expected_nav_links):
assert links_in_page[index].text.strip() == expected_link
template_links = page.select('.message-name a')
assert len(template_links) == len(expected_templates)
for index, expected_template in enumerate(expected_templates):
assert template_links[index].text.strip() == expected_template
mock_get_service_templates.assert_called_with(SERVICE_ONE_ID)
def test_should_not_show_template_nav_if_only_one_type_of_template(
client_request,
mock_get_service_templates_with_only_one_template,
):
page = client_request.get(
'main.choose_template',
service_id=SERVICE_ONE_ID,
)
assert not page.select('.pill')
def test_should_show_page_for_one_template(
logged_in_client,
mock_get_service_template,
service_one,
fake_uuid,
):
template_id = fake_uuid
response = logged_in_client.get(url_for(
'.edit_service_template',
service_id=service_one['id'],
template_id=template_id))
assert response.status_code == 200
assert "Two week reminder" in response.get_data(as_text=True)
assert "Template <em>content</em> with & entity" in response.get_data(as_text=True)
assert "Use priority queue?" not in response.get_data(as_text=True)
mock_get_service_template.assert_called_with(service_one['id'], template_id)
@pytest.mark.parametrize('permissions, links_to_be_shown', [
(
['view_activity'],
[]
),
(
['manage_templates'],
['.edit_service_template']
),
(
['send_texts', 'send_emails', 'send_letters'],
['.send_messages', '.set_sender']
),
(
['send_texts', 'send_emails', 'send_letters', 'manage_templates'],
['.send_messages', '.set_sender', '.edit_service_template']
),
])
def test_should_be_able_to_view_a_template_with_links(
client,
mock_get_service_template,
active_user_with_permissions,
single_letter_contact_block,
mocker,
service_one,
fake_uuid,
permissions,
links_to_be_shown,
):
active_user_with_permissions._permissions[service_one['id']] = permissions
client.login(active_user_with_permissions, mocker, service_one)
response = client.get(url_for(
'.view_template',
service_id=service_one['id'],
template_id=fake_uuid
))
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
links_in_page = page.select('.pill-separate-item')
assert len(links_in_page) == len(links_to_be_shown)
for index, link_to_be_shown in enumerate(links_to_be_shown):
assert links_in_page[index]['href'] == url_for(
link_to_be_shown,
service_id=service_one['id'],
template_id=fake_uuid,
)
def test_should_show_template_id_on_template_page(
logged_in_client,
mock_get_service_template,
service_one,
fake_uuid,
):
response = logged_in_client.get(url_for(
'.view_template',
service_id=service_one['id'],
template_id=fake_uuid))
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.select('.api-key-key')[0].text == fake_uuid
def test_should_show_sms_template_with_downgraded_unicode_characters(
logged_in_client,
mocker,
service_one,
single_letter_contact_block,
fake_uuid,
):
msg = 'here:\tare some “fancy quotes” and zero\u200Bwidth\u200Bspaces'
rendered_msg = 'here: are some "fancy quotes" and zerowidthspaces'
mocker.patch(
'app.service_api_client.get_service_template',
return_value={'data': template_json(service_one['id'], fake_uuid, type_='sms', content=msg)}
)
template_id = fake_uuid
response = logged_in_client.get(url_for(
'.view_template',
service_id=service_one['id'],
template_id=template_id))
assert response.status_code == 200
assert rendered_msg in response.get_data(as_text=True)
def test_should_let_letter_contact_block_be_edited_if_a_letter_contact_block_exists(
mocker,
mock_get_service_letter_template,
single_letter_contact_block,
client_request,
service_one,
fake_uuid,
):
service_one['permissions'].append('letter')
mocker.patch('app.main.views.templates.get_page_count_for_letter', return_value=1)
page = client_request.get(
'main.view_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid
)
assert page.find('a', {'class': 'edit-template-link-letter-contact'})['href'] == url_for(
'.service_edit_letter_contact',
service_id=service_one['id'],
letter_contact_id='1234',
from_template=fake_uuid)
def test_should_let_letter_contact_block_be_added_if_no_letter_contact_blocks_exist(
mocker,
mock_get_service_letter_template,
no_letter_contact_blocks,
client_request,
service_one,
fake_uuid,
):
service_one['permissions'].append('letter')
mocker.patch('app.main.views.templates.get_page_count_for_letter', return_value=1)
page = client_request.get(
'main.view_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid
)
assert page.find('a', {'class': 'edit-template-link-letter-contact'})['href'] == url_for(
'.service_add_letter_contact',
service_id=service_one['id'],
from_template=fake_uuid)
def test_should_show_page_template_with_priority_select_if_platform_admin(
logged_in_platform_admin_client,
platform_admin_user,
mocker,
mock_get_service_template,
fake_uuid,
):
mocker.patch('app.user_api_client.get_users_for_service', return_value=[platform_admin_user])
template_id = fake_uuid
response = logged_in_platform_admin_client.get(url_for(
'.edit_service_template',
service_id='1234',
template_id=template_id))
assert response.status_code == 200
assert "Two week reminder" in response.get_data(as_text=True)
assert "Template <em>content</em> with & entity" in response.get_data(as_text=True)
assert "Use priority queue?" in response.get_data(as_text=True)
mock_get_service_template.assert_called_with('1234', template_id)
@pytest.mark.parametrize('filetype', ['pdf', 'png'])
@pytest.mark.parametrize('view, extra_view_args', [
('.view_letter_template_preview', {}),
('.view_template_version_preview', {'version': 1}),
])
def test_should_show_preview_letter_templates(
view,
extra_view_args,
filetype,
logged_in_client,
mock_get_service_email_template,
service_one,
fake_uuid,
mocker
):
mocked_preview = mocker.patch(
'app.main.views.templates.TemplatePreview.from_database_object',
return_value='foo'
)
service_id, template_id = service_one['id'], fake_uuid
response = logged_in_client.get(url_for(
view,
service_id=service_id,
template_id=template_id,
filetype=filetype,
**extra_view_args
))
assert response.status_code == 200
assert response.get_data(as_text=True) == 'foo'
mock_get_service_email_template.assert_called_with(service_id, template_id, **extra_view_args)
assert mocked_preview.call_args[0][0]['id'] == template_id
assert mocked_preview.call_args[0][0]['service'] == service_id
assert mocked_preview.call_args[0][1] == filetype
def test_dont_show_preview_letter_templates_for_bad_filetype(
logged_in_client,
mock_get_service_template,
service_one,
fake_uuid
):
resp = logged_in_client.get(
url_for(
'.view_letter_template_preview',
service_id=service_one['id'],
template_id=fake_uuid,
filetype='blah'
)
)
assert resp.status_code == 404
assert mock_get_service_template.called is False
@pytest.mark.parametrize('type_of_template', ['email', 'sms'])
def test_should_not_allow_creation_of_template_through_form_without_correct_permission(
logged_in_client,
service_one,
mocker,
type_of_template,
):
service_one['permissions'] = []
template_description = {'sms': 'text messages', 'email': 'emails'}
response = logged_in_client.post(url_for(
'.add_template_by_type',
service_id=service_one['id']),
data={'template_type': type_of_template},
follow_redirects=True)
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert response.status_code == 200
assert page.select('main p')[0].text.strip() == \
"Sending {} has been disabled for your service.".format(template_description[type_of_template])
assert page.select(".page-footer-back-link")[0].text == "Back to add new template"
assert page.select(".page-footer-back-link")[0]['href'] == url_for(
'.add_template_by_type',
service_id=service_one['id'],
template_id='0',
)
@pytest.mark.parametrize('type_of_template', ['email', 'sms'])
def test_should_not_allow_creation_of_a_template_without_correct_permission(
logged_in_client,
service_one,
mocker,
type_of_template,
):
service_one['permissions'] = []
template_description = {'sms': 'text messages', 'email': 'emails'}
response = logged_in_client.get(url_for(
'.add_service_template',
service_id=service_one['id'],
template_type=type_of_template),
follow_redirects=True)
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert response.status_code == 200
assert page.select('main p')[0].text.strip() == \
"Sending {} has been disabled for your service.".format(template_description[type_of_template])
assert page.select(".page-footer-back-link")[0].text == "Back to templates"
assert page.select(".page-footer-back-link")[0]['href'] == url_for(
'.choose_template',
service_id=service_one['id'],
template_id='0',
)
@pytest.mark.parametrize('fixture, expected_status_code', [
(mock_get_service_email_template, 200),
(mock_get_service_template, 200),
(mock_get_service_letter_template, 302),
])
def test_should_redirect_to_one_off_if_template_type_is_letter(
logged_in_client,
active_user_with_permissions,
multiple_reply_to_email_addresses,
multiple_sms_senders,
service_one,
fake_uuid,
mocker,
fixture,
expected_status_code
):
fixture(mocker)
page = logged_in_client.get(
url_for('.set_sender', service_id=service_one['id'], template_id=fake_uuid)
)
assert page.status_code == expected_status_code
def test_should_redirect_when_saving_a_template(
logged_in_client,
active_user_with_permissions,
mocker,
mock_get_service_template,
mock_update_service_template,
fake_uuid,
):
service = create_sample_service(active_user_with_permissions)
mocker.patch('app.user_api_client.get_users_for_service', return_value=[active_user_with_permissions])
template_id = fake_uuid
name = "new name"
content = "template content with & entity"
data = {
'id': template_id,
'name': name,
'template_content': content,
'template_type': 'sms',
'service': service['id'],
'process_type': 'normal'
}
response = logged_in_client.post(url_for(
'.edit_service_template',
service_id=service['id'],
template_id=template_id), data=data)
assert response.status_code == 302
assert response.location == url_for(
'.view_template', service_id=service['id'], template_id=template_id, _external=True)
mock_update_service_template.assert_called_with(
template_id, name, 'sms', content, service['id'], None, 'normal')
def test_should_edit_content_when_process_type_is_priority_not_platform_admin(
logged_in_client,
active_user_with_permissions,
mocker,
mock_get_service_template_with_priority,
mock_update_service_template,
fake_uuid,
):
service = create_sample_service(active_user_with_permissions)
mocker.patch('app.user_api_client.get_users_for_service', return_value=[active_user_with_permissions])
template_id = fake_uuid
data = {
'id': template_id,
'name': "new name",
'template_content': "new template content with & entity",
'template_type': 'sms',
'service': service['id'],
'process_type': 'priority'
}
response = logged_in_client.post(url_for(
'.edit_service_template',
service_id=service['id'],
template_id=template_id), data=data)
assert response.status_code == 302
assert response.location == url_for(
'.view_template', service_id=service['id'], template_id=template_id, _external=True)
mock_update_service_template.assert_called_with(
template_id,
"new name",
'sms',
"new template content with & entity",
service['id'],
None,
'priority'
)
def test_should_not_allow_template_edits_without_correct_permission(
logged_in_client,
mock_get_service_template,
service_one,
fake_uuid,
):
template_id = fake_uuid
service_one['permissions'] = ['email']
response = logged_in_client.get(url_for(
'.edit_service_template',
service_id=service_one['id'],
template_id=template_id),
follow_redirects=True)
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert response.status_code == 200
assert page.select('main p')[0].text.strip() == "Sending text messages has been disabled for your service."
assert page.select(".page-footer-back-link")[0].text == "Back to the template"
assert page.select(".page-footer-back-link")[0]['href'] == url_for(
'.view_template',
service_id=service_one['id'],
template_id=template_id,
)
def test_should_403_when_edit_template_with_process_type_of_priority_for_non_platform_admin(
client,
active_user_with_permissions,
mocker,
mock_get_service_template,
mock_update_service_template,
fake_uuid,
):
service = create_sample_service(active_user_with_permissions)
client.login(active_user_with_permissions, mocker, service)
mocker.patch('app.user_api_client.get_users_for_service', return_value=[active_user_with_permissions])
template_id = fake_uuid
data = {
'id': template_id,
'name': "new name",
'template_content': "template content with & entity",
'template_type': 'sms',
'service': service['id'],
'process_type': 'priority'
}
response = client.post(url_for(
'.edit_service_template',
service_id=service['id'],
template_id=template_id), data=data)
assert response.status_code == 403
mock_update_service_template.called == 0
def test_should_403_when_create_template_with_process_type_of_priority_for_non_platform_admin(
client,
active_user_with_permissions,
mocker,
mock_get_service_template,
mock_update_service_template,
fake_uuid,
):
service = create_sample_service(active_user_with_permissions)
client.login(active_user_with_permissions, mocker, service)
mocker.patch('app.user_api_client.get_users_for_service', return_value=[active_user_with_permissions])
template_id = fake_uuid
data = {
'id': template_id,
'name': "new name",
'template_content': "template content with & entity",
'template_type': 'sms',
'service': service['id'],
'process_type': 'priority'
}
response = client.post(url_for(
'.add_service_template',
service_id=service['id'],
template_type='sms'), data=data)
assert response.status_code == 403
mock_update_service_template.called == 0
@pytest.mark.parametrize('template_mock, expected_paragraphs', [
(
mock_get_service_email_template,
[
'You removed ((date))',
'You added ((name))',
'When you send messages using this template you’ll need 3 columns of data:',
]
),
(
mock_get_service_letter_template,
[
'You removed ((date))',
'You added ((name))',
'When you send messages using this template you’ll need 9 columns of data:',
]
),
])
def test_should_show_interstitial_when_making_breaking_change(
logged_in_client,
api_user_active,
mock_login,
mock_update_service_template,
mock_get_user,
mock_get_service,
mock_get_user_by_email,
mock_has_permissions,
fake_uuid,
mocker,
template_mock,
expected_paragraphs,
):
template_mock(
mocker,
subject="Your ((thing)) is due soon",
content="Your vehicle tax expires on ((date))",
)
service_id = fake_uuid
template_id = fake_uuid
response = logged_in_client.post(
url_for('.edit_service_template', service_id=service_id, template_id=template_id),
data={
'id': template_id,
'name': "new name",
'template_content': "hello lets talk about ((thing))",
'template_type': 'email',
'subject': 'reminder \'" & ((name))',
'service': service_id,
'process_type': 'normal'
}
)
assert response.status_code == 200
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert page.h1.string.strip() == "Confirm changes"
assert page.find('a', {'class': 'page-footer-back-link'})['href'] == url_for(".edit_service_template",
service_id=service_id,
template_id=template_id)
for index, p in enumerate(expected_paragraphs):
assert normalize_spaces(page.select('main p')[index].text) == p
for key, value in {
'name': 'new name',
'subject': 'reminder \'" & ((name))',
'template_content': 'hello lets talk about ((thing))',
'confirm': 'true'
}.items():
assert page.find('input', {'name': key})['value'] == value
# BeautifulSoup returns the value attribute as unencoded, let’s make
# sure that it is properly encoded in the HTML
assert str(page.find('input', {'name': 'subject'})) == (
""""""
)
def test_removing_placeholders_is_not_a_breaking_change(
logged_in_client,
mock_get_service_email_template,
mock_update_service_template,
mock_has_permissions,
fake_uuid,
):
service_id = fake_uuid
template_id = fake_uuid
existing_template = mock_get_service_email_template(0, 0)['data']
response = logged_in_client.post(
url_for(
'.edit_service_template',
service_id=service_id,
template_id=template_id
),
data={
'name': existing_template['name'],
'template_content': "no placeholders",
'subject': existing_template['subject'],
}
)
assert response.status_code == 302
assert response.location == url_for(
'main.view_template',
service_id=service_id,
template_id=template_id,
_external=True,
)
def test_should_not_create_too_big_template(
logged_in_client,
service_one,
mock_get_service_template,
mock_create_service_template_content_too_big,
fake_uuid,
):
template_type = 'sms'
data = {
'name': "new name",
'template_content': "template content",
'template_type': template_type,
'service': service_one['id'],
'process_type': 'normal'
}
resp = logged_in_client.post(url_for(
'.add_service_template',
service_id=service_one['id'],
template_type=template_type
), data=data)
assert resp.status_code == 200
assert "Content has a character count greater than the limit of 459" in resp.get_data(as_text=True)
def test_should_not_update_too_big_template(
logged_in_client,
service_one,
mock_get_service_template,
mock_update_service_template_400_content_too_big,
fake_uuid,
):
template_id = fake_uuid
data = {
'id': fake_uuid,
'name': "new name",
'template_content': "template content",
'service': service_one['id'],
'template_type': 'sms',
'process_type': 'normal'
}
resp = logged_in_client.post(url_for(
'.edit_service_template',
service_id=service_one['id'],
template_id=template_id), data=data)
assert resp.status_code == 200
assert "Content has a character count greater than the limit of 459" in resp.get_data(as_text=True)
def test_should_redirect_when_saving_a_template_email(
logged_in_client,
api_user_active,
mock_login,
mock_get_service_email_template,
mock_update_service_template,
mock_get_user,
mock_get_service,
mock_get_user_by_email,
mock_has_permissions,
fake_uuid,
):
service_id = fake_uuid
template_id = fake_uuid
name = "new name"
content = "template content with & entity ((thing)) ((date))"
subject = "subject & entity"
data = {
'id': template_id,
'name': name,
'template_content': content,
'template_type': 'email',
'service': service_id,
'subject': subject,
'process_type': 'normal'
}
response = logged_in_client.post(url_for(
'.edit_service_template',
service_id=service_id,
template_id=template_id), data=data)
assert response.status_code == 302
assert response.location == url_for(
'.view_template',
service_id=service_id,
template_id=template_id,
_external=True)
mock_update_service_template.assert_called_with(
template_id, name, 'email', content, service_id, subject, 'normal')
def test_should_show_delete_template_page_with_time_block(
client_request,
mock_get_service_template,
mocker,
fake_uuid
):
with freeze_time('2012-01-01 12:00:00'):
template = template_json('1234', '1234', "Test template", "sms", "Something very interesting")
notification = single_notification_json('1234', template=template)
mocker.patch('app.template_statistics_client.get_template_statistics_for_template',
return_value=notification)
with freeze_time('2012-01-01 12:10:00'):
page = client_request.get(
'.delete_service_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_test_page_title=False,
)
assert page.h1.text == 'Are you sure you want to delete Two week reminder?'
assert normalize_spaces(page.select('.banner-dangerous p')[0].text) == (
'It was last used 10 minutes ago'
)
assert normalize_spaces(page.select('.sms-message-wrapper')[0].text) == (
'service one: Template content with & entity'
)
mock_get_service_template.assert_called_with(SERVICE_ONE_ID, fake_uuid)
def test_should_show_delete_template_page_with_time_block_for_empty_notification(
client_request,
mock_get_service_template,
mocker,
fake_uuid
):
with freeze_time('2012-01-08 12:00:00'):
template = template_json('1234', '1234', "Test template", "sms", "Something very interesting")
single_notification_json('1234', template=template)
mocker.patch('app.template_statistics_client.get_template_statistics_for_template',
return_value=None)
with freeze_time('2012-01-01 11:00:00'):
page = client_request.get(
'.delete_service_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_test_page_title=False,
)
assert page.h1.text == 'Are you sure you want to delete Two week reminder?'
assert normalize_spaces(page.select('.banner-dangerous p')[0].text) == (
'It was last used more than seven days ago'
)
assert normalize_spaces(page.select('.sms-message-wrapper')[0].text) == (
'service one: Template content with & entity'
)
mock_get_service_template.assert_called_with(SERVICE_ONE_ID, fake_uuid)
def test_should_show_delete_template_page_with_never_used_block(
client_request,
mock_get_service_template,
fake_uuid,
mocker,
):
mocker.patch(
'app.template_statistics_client.get_template_statistics_for_template',
side_effect=HTTPError(response=Mock(status_code=404), message="Default message")
)
page = client_request.get(
'.delete_service_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_test_page_title=False,
)
assert page.h1.text == 'Are you sure you want to delete Two week reminder?'
assert not page.select('.banner-dangerous p')
assert normalize_spaces(page.select('.sms-message-wrapper')[0].text) == (
'service one: Template content with & entity'
)
mock_get_service_template.assert_called_with(SERVICE_ONE_ID, fake_uuid)
def test_should_redirect_when_deleting_a_template(
logged_in_client,
api_user_active,
mock_login,
mock_get_service,
mock_get_service_template,
mock_delete_service_template,
mock_get_user,
mock_get_user_by_email,
mock_has_permissions,
fake_uuid,
):
service_id = fake_uuid
template_id = fake_uuid
name = "new name"
type_ = "sms"
content = "template content"
data = {
'id': str(template_id),
'name': name,
'template_type': type_,
'content': content,
'service': service_id
}
response = logged_in_client.post(url_for(
'.delete_service_template',
service_id=service_id,
template_id=template_id
), data=data)
assert response.status_code == 302
assert response.location == url_for(
'.choose_template',
service_id=service_id, _external=True)
mock_get_service_template.assert_called_with(
service_id, template_id)
mock_delete_service_template.assert_called_with(
service_id, template_id)
@freeze_time('2016-01-01T15:00')
def test_should_show_page_for_a_deleted_template(
logged_in_client,
api_user_active,
mock_login,
mock_get_service,
mock_get_deleted_template,
single_letter_contact_block,
mock_get_user,
mock_get_user_by_email,
mock_has_permissions,
fake_uuid,
):
service_id = fake_uuid
template_id = fake_uuid
response = logged_in_client.get(url_for(
'.view_template',
service_id=service_id,
template_id=template_id
))
assert response.status_code == 200
content = response.get_data(as_text=True)
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
assert url_for("main.edit_service_template", service_id=fake_uuid, template_id=fake_uuid) not in content
assert url_for("main.send_test", service_id=fake_uuid, template_id=fake_uuid) not in content
assert page.select('p.hint')[0].text.strip() == 'This template was deleted today at 3:00pm.'
assert 'Delete this template' not in page.select_one('main').text
mock_get_deleted_template.assert_called_with(service_id, template_id)
@pytest.mark.parametrize('route', [
'main.add_service_template',
'main.edit_service_template',
'main.delete_service_template'
])
def test_route_permissions(
route,
mocker,
app_,
client,
api_user_active,
service_one,
mock_get_service_template,
mock_get_template_statistics_for_template,
fake_uuid,
):
validate_route_permission(
mocker,
app_,
"GET",
200,
url_for(
route,
service_id=service_one['id'],
template_type='sms',
template_id=fake_uuid),
['manage_templates'],
api_user_active,
service_one)
def test_route_permissions_for_choose_template(
mocker,
app_,
client,
api_user_active,
service_one,
mock_get_service_templates,
):
mocker.patch('app.job_api_client.get_job')
validate_route_permission(
mocker,
app_,
"GET",
200,
url_for(
'main.choose_template',
service_id=service_one['id'],
),
['view_activity'],
api_user_active,
service_one)
@pytest.mark.parametrize('route', [
'main.add_service_template',
'main.edit_service_template',
'main.delete_service_template'
])
def test_route_invalid_permissions(
route,
mocker,
app_,
client,
api_user_active,
service_one,
mock_get_service_template,
mock_get_template_statistics_for_template,
fake_uuid,
):
validate_route_permission(
mocker,
app_,
"GET",
403,
url_for(
route,
service_id=service_one['id'],
template_type='sms',
template_id=fake_uuid),
['view_activity'],
api_user_active,
service_one)
def test_get_last_use_message_returns_no_template_message():
assert get_last_use_message('My Template', []) == 'My Template has never been used'
@freeze_time('2000-01-01T15:00')
def test_get_last_use_message_uses_most_recent_statistics():
template_statistics = [
{
'updated_at': '2000-01-01T12:00:00.000000+00:00'
},
{
'updated_at': '2000-01-01T09:00:00.000000+00:00'
},
]
assert get_last_use_message('My Template', template_statistics) == 'My Template was last used 3 hours ago'
@pytest.mark.parametrize('from_time, until_time, message', [
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 12, 0, 59), 'under a minute'),
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 12, 1), '1 minute'),
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 12, 2, 35), '2 minutes'),
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 12, 59), '59 minutes'),
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 13, 0), '1 hour'),
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 1, 14, 0), '2 hours'),
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 2, 11, 59), '23 hours'),
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 2, 12, 0), '1 day'),
(datetime(2000, 1, 1, 12, 0), datetime(2000, 1, 3, 14, 0), '2 days'),
])
def test_get_human_readable_delta(from_time, until_time, message):
assert get_human_readable_delta(from_time, until_time) == message
def test_can_create_email_template_with_emoji(
logged_in_client,
service_one,
mock_create_service_template
):
data = {
'name': "new name",
'subject': "Food incoming!",
'template_content': "here's a burrito 🌯",
'template_type': 'email',
'service': service_one['id'],
'process_type': 'normal'
}
resp = logged_in_client.post(url_for(
'.add_service_template',
service_id=service_one['id'],
template_type='email'
), data=data)
assert resp.status_code == 302
def test_should_not_create_sms_template_with_emoji(
logged_in_client,
service_one,
mock_create_service_template
):
data = {
'name': "new name",
'template_content': "here are some noodles 🍜",
'template_type': 'sms',
'service': service_one['id'],
'process_type': 'normal'
}
resp = logged_in_client.post(url_for(
'.add_service_template',
service_id=service_one['id'],
template_type='sms'
), data=data)
assert resp.status_code == 200
assert "You can’t use 🍜 in text messages." in resp.get_data(as_text=True)
def test_should_not_update_sms_template_with_emoji(
logged_in_client,
service_one,
mock_get_service_template,
mock_update_service_template,
fake_uuid,
):
data = {
'id': fake_uuid,
'name': "new name",
'template_content': "here's a burger 🍔",
'service': service_one['id'],
'template_type': 'sms',
'process_type': 'normal'
}
resp = logged_in_client.post(url_for(
'.edit_service_template',
service_id=service_one['id'],
template_id=fake_uuid), data=data)
assert resp.status_code == 200
assert "You can’t use 🍔 in text messages." in resp.get_data(as_text=True)
def test_should_create_sms_template_without_downgrading_unicode_characters(
logged_in_client,
service_one,
mock_create_service_template
):
msg = 'here:\tare some “fancy quotes” and non\u200Bbreaking\u200Bspaces'
data = {
'name': "new name",
'template_content': msg,
'template_type': 'sms',
'service': service_one['id'],
'process_type': 'normal'
}
resp = logged_in_client.post(url_for(
'.add_service_template',
service_id=service_one['id'],
template_type='sms'
), data=data)
mock_create_service_template.assert_called_with(
ANY, # name
ANY, # type
msg, # content
ANY, # service_id
ANY, # subject
ANY # process_type
)
assert resp.status_code == 302
def test_should_show_template_as_first_page_of_tour(
client_request,
mock_get_service_template,
service_one,
fake_uuid,
):
page = client_request.get(
'main.start_tour',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
)
assert normalize_spaces(
page.select('.banner-tour .heading-medium')[0].text
) == (
'Try sending yourself this example'
)
assert normalize_spaces(
page.select('.sms-message-wrapper')[0].text
) == (
'service one: Template content with & entity'
)
assert page.select('a.button')[0]['href'] == url_for(
'.send_test', service_id=SERVICE_ONE_ID, template_id=fake_uuid, help=2
)
@pytest.mark.parametrize('template_mock', [
mock_get_service_email_template,
mock_get_service_letter_template,
])
def test_cant_see_email_template_in_tour(
client_request,
fake_uuid,
mocker,
template_mock,
):
template_mock(mocker)
client_request.get(
'main.start_tour',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_expected_status=404,
)
def test_should_show_message_before_redacting_template(
client_request,
mock_get_service_template,
service_one,
fake_uuid,
):
page = client_request.get(
'main.redact_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_test_page_title=False,
)
assert (
'Are you sure you want to hide personalisation after sending?'
) in page.select('.banner-dangerous')[0].text
form = page.select('.banner-dangerous form')[0]
assert 'action' not in form
assert form['method'] == 'post'
def test_should_show_redact_template(
client_request,
mock_get_service_template,
mock_redact_template,
single_letter_contact_block,
service_one,
fake_uuid,
):
page = client_request.post(
'main.redact_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
_follow_redirects=True,
)
assert normalize_spaces(page.select('.banner-default-with-tick')[0].text) == (
'Personalised content will be hidden for messages sent with this template'
)
mock_redact_template.assert_called_once_with(SERVICE_ONE_ID, fake_uuid)
def test_should_show_hint_once_template_redacted(
client_request,
mocker,
service_one,
fake_uuid,
):
mock_get_service_email_template(mocker, redact_personalisation=True)
page = client_request.get(
'main.view_template',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
)
assert page.select('.hint')[0].text == 'Personalisation is hidden after sending'
@pytest.mark.parametrize('test_user, template_mock, expected_response_code', [
(
active_user_with_permissions,
mock_get_service_letter_template,
403
),
(
platform_admin_user,
mock_get_service_template,
404
),
(
platform_admin_user,
mock_get_service_email_template,
404
),
(
platform_admin_user,
mock_get_service_letter_template,
200
),
])
def test_should_show_letter_template_as_dvla_markup(
client,
mocker,
service_one,
fake_uuid,
mock_get_service,
test_user,
template_mock,
expected_response_code,
):
client.login(test_user(fake_uuid), mocker, service_one)
template_mock(mocker)
response = client.get(url_for(
'.view_template_as_dvla_markup',
service_id=SERVICE_ONE_ID,
template_id=fake_uuid,
))
assert response.status_code == expected_response_code