mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-05-16 23:09:14 -04:00
2137 lines
59 KiB
Python
2137 lines
59 KiB
Python
import json
|
||
from unittest.mock import ANY, Mock
|
||
|
||
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 import template_json, validate_route_permission
|
||
from tests.app.main.views.test_template_folders import (
|
||
CHILD_FOLDER_ID,
|
||
FOLDER_TWO_ID,
|
||
PARENT_FOLDER_ID,
|
||
_folder,
|
||
_template,
|
||
)
|
||
from tests.conftest import (
|
||
SERVICE_ONE_ID,
|
||
SERVICE_TWO_ID,
|
||
TEMPLATE_ONE_ID,
|
||
ElementNotFound,
|
||
create_active_caseworking_user,
|
||
create_active_user_view_permissions,
|
||
create_template,
|
||
normalize_spaces,
|
||
)
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
("permissions", "expected_message"),
|
||
[
|
||
(
|
||
["email"],
|
||
(
|
||
"Every message starts with a template. You can change it later. "
|
||
"You need a template before you can send messages."
|
||
),
|
||
),
|
||
(
|
||
["sms"],
|
||
(
|
||
"Every message starts with a template. You can change it later. "
|
||
"You need a template before you can send messages."
|
||
),
|
||
),
|
||
(
|
||
["email", "sms"],
|
||
(
|
||
"Every message starts with a template. You can change it later. "
|
||
"You need a template before you can send messages."
|
||
),
|
||
),
|
||
],
|
||
)
|
||
def test_should_show_empty_page_when_no_templates(
|
||
client_request,
|
||
service_one,
|
||
mock_get_service_templates_when_no_templates_exist,
|
||
mock_get_template_folders,
|
||
mock_get_no_api_keys,
|
||
permissions,
|
||
expected_message,
|
||
):
|
||
service_one["permissions"] = permissions
|
||
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=service_one["id"],
|
||
)
|
||
|
||
assert normalize_spaces(page.select_one("h1").text) == (
|
||
"Select or create a template"
|
||
)
|
||
assert normalize_spaces(page.select_one("main p").text) == (expected_message)
|
||
assert page.select_one("#add_new_folder_form")
|
||
assert page.select_one("#add_new_template_form")
|
||
|
||
|
||
def test_should_show_add_template_form_if_service_has_folder_permission(
|
||
client_request,
|
||
service_one,
|
||
mock_get_service_templates_when_no_templates_exist,
|
||
mock_get_template_folders,
|
||
mock_get_no_api_keys,
|
||
):
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=service_one["id"],
|
||
)
|
||
|
||
assert normalize_spaces(page.select_one("h1").text) == (
|
||
"Select or create a template"
|
||
)
|
||
assert normalize_spaces(page.select_one("main p").text) == (
|
||
"Every message starts with a template. You can change it later. "
|
||
"You need a template before you can send messages."
|
||
)
|
||
assert [(item["name"], item["value"]) for item in page.select("[type=radio]")] == [
|
||
# ('add_template_by_template_type', 'email'),
|
||
("add_template_by_template_type", "sms"),
|
||
]
|
||
assert not page.select("main a")
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
(
|
||
"user",
|
||
"expected_page_title",
|
||
"extra_args",
|
||
"expected_nav_links",
|
||
"expected_templates",
|
||
),
|
||
[
|
||
(
|
||
create_active_user_view_permissions(),
|
||
"Select or create a template",
|
||
{},
|
||
["Email", "Text message"],
|
||
[
|
||
"sms_template_one",
|
||
"sms_template_two",
|
||
"email_template_one",
|
||
"email_template_two",
|
||
],
|
||
),
|
||
(
|
||
create_active_user_view_permissions(),
|
||
"Select or create a template",
|
||
{"template_type": "sms"},
|
||
["All", "Email"],
|
||
["sms_template_one", "sms_template_two"],
|
||
),
|
||
(
|
||
create_active_user_view_permissions(),
|
||
"Select or create a template",
|
||
{"template_type": "email"},
|
||
["All", "Text message"],
|
||
["email_template_one", "email_template_two"],
|
||
),
|
||
(
|
||
create_active_caseworking_user(),
|
||
"Select or create a template",
|
||
{},
|
||
["Email", "Text message"],
|
||
[
|
||
"sms_template_one",
|
||
"sms_template_two",
|
||
"email_template_one",
|
||
"email_template_two",
|
||
],
|
||
),
|
||
(
|
||
create_active_caseworking_user(),
|
||
"Select or create a template",
|
||
{"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,
|
||
mock_get_template_folders,
|
||
mock_has_no_jobs,
|
||
mock_get_no_api_keys,
|
||
extra_args,
|
||
expected_nav_links,
|
||
expected_templates,
|
||
service_one,
|
||
mocker,
|
||
user,
|
||
expected_page_title,
|
||
):
|
||
client_request.login(user)
|
||
|
||
page = client_request.get(
|
||
"main.choose_template", service_id=service_one["id"], **extra_args
|
||
)
|
||
|
||
assert normalize_spaces(page.select_one("h1").text) == expected_page_title
|
||
|
||
links_in_page = page.select(".pill a:not(.pill-item--selected)")
|
||
|
||
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("#template-list a, .template-list-item 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_once_with(SERVICE_ONE_ID)
|
||
mock_get_template_folders.assert_called_once_with(SERVICE_ONE_ID)
|
||
|
||
|
||
def test_choose_template_can_pass_through_an_initial_state_to_templates_and_folders_selection_form(
|
||
client_request,
|
||
mock_get_template_folders,
|
||
mock_get_service_templates,
|
||
mock_get_no_api_keys,
|
||
):
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
initial_state="add-new-template",
|
||
)
|
||
|
||
templates_and_folders_form = page.find("form")
|
||
assert templates_and_folders_form["data-prev-state"] == "add-new-template"
|
||
|
||
|
||
def test_should_not_show_template_nav_if_only_one_type_of_template(
|
||
client_request,
|
||
mock_get_template_folders,
|
||
mock_get_service_templates_with_only_one_template,
|
||
mock_get_no_api_keys,
|
||
):
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
|
||
assert not page.select(".pill")
|
||
|
||
|
||
def test_should_not_show_live_search_if_list_of_templates_fits_onscreen(
|
||
client_request,
|
||
mock_get_template_folders,
|
||
mock_get_service_templates,
|
||
mock_get_no_api_keys,
|
||
):
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
|
||
assert not page.select(".live-search")
|
||
|
||
|
||
def test_should_show_live_search_if_list_of_templates_taller_than_screen(
|
||
client_request,
|
||
mock_get_template_folders,
|
||
mock_get_more_service_templates_than_can_fit_onscreen,
|
||
mock_get_no_api_keys,
|
||
):
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
search = page.select_one(".live-search")
|
||
|
||
assert search["data-module"] == "live-search"
|
||
assert search["data-targets"] == "#template-list .template-list-item"
|
||
assert normalize_spaces(search.select_one("label").text) == ("Search by name")
|
||
|
||
assert (
|
||
len(page.select(search["data-targets"]))
|
||
== len(page.select("#template-list .usa-checkbox"))
|
||
== 20
|
||
)
|
||
|
||
|
||
def test_should_label_search_by_id_for_services_with_api_keys(
|
||
client_request,
|
||
mock_get_template_folders,
|
||
mock_get_more_service_templates_than_can_fit_onscreen,
|
||
mock_get_api_keys,
|
||
):
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
assert normalize_spaces(page.select_one(".live-search label").text) == (
|
||
"Search by name or ID"
|
||
)
|
||
|
||
|
||
def test_should_show_live_search_if_service_has_lots_of_folders(
|
||
client_request,
|
||
mock_get_template_folders,
|
||
mock_get_service_templates, # returns 4 templates
|
||
mock_get_no_api_keys,
|
||
):
|
||
mock_get_template_folders.return_value = [
|
||
_folder("one", PARENT_FOLDER_ID),
|
||
_folder("two", None, parent=PARENT_FOLDER_ID),
|
||
_folder("three", None, parent=PARENT_FOLDER_ID),
|
||
_folder("four", None, parent=PARENT_FOLDER_ID),
|
||
]
|
||
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
|
||
count_of_templates_and_folders = len(page.select("#template-list .usa-checkbox"))
|
||
count_of_folders = len(page.select(".template-list-folder:first-of-type"))
|
||
count_of_templates = count_of_templates_and_folders - count_of_folders
|
||
|
||
assert len(page.select(".live-search")) == 1
|
||
assert count_of_folders == 4
|
||
assert count_of_templates == 4
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
("service_permissions", "expected_values", "expected_labels"),
|
||
[
|
||
pytest.param(
|
||
["email", "sms"],
|
||
[
|
||
# 'email',
|
||
"sms",
|
||
"copy-existing",
|
||
],
|
||
[
|
||
# 'Email',
|
||
"Start with a blank template",
|
||
"Copy an existing template",
|
||
],
|
||
),
|
||
# TODO This is a duplicate of above. Why?
|
||
# pytest.param(
|
||
# ["email", "sms"],
|
||
# [
|
||
# # 'email',
|
||
# "sms",
|
||
# "copy-existing",
|
||
# ],
|
||
# [
|
||
# # 'Email',
|
||
# "Start with a blank template",
|
||
# "Copy an existing template",
|
||
# ],
|
||
# ),
|
||
],
|
||
)
|
||
def test_should_show_new_template_choices_if_service_has_folder_permission(
|
||
client_request,
|
||
service_one,
|
||
mock_get_service_templates,
|
||
mock_get_template_folders,
|
||
mock_get_no_api_keys,
|
||
service_permissions,
|
||
expected_values,
|
||
expected_labels,
|
||
):
|
||
service_one["permissions"] = service_permissions
|
||
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
|
||
if not page.select("#add_new_template_form"):
|
||
raise ElementNotFound()
|
||
|
||
assert normalize_spaces(
|
||
page.select_one("#add_new_template_form fieldset legend").text
|
||
) == ("New template")
|
||
assert [
|
||
choice["value"]
|
||
for choice in page.select("#add_new_template_form input[type=radio]")
|
||
] == expected_values
|
||
assert [
|
||
normalize_spaces(choice.text)
|
||
for choice in page.select("#add_new_template_form label")
|
||
] == expected_labels
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
("permissions", "are_data_attrs_added"),
|
||
[
|
||
(["sms"], True),
|
||
(["email"], True),
|
||
(["sms", "email"], False),
|
||
],
|
||
)
|
||
def test_should_add_data_attributes_for_services_that_only_allow_one_type_of_notifications(
|
||
client_request,
|
||
service_one,
|
||
mock_get_service_templates,
|
||
mock_get_template_folders,
|
||
mock_get_no_api_keys,
|
||
permissions,
|
||
are_data_attrs_added,
|
||
):
|
||
service_one["permissions"] = permissions
|
||
|
||
page = client_request.get(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
|
||
if not page.select("#add_new_template_form"):
|
||
raise ElementNotFound()
|
||
|
||
if are_data_attrs_added:
|
||
assert (
|
||
page.find(id="add_new_template_form").attrs["data-channel"]
|
||
== permissions[0]
|
||
)
|
||
assert (
|
||
page.find(id="add_new_template_form").attrs["data-service"]
|
||
== SERVICE_ONE_ID
|
||
)
|
||
else:
|
||
assert page.find(id="add_new_template_form").attrs.get("data-channel") is None
|
||
assert page.find(id="add_new_template_form").attrs.get("data-service") is None
|
||
|
||
|
||
def test_should_show_page_for_one_template(
|
||
client_request,
|
||
mock_get_service_template,
|
||
fake_uuid,
|
||
):
|
||
template_id = fake_uuid
|
||
page = client_request.get(
|
||
".edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=template_id,
|
||
)
|
||
|
||
assert page.select_one("input[type=text]")["value"] == "Two week reminder"
|
||
assert "Template <em>content</em> with & entity" in str(
|
||
page.select_one("textarea")
|
||
)
|
||
assert page.select_one("textarea")["data-module"] == "enhanced-textbox"
|
||
assert page.select_one("textarea")["data-highlight-placeholders"] == "true"
|
||
assert "priority" not in str(page.select_one("main"))
|
||
|
||
assert (
|
||
(page.select_one("[data-module=update-status]")["data-target"])
|
||
== (page.select_one("textarea")["id"])
|
||
== ("template_content")
|
||
)
|
||
|
||
assert (
|
||
page.select_one("[data-module=update-status]")["data-updates-url"]
|
||
) == url_for(
|
||
".count_content_length",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_type="sms",
|
||
)
|
||
|
||
assert (page.select_one("[data-module=update-status]")["aria-live"]) == ("polite")
|
||
|
||
mock_get_service_template.assert_called_with(SERVICE_ONE_ID, template_id, None)
|
||
|
||
|
||
def test_caseworker_redirected_to_set_sender_for_one_off(
|
||
client_request,
|
||
mock_get_service_templates,
|
||
mock_get_service_template,
|
||
mocker,
|
||
fake_uuid,
|
||
active_caseworking_user,
|
||
):
|
||
client_request.login(active_caseworking_user)
|
||
|
||
client_request.get(
|
||
"main.view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_expected_status=302,
|
||
_expected_redirect=url_for(
|
||
"main.set_sender",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
),
|
||
)
|
||
|
||
|
||
@freeze_time("2020-01-01 20:00")
|
||
def test_caseworker_sees_template_page_if_template_is_deleted(
|
||
client_request,
|
||
mock_get_deleted_template,
|
||
fake_uuid,
|
||
mocker,
|
||
active_caseworking_user,
|
||
):
|
||
mocker.patch("app.user_api_client.get_user", return_value=active_caseworking_user)
|
||
|
||
template_id = fake_uuid
|
||
page = client_request.get(
|
||
".view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=template_id,
|
||
_test_page_title=False,
|
||
)
|
||
|
||
content = str(page)
|
||
assert (
|
||
url_for("main.send_one_off", service_id=SERVICE_ONE_ID, template_id=fake_uuid)
|
||
not in content
|
||
)
|
||
assert (
|
||
page.select("p.hint")[0].text.strip()
|
||
== "This template was deleted today at 15:00 America/New_York."
|
||
)
|
||
|
||
mock_get_deleted_template.assert_called_with(SERVICE_ONE_ID, template_id, None)
|
||
|
||
|
||
def test_user_with_only_send_and_view_redirected_to_set_sender_for_one_off(
|
||
client_request,
|
||
mock_get_service_templates,
|
||
mock_get_service_template,
|
||
active_user_with_permissions,
|
||
mocker,
|
||
fake_uuid,
|
||
):
|
||
active_user_with_permissions["permissions"][SERVICE_ONE_ID] = [
|
||
"send_messages",
|
||
"view_activity",
|
||
]
|
||
client_request.login(active_user_with_permissions)
|
||
client_request.get(
|
||
"main.view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_expected_status=302,
|
||
_expected_redirect=url_for(
|
||
"main.set_sender",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
),
|
||
)
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
("permissions", "links_to_be_shown", "permissions_warning_to_be_shown"),
|
||
[
|
||
(
|
||
["view_activity"],
|
||
[],
|
||
"If you need to send this text message or edit this template, contact your manager.",
|
||
),
|
||
(
|
||
["manage_api_keys"],
|
||
[],
|
||
None,
|
||
),
|
||
(
|
||
["manage_templates"],
|
||
[
|
||
(".edit_service_template", "Edit this template"),
|
||
],
|
||
None,
|
||
),
|
||
(
|
||
["send_messages", "manage_templates"],
|
||
[
|
||
(".set_sender", "Use this template"),
|
||
(".edit_service_template", "Edit this template"),
|
||
],
|
||
None,
|
||
),
|
||
],
|
||
)
|
||
def test_should_be_able_to_view_a_template_with_links(
|
||
client_request,
|
||
mock_get_service_template,
|
||
mock_get_template_folders,
|
||
active_user_with_permissions,
|
||
fake_uuid,
|
||
permissions,
|
||
links_to_be_shown,
|
||
permissions_warning_to_be_shown,
|
||
):
|
||
active_user_with_permissions["permissions"][SERVICE_ONE_ID] = permissions + [
|
||
"view_activity"
|
||
]
|
||
client_request.login(active_user_with_permissions)
|
||
|
||
page = client_request.get(
|
||
".view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_test_page_title=False,
|
||
)
|
||
|
||
assert normalize_spaces(page.select_one("h1").text) == ("Confirm your template")
|
||
assert normalize_spaces(page.select_one("title").text) == (
|
||
"Confirm your template – service one – Notify.gov"
|
||
)
|
||
|
||
assert [
|
||
(link["href"], normalize_spaces(link.text))
|
||
for link in page.select(".usa-pill-separate-item")
|
||
] == [
|
||
(
|
||
url_for(
|
||
endpoint,
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
),
|
||
text,
|
||
)
|
||
for endpoint, text in links_to_be_shown
|
||
]
|
||
|
||
assert normalize_spaces(page.select_one("main p").text) == (
|
||
"To: phone number" or permissions_warning_to_be_shown
|
||
)
|
||
|
||
|
||
@pytest.mark.skip(
|
||
reason="Hiding the copy-to-clipboard widget until API access is opened up"
|
||
)
|
||
def test_should_show_template_id_on_template_page(
|
||
client_request,
|
||
mock_get_service_template,
|
||
mock_get_template_folders,
|
||
fake_uuid,
|
||
):
|
||
page = client_request.get(
|
||
".view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_test_page_title=False,
|
||
)
|
||
assert fake_uuid in page.select(".copy-to-clipboard__value")[0].text
|
||
|
||
|
||
def test_should_show_sms_template_with_downgraded_unicode_characters(
|
||
client_request,
|
||
mocker,
|
||
service_one,
|
||
mock_get_template_folders,
|
||
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
|
||
)
|
||
},
|
||
)
|
||
|
||
page = client_request.get(
|
||
".view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_test_page_title=False,
|
||
)
|
||
|
||
assert rendered_msg in page.text
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"prefix_sms", [True, pytest.param(False, marks=pytest.mark.xfail())]
|
||
)
|
||
def test_should_show_message_with_prefix_hint_if_enabled_for_service(
|
||
client_request,
|
||
mocker,
|
||
mock_get_service_template,
|
||
mock_get_users_by_service,
|
||
service_one,
|
||
fake_uuid,
|
||
prefix_sms,
|
||
):
|
||
service_one["prefix_sms"] = prefix_sms
|
||
|
||
page = client_request.get(
|
||
".edit_service_template",
|
||
service_id=service_one["id"],
|
||
template_id=fake_uuid,
|
||
)
|
||
|
||
assert "Your service name will be added to the start of your message" in page.text
|
||
|
||
|
||
def test_should_show_page_template_with_priority_select_if_platform_admin(
|
||
client_request,
|
||
platform_admin_user,
|
||
mocker,
|
||
mock_get_service_template,
|
||
service_one,
|
||
fake_uuid,
|
||
):
|
||
mocker.patch(
|
||
"app.user_api_client.get_users_for_service", return_value=[platform_admin_user]
|
||
)
|
||
template_id = fake_uuid
|
||
client_request.login(platform_admin_user)
|
||
page = client_request.get(
|
||
".edit_service_template",
|
||
service_id=service_one["id"],
|
||
template_id=template_id,
|
||
)
|
||
|
||
assert page.select_one("input[name=name]")["value"] == "Two week reminder"
|
||
assert "Template <em>content</em> with & entity" in str(
|
||
page.select_one("textarea")
|
||
)
|
||
assert "Use priority queue?" not in page.text
|
||
mock_get_service_template.assert_called_with(service_one["id"], template_id, None)
|
||
|
||
|
||
def test_choosing_to_copy_redirects(
|
||
client_request,
|
||
service_one,
|
||
mock_get_service_templates,
|
||
mock_get_template_folders,
|
||
):
|
||
client_request.post(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
_data={
|
||
"operation": "add-new-template",
|
||
"add_template_by_template_type": "copy-existing",
|
||
},
|
||
_expected_status=302,
|
||
_expected_redirect=url_for(
|
||
"main.choose_template_to_copy",
|
||
service_id=SERVICE_ONE_ID,
|
||
),
|
||
)
|
||
|
||
|
||
def test_choose_a_template_to_copy(
|
||
client_request,
|
||
mock_get_service_templates,
|
||
mock_get_template_folders,
|
||
mock_get_no_api_keys,
|
||
mock_get_just_services_for_user,
|
||
):
|
||
page = client_request.get(
|
||
"main.choose_template_to_copy",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
|
||
assert page.select(".folder-heading") == []
|
||
|
||
expected = [
|
||
(""),
|
||
("Service 1 sms_template_one"),
|
||
("Service 1 sms_template_two"),
|
||
("Service 1 email_template_one"),
|
||
("Service 1 email_template_two"),
|
||
(""),
|
||
("Service 2 sms_template_one"),
|
||
("Service 2 sms_template_two"),
|
||
("Service 2 email_template_one"),
|
||
("Service 2 email_template_two"),
|
||
]
|
||
actual = page.select(".template-list-item")
|
||
|
||
assert len(actual) == len(expected)
|
||
|
||
zipobject = zip(actual, expected)
|
||
for actual, expected in zipobject:
|
||
assert normalize_spaces(actual.text) == expected
|
||
links = page.select("main nav a")
|
||
assert links[0]["href"] == url_for(
|
||
"main.choose_template_to_copy",
|
||
service_id=SERVICE_ONE_ID,
|
||
from_service=SERVICE_TWO_ID,
|
||
)
|
||
|
||
|
||
def test_choose_a_template_to_copy_when_user_has_one_service(
|
||
client_request,
|
||
mock_get_service_templates,
|
||
mock_get_template_folders,
|
||
mock_get_no_api_keys,
|
||
mock_get_empty_organizations_and_one_service_for_user,
|
||
):
|
||
page = client_request.get(
|
||
"main.choose_template_to_copy",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
|
||
assert page.select(".folder-heading") == []
|
||
|
||
expected = [
|
||
("sms_template_one"),
|
||
("sms_template_two"),
|
||
("email_template_one"),
|
||
("email_template_two"),
|
||
]
|
||
actual = page.select(".template-list-item")
|
||
|
||
assert len(actual) == len(expected)
|
||
|
||
zipobject = zip(actual, expected)
|
||
for actual, expected in zipobject:
|
||
assert normalize_spaces(actual.text) == expected
|
||
|
||
assert page.select("main nav a")[0]["href"] == url_for(
|
||
"main.copy_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=TEMPLATE_ONE_ID,
|
||
from_service=SERVICE_TWO_ID,
|
||
)
|
||
|
||
|
||
def test_choose_a_template_to_copy_from_folder_within_service(
|
||
mocker,
|
||
client_request,
|
||
mock_get_template_folders,
|
||
mock_get_non_empty_organizations_and_services_for_user,
|
||
mock_get_no_api_keys,
|
||
):
|
||
mock_get_template_folders.return_value = [
|
||
_folder("Parent folder", PARENT_FOLDER_ID),
|
||
_folder("", CHILD_FOLDER_ID, parent=PARENT_FOLDER_ID),
|
||
_folder("Child folder non-empty", FOLDER_TWO_ID, parent=PARENT_FOLDER_ID),
|
||
]
|
||
mocker.patch(
|
||
"app.service_api_client.get_service_templates",
|
||
return_value={
|
||
"data": [
|
||
_template(
|
||
"sms",
|
||
"Should not appear in list (at service root)",
|
||
),
|
||
_template(
|
||
"sms",
|
||
"Should appear in list (at same level)",
|
||
parent=PARENT_FOLDER_ID,
|
||
),
|
||
_template(
|
||
"sms",
|
||
"Should appear in list (nested)",
|
||
parent=FOLDER_TWO_ID,
|
||
template_id=TEMPLATE_ONE_ID,
|
||
),
|
||
]
|
||
},
|
||
)
|
||
page = client_request.get(
|
||
"main.choose_template_to_copy",
|
||
service_id=SERVICE_ONE_ID,
|
||
from_service=SERVICE_ONE_ID,
|
||
from_folder=PARENT_FOLDER_ID,
|
||
)
|
||
|
||
assert normalize_spaces(page.select_one(".folder-heading").text) == (
|
||
"service one Parent folder"
|
||
)
|
||
breadcrumb_links = page.select(".folder-heading a")
|
||
assert len(breadcrumb_links) == 1
|
||
assert breadcrumb_links[0]["href"] == url_for(
|
||
"main.choose_template_to_copy",
|
||
service_id=SERVICE_ONE_ID,
|
||
from_service=SERVICE_ONE_ID,
|
||
)
|
||
|
||
expected = [
|
||
(""),
|
||
(""),
|
||
("Child folder non-empty Should appear in list (nested)"),
|
||
("Should appear in list (at same level)"),
|
||
]
|
||
actual = page.select(".template-list-item")
|
||
|
||
assert len(actual) == len(expected)
|
||
|
||
zipobject = zip(actual, expected)
|
||
for actual, expected in zipobject:
|
||
assert normalize_spaces(actual.text) == expected
|
||
|
||
links = page.select("main nav a")
|
||
assert links[0]["href"] == url_for(
|
||
"main.choose_template_to_copy",
|
||
service_id=SERVICE_ONE_ID,
|
||
from_folder=FOLDER_TWO_ID,
|
||
)
|
||
# assert links[1]["href"] == url_for(
|
||
# "main.choose_template_to_copy",
|
||
# service_id=SERVICE_ONE_ID,
|
||
# from_service=SERVICE_ONE_ID,
|
||
# from_folder=PARENT_FOLDER_ID,
|
||
# )
|
||
# assert links[2]["href"] == url_for(
|
||
# "main.choose_template_to_copy",
|
||
# service_id=SERVICE_ONE_ID,
|
||
# from_folder=FOLDER_TWO_ID,
|
||
# )
|
||
# assert links[3]["href"] == url_for(
|
||
# "main.copy_template",
|
||
# service_id=SERVICE_ONE_ID,
|
||
# template_id=TEMPLATE_ONE_ID,
|
||
# from_service=SERVICE_ONE_ID,
|
||
# )
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
("existing_template_names", "expected_name"),
|
||
[
|
||
(["Two week reminder"], "Two week reminder (copy)"),
|
||
(["Two week reminder (copy)"], "Two week reminder (copy 2)"),
|
||
(
|
||
["Two week reminder", "Two week reminder (copy)"],
|
||
"Two week reminder (copy 2)",
|
||
),
|
||
(
|
||
["Two week reminder (copy 8)", "Two week reminder (copy 9)"],
|
||
"Two week reminder (copy 10)",
|
||
),
|
||
(
|
||
["Two week reminder (copy)", "Two week reminder (copy 9)"],
|
||
"Two week reminder (copy 10)",
|
||
),
|
||
(
|
||
["Two week reminder (copy)", "Two week reminder (copy 10)"],
|
||
"Two week reminder (copy 2)",
|
||
),
|
||
],
|
||
)
|
||
def test_load_edit_template_with_copy_of_template(
|
||
client_request,
|
||
active_user_with_permission_to_two_services,
|
||
mock_get_service_templates,
|
||
mock_get_service_email_template,
|
||
mock_get_non_empty_organizations_and_services_for_user,
|
||
existing_template_names,
|
||
expected_name,
|
||
):
|
||
mock_get_service_templates.side_effect = lambda service_id: {
|
||
"data": [
|
||
{"name": existing_template_name, "template_type": "sms"}
|
||
for existing_template_name in existing_template_names
|
||
]
|
||
}
|
||
client_request.login(active_user_with_permission_to_two_services)
|
||
page = client_request.get(
|
||
"main.copy_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=TEMPLATE_ONE_ID,
|
||
from_service=SERVICE_TWO_ID,
|
||
)
|
||
|
||
assert page.select_one("form")["method"] == "post"
|
||
|
||
assert page.select_one("input")["value"] == (expected_name)
|
||
assert page.select_one("textarea").text.strip() == ("Your ((thing)) is due soon")
|
||
mock_get_service_email_template.assert_called_once_with(
|
||
SERVICE_TWO_ID,
|
||
TEMPLATE_ONE_ID,
|
||
)
|
||
|
||
|
||
def test_copy_template_loads_template_from_within_subfolder(
|
||
client_request,
|
||
active_user_with_permission_to_two_services,
|
||
mock_get_service_templates,
|
||
mock_get_non_empty_organizations_and_services_for_user,
|
||
mocker,
|
||
):
|
||
template = template_json(
|
||
SERVICE_TWO_ID, TEMPLATE_ONE_ID, name="foo", folder=PARENT_FOLDER_ID
|
||
)
|
||
|
||
mock_get_service_template = mocker.patch(
|
||
"app.service_api_client.get_service_template", return_value={"data": template}
|
||
)
|
||
mock_get_template_folder = mocker.patch(
|
||
"app.template_folder_api_client.get_template_folder",
|
||
return_value=_folder("Parent folder", PARENT_FOLDER_ID),
|
||
)
|
||
client_request.login(active_user_with_permission_to_two_services)
|
||
|
||
page = client_request.get(
|
||
"main.copy_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=TEMPLATE_ONE_ID,
|
||
from_service=SERVICE_TWO_ID,
|
||
)
|
||
|
||
assert page.select_one("input")["value"] == "foo (copy)"
|
||
mock_get_service_template.assert_called_once_with(SERVICE_TWO_ID, TEMPLATE_ONE_ID)
|
||
mock_get_template_folder.assert_called_once_with(SERVICE_TWO_ID, PARENT_FOLDER_ID)
|
||
|
||
|
||
def test_cant_copy_template_from_non_member_service(
|
||
client_request,
|
||
mock_get_service_email_template,
|
||
mock_get_organizations_and_services_for_user,
|
||
):
|
||
client_request.get(
|
||
"main.copy_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=TEMPLATE_ONE_ID,
|
||
from_service=SERVICE_TWO_ID,
|
||
_expected_status=403,
|
||
)
|
||
assert mock_get_service_email_template.call_args_list == []
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
("service_permissions", "data", "expected_error"),
|
||
[
|
||
(
|
||
["email"],
|
||
{
|
||
"operation": "add-new-template",
|
||
"add_template_by_template_type": "sms",
|
||
},
|
||
"Sending text messages has been disabled for your service.",
|
||
),
|
||
],
|
||
)
|
||
def test_should_not_allow_creation_of_template_through_form_without_correct_permission(
|
||
client_request,
|
||
service_one,
|
||
mock_get_service_templates,
|
||
mock_get_template_folders,
|
||
service_permissions,
|
||
data,
|
||
expected_error,
|
||
fake_uuid,
|
||
):
|
||
service_one["permissions"] = service_permissions
|
||
page = client_request.post(
|
||
"main.choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
_data=data,
|
||
_follow_redirects=True,
|
||
_expected_status=403,
|
||
)
|
||
assert normalize_spaces(page.select("main p")[0].text) == expected_error
|
||
assert page.select(".usa-back-link")[0].text == "Back"
|
||
assert page.select(".usa-back-link")[0]["href"] == url_for(
|
||
".choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
)
|
||
|
||
|
||
@pytest.mark.parametrize("method", ["get", "post"])
|
||
@pytest.mark.parametrize(
|
||
("type_of_template", "expected_error"),
|
||
[
|
||
("email", "Sending emails has been disabled for your service."),
|
||
("sms", "Sending text messages has been disabled for your service."),
|
||
],
|
||
)
|
||
def test_should_not_allow_creation_of_a_template_without_correct_permission(
|
||
client_request,
|
||
service_one,
|
||
mocker,
|
||
method,
|
||
type_of_template,
|
||
expected_error,
|
||
):
|
||
service_one["permissions"] = []
|
||
|
||
page = getattr(client_request, method)(
|
||
".add_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_type=type_of_template,
|
||
_follow_redirects=True,
|
||
_expected_status=403,
|
||
)
|
||
assert page.select("main p")[0].text.strip() == expected_error
|
||
assert page.select(".usa-back-link")[0].text == "Back"
|
||
assert page.select(".usa-back-link")[0]["href"] == url_for(
|
||
".choose_template",
|
||
service_id=service_one["id"],
|
||
)
|
||
|
||
|
||
def test_should_redirect_when_saving_a_template(
|
||
client_request,
|
||
mock_get_service_template,
|
||
mock_get_api_keys,
|
||
mock_update_service_template,
|
||
fake_uuid,
|
||
):
|
||
name = "new name"
|
||
content = "template <em>content</em> with & entity"
|
||
client_request.post(
|
||
".edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_data={
|
||
"id": fake_uuid,
|
||
"name": name,
|
||
"template_content": content,
|
||
"template_type": "sms",
|
||
"service": SERVICE_ONE_ID,
|
||
},
|
||
_expected_status=302,
|
||
_expected_redirect=url_for(
|
||
".view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
),
|
||
)
|
||
mock_update_service_template.assert_called_with(
|
||
fake_uuid, name, "sms", content, SERVICE_ONE_ID, None
|
||
)
|
||
|
||
|
||
def test_should_edit_content_when_process_type_is_priority_not_platform_admin(
|
||
client_request,
|
||
mock_get_service_template_with_priority,
|
||
mock_update_service_template,
|
||
fake_uuid,
|
||
):
|
||
client_request.post(
|
||
".edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_data={
|
||
"id": fake_uuid,
|
||
"name": "new name",
|
||
"template_content": "new template <em>content</em> with & entity",
|
||
"template_type": "sms",
|
||
"service": SERVICE_ONE_ID,
|
||
},
|
||
_expected_status=302,
|
||
_expected_redirect=url_for(
|
||
".view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
),
|
||
)
|
||
mock_update_service_template.assert_called_with(
|
||
fake_uuid,
|
||
"new name",
|
||
"sms",
|
||
"new template <em>content</em> with & entity",
|
||
SERVICE_ONE_ID,
|
||
None,
|
||
)
|
||
|
||
|
||
def test_should_not_allow_template_edits_without_correct_permission(
|
||
client_request,
|
||
mock_get_service_template,
|
||
service_one,
|
||
fake_uuid,
|
||
):
|
||
service_one["permissions"] = ["email"]
|
||
|
||
page = client_request.get(
|
||
".edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_follow_redirects=True,
|
||
_expected_status=403,
|
||
)
|
||
|
||
assert (
|
||
page.select("main p")[0].text.strip()
|
||
== "Sending text messages has been disabled for your service."
|
||
)
|
||
assert page.select(".usa-back-link")[0].text == "Back"
|
||
assert page.select(".usa-back-link")[0]["href"] == url_for(
|
||
".view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
)
|
||
|
||
|
||
def test_should_403_when_edit_template_with_process_type_of_priority_for_non_platform_admin(
|
||
client_request,
|
||
active_user_with_permissions,
|
||
mocker,
|
||
mock_get_service_template,
|
||
mock_update_service_template,
|
||
fake_uuid,
|
||
service_one,
|
||
):
|
||
service_one["users"] = [active_user_with_permissions]
|
||
client_request.login(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": "template <em>content</em> with & entity",
|
||
"template_type": "sms",
|
||
"service": service_one["id"],
|
||
"process_type": "priority",
|
||
}
|
||
client_request.post(
|
||
".edit_service_template",
|
||
service_id=service_one["id"],
|
||
template_id=template_id,
|
||
_data=data,
|
||
_expected_status=403,
|
||
)
|
||
assert mock_update_service_template.called is False
|
||
|
||
|
||
def test_should_403_when_create_template_with_process_type_of_priority_for_non_platform_admin(
|
||
client_request,
|
||
active_user_with_permissions,
|
||
mocker,
|
||
mock_get_service_template,
|
||
mock_update_service_template,
|
||
fake_uuid,
|
||
service_one,
|
||
):
|
||
service_one["users"] = [active_user_with_permissions]
|
||
client_request.login(active_user_with_permissions, service_one)
|
||
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 <em>content</em> with & entity",
|
||
"template_type": "sms",
|
||
"service": service_one["id"],
|
||
"process_type": "priority",
|
||
}
|
||
client_request.post(
|
||
".add_service_template",
|
||
service_id=service_one["id"],
|
||
template_type="sms",
|
||
_data=data,
|
||
_expected_status=403,
|
||
)
|
||
assert mock_update_service_template.called is False
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
("old_content", "new_content", "expected_paragraphs"),
|
||
[
|
||
(
|
||
"my favorite color is blue",
|
||
"my favorite color is ((color))",
|
||
[
|
||
"You added ((color))",
|
||
"Before you send any messages, make sure your API calls include color.",
|
||
],
|
||
),
|
||
(
|
||
"hello ((name))",
|
||
"hello ((first name)) ((middle name)) ((last name))",
|
||
[
|
||
"You removed ((name))",
|
||
"You added ((first name)) ((middle name)) and ((last name))",
|
||
"Before you send any messages, make sure your API calls include first name, middle name and last name.",
|
||
],
|
||
),
|
||
],
|
||
)
|
||
def test_should_show_interstitial_when_making_breaking_change(
|
||
client_request,
|
||
mock_update_service_template,
|
||
mock_get_user_by_email,
|
||
mock_get_api_keys,
|
||
fake_uuid,
|
||
mocker,
|
||
new_content,
|
||
old_content,
|
||
expected_paragraphs,
|
||
):
|
||
email_template = create_template(
|
||
template_id=fake_uuid,
|
||
template_type="email",
|
||
subject="Your ((thing)) is due soon",
|
||
content=old_content,
|
||
)
|
||
mocker.patch(
|
||
"app.service_api_client.get_service_template",
|
||
return_value={"data": email_template},
|
||
)
|
||
|
||
data = {
|
||
"id": fake_uuid,
|
||
"name": "new name",
|
||
"template_content": new_content,
|
||
"template_type": "email",
|
||
"subject": "reminder '\" <span> & ((thing))",
|
||
"service": SERVICE_ONE_ID,
|
||
"process_type": "normal",
|
||
}
|
||
|
||
page = client_request.post(
|
||
".edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_data=data,
|
||
_expected_status=200,
|
||
)
|
||
|
||
assert page.h1.string.strip() == "Confirm changes"
|
||
assert page.find("a", {"class": "usa-back-link"})["href"] == url_for(
|
||
".edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
)
|
||
assert [
|
||
normalize_spaces(paragraph.text) for paragraph in page.select("main p")
|
||
] == expected_paragraphs
|
||
|
||
for key, value in {
|
||
"name": "new name",
|
||
"subject": "reminder '\" <span> & ((thing))",
|
||
"template_content": new_content,
|
||
"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"})) == (
|
||
"""<input name="subject" type="hidden" value="reminder '" <span> & ((thing))"/>"""
|
||
)
|
||
|
||
|
||
def test_removing_placeholders_is_not_a_breaking_change(
|
||
client_request,
|
||
mock_get_service_email_template,
|
||
mock_update_service_template,
|
||
fake_uuid,
|
||
):
|
||
existing_template = mock_get_service_email_template(0, 0)["data"]
|
||
client_request.post(
|
||
".edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_data={
|
||
"name": existing_template["name"],
|
||
"template_content": "no placeholders",
|
||
"subject": existing_template["subject"],
|
||
},
|
||
_expected_status=302,
|
||
_expected_redirect=url_for(
|
||
"main.view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
),
|
||
)
|
||
assert mock_update_service_template.called is True
|
||
|
||
|
||
def test_should_not_create_too_big_template(
|
||
client_request,
|
||
mock_get_service_template,
|
||
mock_create_service_template_content_too_big,
|
||
fake_uuid,
|
||
):
|
||
page = client_request.post(
|
||
".add_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_type="sms",
|
||
_data={
|
||
"name": "new name",
|
||
"template_content": "template content",
|
||
"template_type": "sms",
|
||
"service": SERVICE_ONE_ID,
|
||
"process_type": "normal",
|
||
},
|
||
_expected_status=200,
|
||
)
|
||
assert "Content has a character count greater than the limit of 459" in page.text
|
||
|
||
|
||
def test_should_not_update_too_big_template(
|
||
client_request,
|
||
mock_get_service_template,
|
||
mock_update_service_template_400_content_too_big,
|
||
fake_uuid,
|
||
):
|
||
page = client_request.post(
|
||
".edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
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",
|
||
},
|
||
_expected_status=200,
|
||
)
|
||
assert "Content has a character count greater than the limit of 459" in page.text
|
||
|
||
|
||
def test_should_redirect_when_saving_a_template_email(
|
||
client_request,
|
||
mock_get_service_email_template,
|
||
mock_update_service_template,
|
||
mock_get_user_by_email,
|
||
fake_uuid,
|
||
):
|
||
name = "new name"
|
||
content = "template <em>content</em> with & entity ((thing)) ((date))"
|
||
subject = "subject & entity"
|
||
client_request.post(
|
||
".edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_data={
|
||
"id": fake_uuid,
|
||
"name": name,
|
||
"template_content": content,
|
||
"template_type": "email",
|
||
"service": SERVICE_ONE_ID,
|
||
"subject": subject,
|
||
},
|
||
_expected_status=302,
|
||
_expected_redirect=url_for(
|
||
".view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
),
|
||
)
|
||
mock_update_service_template.assert_called_with(
|
||
fake_uuid, name, "email", content, SERVICE_ONE_ID, subject
|
||
)
|
||
|
||
|
||
def test_should_show_delete_template_page_with_time_block(
|
||
client_request,
|
||
mock_get_service_template,
|
||
mock_get_template_folders,
|
||
mocker,
|
||
fake_uuid,
|
||
):
|
||
mocker.patch(
|
||
"app.template_statistics_client.get_last_used_date_for_template",
|
||
return_value="2012-01-01 12:00:00",
|
||
)
|
||
|
||
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 (
|
||
"Are you sure you want to delete ‘Two week reminder’?"
|
||
in page.select(".banner-dangerous")[0].text
|
||
)
|
||
assert normalize_spaces(page.select(".banner-dangerous p")[0].text) == (
|
||
"This template was last used 10 minutes ago."
|
||
)
|
||
assert normalize_spaces(page.select(".sms-message-wrapper")[0].text) == (
|
||
"service one: Template <em>content</em> with & entity"
|
||
)
|
||
mock_get_service_template.assert_called_with(SERVICE_ONE_ID, fake_uuid, None)
|
||
|
||
|
||
def test_should_show_delete_template_page_with_time_block_for_empty_notification(
|
||
client_request,
|
||
mock_get_service_template,
|
||
mock_get_template_folders,
|
||
mocker,
|
||
fake_uuid,
|
||
):
|
||
mocker.patch(
|
||
"app.template_statistics_client.get_last_used_date_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 (
|
||
"Are you sure you want to delete ‘Two week reminder’?"
|
||
in page.select(".banner-dangerous")[0].text
|
||
)
|
||
assert normalize_spaces(page.select(".banner-dangerous p")[0].text) == (
|
||
"This template has never been used."
|
||
)
|
||
assert normalize_spaces(page.select(".sms-message-wrapper")[0].text) == (
|
||
"service one: Template <em>content</em> with & entity"
|
||
)
|
||
mock_get_service_template.assert_called_with(SERVICE_ONE_ID, fake_uuid, None)
|
||
|
||
|
||
def test_should_show_delete_template_page_with_never_used_block(
|
||
client_request,
|
||
mock_get_service_template,
|
||
mock_get_template_folders,
|
||
fake_uuid,
|
||
mocker,
|
||
):
|
||
mocker.patch(
|
||
"app.template_statistics_client.get_last_used_date_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 (
|
||
"Are you sure you want to delete ‘Two week reminder’?"
|
||
in page.select(".banner-dangerous")[0].text
|
||
)
|
||
assert not page.select(".banner-dangerous p")
|
||
assert normalize_spaces(page.select(".sms-message-wrapper")[0].text) == (
|
||
"service one: Template <em>content</em> with & entity"
|
||
)
|
||
mock_get_service_template.assert_called_with(SERVICE_ONE_ID, fake_uuid, None)
|
||
|
||
|
||
@pytest.mark.parametrize("parent", [PARENT_FOLDER_ID, None])
|
||
def test_should_redirect_when_deleting_a_template(
|
||
mocker,
|
||
client_request,
|
||
mock_delete_service_template,
|
||
mock_get_template_folders,
|
||
parent,
|
||
):
|
||
mock_get_template_folders.return_value = [
|
||
{
|
||
"id": PARENT_FOLDER_ID,
|
||
"name": "Folder",
|
||
"parent": None,
|
||
"users_with_permission": [ANY],
|
||
}
|
||
]
|
||
mock_get_service_template = mocker.patch(
|
||
"app.service_api_client.get_service_template",
|
||
return_value={
|
||
"data": _template(
|
||
"sms",
|
||
"Hello",
|
||
parent=parent,
|
||
)
|
||
},
|
||
)
|
||
|
||
client_request.post(
|
||
".delete_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=TEMPLATE_ONE_ID,
|
||
_expected_status=302,
|
||
_expected_redirect=url_for(
|
||
".choose_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_folder_id=parent,
|
||
),
|
||
)
|
||
|
||
mock_get_service_template.assert_called_with(SERVICE_ONE_ID, TEMPLATE_ONE_ID, None)
|
||
mock_delete_service_template.assert_called_with(SERVICE_ONE_ID, TEMPLATE_ONE_ID)
|
||
|
||
|
||
@freeze_time("2016-01-01T20:00")
|
||
def test_should_show_page_for_a_deleted_template(
|
||
client_request,
|
||
mock_get_template_folders,
|
||
mock_get_deleted_template,
|
||
mock_get_user,
|
||
mock_get_user_by_email,
|
||
mock_has_permissions,
|
||
fake_uuid,
|
||
):
|
||
template_id = fake_uuid
|
||
page = client_request.get(
|
||
".view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=template_id,
|
||
_test_page_title=False,
|
||
)
|
||
|
||
content = str(page)
|
||
assert (
|
||
url_for(
|
||
"main.edit_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
)
|
||
not in content
|
||
)
|
||
assert (
|
||
url_for("main.send_one_off", service_id=SERVICE_ONE_ID, template_id=fake_uuid)
|
||
not in content
|
||
)
|
||
assert (
|
||
page.select("p.hint")[0].text.strip()
|
||
== "This template was deleted today at 15:00 America/New_York."
|
||
)
|
||
assert "Delete this template" not in page.select_one("main").text
|
||
|
||
mock_get_deleted_template.assert_called_with(SERVICE_ONE_ID, template_id, None)
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"route",
|
||
[
|
||
"main.add_service_template",
|
||
"main.edit_service_template",
|
||
"main.delete_service_template",
|
||
],
|
||
)
|
||
def test_route_permissions(
|
||
route,
|
||
mocker,
|
||
notify_admin,
|
||
client_request,
|
||
api_user_active,
|
||
service_one,
|
||
mock_get_service_template,
|
||
mock_get_template_folders,
|
||
fake_uuid,
|
||
):
|
||
mocker.patch(
|
||
"app.template_statistics_client.get_last_used_date_for_template",
|
||
return_value="2012-01-01 12:00:00",
|
||
)
|
||
validate_route_permission(
|
||
mocker,
|
||
notify_admin,
|
||
"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,
|
||
notify_admin,
|
||
client_request,
|
||
api_user_active,
|
||
mock_get_template_folders,
|
||
service_one,
|
||
mock_get_service_templates,
|
||
mock_get_no_api_keys,
|
||
):
|
||
mocker.patch("app.job_api_client.get_job")
|
||
validate_route_permission(
|
||
mocker,
|
||
notify_admin,
|
||
"GET",
|
||
200,
|
||
url_for(
|
||
"main.choose_template",
|
||
service_id=service_one["id"],
|
||
),
|
||
[],
|
||
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,
|
||
notify_admin,
|
||
client_request,
|
||
api_user_active,
|
||
service_one,
|
||
mock_get_service_template,
|
||
fake_uuid,
|
||
):
|
||
validate_route_permission(
|
||
mocker,
|
||
notify_admin,
|
||
"GET",
|
||
403,
|
||
url_for(
|
||
route,
|
||
service_id=service_one["id"],
|
||
template_type="sms",
|
||
template_id=fake_uuid,
|
||
),
|
||
["view_activity"],
|
||
api_user_active,
|
||
service_one,
|
||
)
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
("template_type", "expected"),
|
||
[
|
||
("email", "New email template"),
|
||
("sms", "New text message template"),
|
||
],
|
||
)
|
||
def test_add_template_page_title(
|
||
client_request,
|
||
service_one,
|
||
template_type,
|
||
expected,
|
||
):
|
||
service_one["permissions"] += [template_type]
|
||
page = client_request.get(
|
||
".add_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_type=template_type,
|
||
)
|
||
assert normalize_spaces(page.select_one("h1").text) == expected
|
||
|
||
|
||
# def test_can_create_email_template_with_emoji(
|
||
# client_request, mock_create_service_template
|
||
# ):
|
||
# client_request.post(
|
||
# ".add_service_template",
|
||
# service_id=SERVICE_ONE_ID,
|
||
# template_type="email",
|
||
# _data={
|
||
# "name": "new name",
|
||
# "subject": "Food incoming!",
|
||
# "template_content": "here's a burrito 🌯",
|
||
# "template_type": "email",
|
||
# "service": SERVICE_ONE_ID,
|
||
# "process_type": "normal",
|
||
# },
|
||
# _expected_status=302,
|
||
# )
|
||
# assert mock_create_service_template.called is True
|
||
|
||
|
||
# @pytest.mark.parametrize(
|
||
# ("template_type", "expected_error"),
|
||
# [
|
||
# (
|
||
# "sms",
|
||
# (
|
||
# "Please remove the unaccepted character 🍜 in your message, then save again"
|
||
# ),
|
||
# ),
|
||
# ],
|
||
# )
|
||
# def test_should_not_create_sms_template_with_emoji(
|
||
# client_request,
|
||
# service_one,
|
||
# mock_create_service_template,
|
||
# template_type,
|
||
# expected_error,
|
||
# ):
|
||
# service_one["permissions"] += [template_type]
|
||
# page = client_request.post(
|
||
# ".add_service_template",
|
||
# service_id=SERVICE_ONE_ID,
|
||
# template_type=template_type,
|
||
# _data={
|
||
# "name": "new name",
|
||
# "template_content": "here are some noodles 🍜",
|
||
# "template_type": "sms",
|
||
# "service": SERVICE_ONE_ID,
|
||
# "process_type": "normal",
|
||
# },
|
||
# _expected_status=200,
|
||
# )
|
||
# # print(page.main.prettify())
|
||
# assert expected_error in normalize_spaces(
|
||
# page.select_one("#template_content-error").text
|
||
# )
|
||
# assert mock_create_service_template.called is False
|
||
|
||
|
||
# @pytest.mark.parametrize(
|
||
# ("template_type", "expected_error"),
|
||
# [
|
||
# (
|
||
# "sms",
|
||
# (
|
||
# "Please remove the unaccepted character 🍔 in your message, then save again"
|
||
# ),
|
||
# ),
|
||
# ],
|
||
# )
|
||
# def test_should_not_update_sms_template_with_emoji(
|
||
# mocker,
|
||
# client_request,
|
||
# service_one,
|
||
# mock_get_service_template,
|
||
# mock_update_service_template,
|
||
# fake_uuid,
|
||
# template_type,
|
||
# expected_error,
|
||
# ):
|
||
# service_one["permissions"] += [template_type]
|
||
# return mocker.patch(
|
||
# "app.service_api_client.get_service_template",
|
||
# return_value=template_json(
|
||
# SERVICE_ONE_ID,
|
||
# fake_uuid,
|
||
# type_=template_type,
|
||
# ),
|
||
# )
|
||
# page = client_request.post(
|
||
# ".edit_service_template",
|
||
# service_id=SERVICE_ONE_ID,
|
||
# template_id=fake_uuid,
|
||
# _data={
|
||
# "id": fake_uuid,
|
||
# "name": "new name",
|
||
# "template_content": "here's a burger 🍔",
|
||
# "service": SERVICE_ONE_ID,
|
||
# "template_type": template_type,
|
||
# "process_type": "normal",
|
||
# },
|
||
# _expected_status=200,
|
||
# )
|
||
# assert expected_error in page.text
|
||
# assert mock_update_service_template.called is False
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"template_type",
|
||
[
|
||
"sms",
|
||
],
|
||
)
|
||
def test_should_create_sms_template_without_downgrading_unicode_characters(
|
||
client_request,
|
||
service_one,
|
||
mock_create_service_template,
|
||
template_type,
|
||
):
|
||
service_one["permissions"] += [template_type]
|
||
|
||
msg = "here:\tare some “fancy quotes” and non\u200bbreaking\u200bspaces"
|
||
|
||
client_request.post(
|
||
".add_service_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_type="sms",
|
||
_data={
|
||
"name": "new name",
|
||
"template_content": msg,
|
||
"template_type": template_type,
|
||
"service": SERVICE_ONE_ID,
|
||
},
|
||
expected_status=302,
|
||
)
|
||
|
||
mock_create_service_template.assert_called_with(
|
||
ANY, # name
|
||
ANY, # type
|
||
msg, # content
|
||
ANY, # service_id
|
||
ANY, # subject
|
||
ANY, # parent_folder_id
|
||
)
|
||
|
||
|
||
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 all personalized and conditional"
|
||
" content after sending for increased privacy protection?"
|
||
) 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_get_template_folders,
|
||
mock_redact_template,
|
||
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) == (
|
||
"Personalized 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,
|
||
mock_get_template_folders,
|
||
fake_uuid,
|
||
):
|
||
template = create_template(
|
||
template_type="email", content="hi ((name))", redact_personalisation=True
|
||
)
|
||
mocker.patch(
|
||
"app.service_api_client.get_service_template", return_value={"data": template}
|
||
)
|
||
|
||
page = client_request.get(
|
||
"main.view_template",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_test_page_title=False,
|
||
)
|
||
|
||
assert page.select(".hint")[0].text == "Personalization is hidden after sending"
|
||
|
||
|
||
def test_set_template_sender(
|
||
client_request,
|
||
fake_uuid,
|
||
mock_update_service_template_sender,
|
||
mock_get_service_template,
|
||
single_sms_sender,
|
||
):
|
||
data = {
|
||
"sender": "1234",
|
||
}
|
||
|
||
client_request.post(
|
||
"main.set_template_sender",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_id=fake_uuid,
|
||
_data=data,
|
||
)
|
||
|
||
mock_update_service_template_sender.assert_called_once_with(
|
||
SERVICE_ONE_ID,
|
||
fake_uuid,
|
||
"1234",
|
||
)
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
("template_type", "prefix_sms", "content", "expected_message", "expected_class"),
|
||
[
|
||
(
|
||
"sms",
|
||
False,
|
||
"a" * 160,
|
||
"Will be charged as 1 text message",
|
||
None,
|
||
),
|
||
(
|
||
"sms",
|
||
False,
|
||
"a" * 161,
|
||
"Will be charged as 2 text messages",
|
||
None,
|
||
),
|
||
(
|
||
"sms",
|
||
True,
|
||
"a" * 147,
|
||
"Will be charged as 1 text message",
|
||
None,
|
||
),
|
||
(
|
||
# service name takes 13 characters, 148 + 13 = 161
|
||
"sms",
|
||
True,
|
||
"a" * 148,
|
||
"Will be charged as 2 text messages",
|
||
None,
|
||
),
|
||
(
|
||
"sms",
|
||
False,
|
||
"a" * 918,
|
||
"Will be charged as 6 text messages",
|
||
None,
|
||
),
|
||
(
|
||
# Service name increases fragment count but doesn’t count
|
||
# against total character limit
|
||
"sms",
|
||
True,
|
||
"a" * 918,
|
||
"Will be charged as 7 text messages",
|
||
None,
|
||
),
|
||
(
|
||
# Can’t make a 7 fragment text template from content alone
|
||
"sms",
|
||
False,
|
||
"a" * 919,
|
||
"You have 1 character too many",
|
||
"usa-error-message",
|
||
),
|
||
(
|
||
# Service name increases content count but character count
|
||
# is based on content alone
|
||
"sms",
|
||
True,
|
||
"a" * 919,
|
||
"You have 1 character too many",
|
||
"usa-error-message",
|
||
),
|
||
(
|
||
# Service name increases content count but character count
|
||
# is based on content alone
|
||
"sms",
|
||
True,
|
||
"a" * 920,
|
||
"You have 2 characters too many",
|
||
"usa-error-message",
|
||
),
|
||
(
|
||
"sms",
|
||
False,
|
||
"Ẅ" * 70,
|
||
"Will be charged as 1 text message.", # noqa E501
|
||
None,
|
||
),
|
||
(
|
||
"sms",
|
||
False,
|
||
"Ẅ" * 71,
|
||
"Will be charged as 2 text messages",
|
||
None,
|
||
),
|
||
(
|
||
"sms",
|
||
False,
|
||
"Ẅ" * 918,
|
||
"Will be charged as 14 text messages",
|
||
None,
|
||
),
|
||
(
|
||
"sms",
|
||
False,
|
||
"Ẅ" * 919,
|
||
"You have 1 character too many",
|
||
"usa-error-message",
|
||
),
|
||
(
|
||
"sms",
|
||
False,
|
||
"Hello ((name))",
|
||
"Will be charged as 1 text message (not including personalization).",
|
||
None,
|
||
),
|
||
(
|
||
# Length of placeholder body doesn’t count towards fragment count
|
||
"sms",
|
||
False,
|
||
f'Hello (( {"a" * 999} ))',
|
||
"Will be charged as 1 text message (not including personalization).",
|
||
None,
|
||
),
|
||
],
|
||
)
|
||
def test_content_count_json_endpoint(
|
||
client_request,
|
||
service_one,
|
||
template_type,
|
||
prefix_sms,
|
||
content,
|
||
expected_message,
|
||
expected_class,
|
||
):
|
||
service_one["prefix_sms"] = prefix_sms
|
||
response = client_request.post_response(
|
||
"main.count_content_length",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_type=template_type,
|
||
_data={
|
||
"template_content": content,
|
||
},
|
||
_expected_status=200,
|
||
)
|
||
|
||
html = json.loads(response.get_data(as_text=True))["html"]
|
||
snippet = BeautifulSoup(html, "html.parser").select_one("span")
|
||
|
||
assert expected_message in normalize_spaces(snippet.text)
|
||
|
||
if snippet.has_attr("class"):
|
||
assert snippet["class"] == [expected_class]
|
||
else:
|
||
assert expected_class is None
|
||
|
||
|
||
@pytest.mark.parametrize(
|
||
"template_type",
|
||
[
|
||
"email",
|
||
"banana",
|
||
],
|
||
)
|
||
def test_content_count_json_endpoint_for_unsupported_template_types(
|
||
client_request,
|
||
template_type,
|
||
):
|
||
client_request.post(
|
||
"main.count_content_length",
|
||
service_id=SERVICE_ONE_ID,
|
||
template_type=template_type,
|
||
content="foo",
|
||
_expected_status=404,
|
||
)
|