Files
notifications-admin/tests/app/main/views/test_activity.py

724 lines
20 KiB
Python
Raw Normal View History

import json
import uuid
from functools import partial
from urllib.parse import parse_qs, urlparse
import pytest
from flask import url_for
from freezegun import freeze_time
from app.main.views.jobs import get_status_filters, get_time_left
from app.models.service import Service
from tests.conftest import (
SERVICE_ONE_ID,
create_active_caseworking_user,
create_active_user_view_permissions,
create_active_user_with_permissions,
create_notifications,
normalize_spaces,
)
@pytest.mark.parametrize(
(
"user",
"extra_args",
"expected_update_endpoint",
"expected_limit_days",
"page_title",
),
[
(
create_active_user_view_permissions(),
{"message_type": "email"},
"/email.json",
7,
"Emails",
),
(
create_active_user_view_permissions(),
{"message_type": "sms"},
"/sms.json",
7,
"Text message",
),
(
create_active_caseworking_user(),
{},
".json",
None,
"Sent messages",
),
],
)
@pytest.mark.parametrize(
("status_argument", "expected_api_call"),
[
(
"",
[
"created",
"pending",
"sending",
"delivered",
"sent",
"failed",
"temporary-failure",
"permanent-failure",
"technical-failure",
"validation-failed",
],
),
("sending", ["sending", "created", "pending"]),
("delivered", ["delivered", "sent"]),
(
"failed",
[
"failed",
"temporary-failure",
"permanent-failure",
"technical-failure",
"validation-failed",
],
),
],
)
@pytest.mark.parametrize(
("page_argument", "expected_page_argument"), [(1, 1), (22, 22), (None, 1)]
)
@pytest.mark.parametrize(
("to_argument", "expected_to_argument"),
[
("", ""),
("+12029000123", "+12029000123"),
("test@example.com", "test@example.com"),
],
)
@freeze_time("2020-01-01 06:00")
def test_can_show_notifications(
client_request,
service_one,
mock_get_notifications,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_has_no_jobs,
mock_get_no_api_keys,
user,
extra_args,
expected_update_endpoint,
expected_limit_days,
page_title,
status_argument,
expected_api_call,
page_argument,
expected_page_argument,
to_argument,
expected_to_argument,
mocker,
):
client_request.login(user)
if expected_to_argument:
page = client_request.post(
"main.view_notifications",
service_id=SERVICE_ONE_ID,
status=status_argument,
page=page_argument,
_data={"to": to_argument},
_expected_status=200,
**extra_args
)
else:
page = client_request.get(
"main.view_notifications",
service_id=SERVICE_ONE_ID,
status=status_argument,
page=page_argument,
**extra_args
)
first_row = page.select_one("tbody tr")
assert normalize_spaces(
first_row.select_one("a.file-list-filename.usa-link").text
) == (
# Comes from
# https://github.com/alphagov/notifications-admin/blob/8faffad508f9a087b0006989c197741c693cc2e2/tests/__init__.py#L436
"2021234567"
)
assert normalize_spaces(
# Were doing str() here not .text to make sure theres no extra
# HTML sneaking in
str(first_row.select_one(".file-list-hint"))
) == (
# Comes from
# https://github.com/alphagov/notifications-admin/blob/8faffad508f9a087b0006989c197741c693cc2e2/tests/__init__.py#L271
"template content"
) or (
# Comes from
# https://github.com/alphagov/notifications-admin/blob/8faffad508f9a087b0006989c197741c693cc2e2/tests/__init__.py#L273
"template subject"
)
assert normalize_spaces(
first_row.select_one(".table-field-right-aligned .align-with-message-body").text
2023-11-16 12:24:27 -08:00
) in [
"Delivered 01-01-2020 at 01:00 AM",
"Delivered 01-01-2020 at 01:00 AM",
2023-11-16 12:24:27 -08:00
]
assert page_title in page.h1.text.strip()
path_to_json = page.find("div", {"data-key": "notifications"})["data-resource"]
url = urlparse(path_to_json)
assert url.path == "/services/{}/notifications{}".format(
SERVICE_ONE_ID,
expected_update_endpoint,
)
query_dict = parse_qs(url.query)
if status_argument:
assert query_dict["status"] == [status_argument]
if expected_page_argument:
assert query_dict["page"] == [str(expected_page_argument)]
assert "to" not in query_dict
mock_get_notifications.assert_called_with(
limit_days=expected_limit_days,
page=expected_page_argument,
service_id=SERVICE_ONE_ID,
status=expected_api_call,
template_type=list(extra_args.values()),
to=expected_to_argument,
)
json_response = client_request.get_response(
"main.get_notifications_as_json",
service_id=service_one["id"],
status=status_argument,
**extra_args
)
json_content = json.loads(json_response.get_data(as_text=True))
assert json_content.keys() == {
"counts",
"notifications",
"service_data_retention_days",
}
def test_can_show_notifications_if_data_retention_not_available(
client_request,
mock_get_notifications,
mock_get_service_statistics,
mock_has_no_jobs,
mock_get_no_api_keys,
):
page = client_request.get(
"main.view_notifications",
service_id=SERVICE_ONE_ID,
status="sending,delivered,failed",
)
assert page.h1.text.strip() == "Messages"
@pytest.mark.parametrize(
("user", "query_parameters", "expected_download_link"),
[
(
create_active_user_with_permissions(),
{},
partial(
url_for,
".download_notifications_csv",
message_type=None,
2024-06-10 10:15:22 -06:00
number_of_days="seven_day",
),
),
(
create_active_user_with_permissions(),
{"status": "failed"},
2024-06-10 10:15:22 -06:00
partial(
url_for,
".download_notifications_csv",
status="failed",
number_of_days="seven_day",
),
),
(
create_active_user_with_permissions(),
{"message_type": "sms"},
partial(
url_for,
".download_notifications_csv",
message_type="sms",
2024-06-10 10:15:22 -06:00
number_of_days="seven_day",
),
),
(
create_active_user_view_permissions(),
{},
2024-06-10 10:15:22 -06:00
partial(url_for, ".download_notifications_csv", number_of_days="seven_day"),
),
(
create_active_caseworking_user(),
{},
lambda service_id: None,
),
],
)
def test_link_to_download_notifications(
client_request,
mock_get_notifications,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_has_no_jobs,
mock_get_no_api_keys,
user,
query_parameters,
expected_download_link,
):
client_request.login(user)
page = client_request.get(
"main.view_notifications", service_id=SERVICE_ONE_ID, **query_parameters
)
download_link = page.select_one("a[download=download]")
assert (download_link["href"] if download_link else None) == expected_download_link(
service_id=SERVICE_ONE_ID
)
2018-08-09 17:51:34 +01:00
def test_download_not_available_to_users_without_dashboard(
client_request,
active_caseworking_user,
):
client_request.login(active_caseworking_user)
client_request.get(
"main.download_notifications_csv",
service_id=SERVICE_ONE_ID,
_expected_status=403,
)
def test_shows_message_when_no_notifications(
client_request,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_get_notifications_with_no_notifications,
mock_get_no_api_keys,
):
page = client_request.get(
"main.view_notifications",
service_id=SERVICE_ONE_ID,
message_type="sms",
)
assert normalize_spaces(page.select("tbody tr")[0].text) == (
"No messages found (messages are kept for 7 days)"
)
@pytest.mark.parametrize(
(
"initial_query_arguments",
"form_post_data",
"expected_search_box_label",
"expected_search_box_contents",
),
[
(
{},
{},
"Search by recipient",
None,
),
(
{
"message_type": "sms",
},
{},
"Search by phone number",
None,
),
(
{
"message_type": "sms",
},
{
"to": "+33(0)5-12-34-56-78",
},
"Search by phone number",
"+33(0)5-12-34-56-78",
),
(
{
"status": "failed",
"message_type": "email",
"page": "99",
},
{
"to": "test@example.com",
},
"Search by email address",
"test@example.com",
),
],
)
def test_search_recipient_form(
client_request,
mock_get_notifications,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_get_no_api_keys,
initial_query_arguments,
form_post_data,
expected_search_box_label,
expected_search_box_contents,
):
page = client_request.post(
"main.view_notifications",
service_id=SERVICE_ONE_ID,
_data=form_post_data,
_expected_status=200,
**initial_query_arguments
)
assert page.find("form")["method"] == "post"
action_url = page.find("form")["action"]
url = urlparse(action_url)
assert url.path == "/services/{}/notifications/{}".format(
SERVICE_ONE_ID, initial_query_arguments.get("message_type", "")
).rstrip("/")
query_dict = parse_qs(url.query)
assert query_dict == {}
assert page.select_one("label[for=to]").text.strip() == expected_search_box_label
recipient_inputs = page.select("input[name=to]")
assert len(recipient_inputs) == 2
for field in recipient_inputs:
assert field.get("value") == expected_search_box_contents
@pytest.mark.parametrize(
("message_type", "expected_search_box_label"),
[
(None, "Search by recipient or reference"),
("sms", "Search by phone number or reference"),
("email", "Search by email address or reference"),
],
)
def test_api_users_are_told_they_can_search_by_reference_when_service_has_api_keys(
client_request,
mocker,
fake_uuid,
mock_get_notifications,
mock_get_service_statistics,
mock_get_service_data_retention,
message_type,
expected_search_box_label,
mock_get_api_keys,
):
page = client_request.get(
"main.view_notifications",
service_id=SERVICE_ONE_ID,
message_type=message_type,
)
assert page.select_one("label[for=to]").text.strip() == expected_search_box_label
@pytest.mark.parametrize(
("message_type", "expected_search_box_label"),
[
(None, "Search by recipient"),
("sms", "Search by phone number"),
("email", "Search by email address"),
],
)
def test_api_users_are_not_told_they_can_search_by_reference_when_service_has_no_api_keys(
client_request,
mocker,
fake_uuid,
mock_get_notifications,
mock_get_service_statistics,
mock_get_service_data_retention,
message_type,
expected_search_box_label,
mock_get_no_api_keys,
):
page = client_request.get(
"main.view_notifications",
service_id=SERVICE_ONE_ID,
message_type=message_type,
)
assert page.select_one("label[for=to]").text.strip() == expected_search_box_label
def test_should_show_notifications_for_a_service_with_next_previous(
client_request,
service_one,
active_user_with_permissions,
mock_get_notifications_with_previous_next,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_get_no_api_keys,
mocker,
):
page = client_request.get(
"main.view_notifications",
service_id=service_one["id"],
message_type="sms",
page=2,
)
next_page_link = page.find("a", {"rel": "next"})
prev_page_link = page.find("a", {"rel": "previous"})
assert (
url_for(
"main.view_notifications",
service_id=service_one["id"],
message_type="sms",
page=3,
)
in next_page_link["href"]
)
assert "Next page" in next_page_link.text.strip()
assert "page 3" in next_page_link.text.strip()
assert (
url_for(
"main.view_notifications",
service_id=service_one["id"],
message_type="sms",
page=1,
)
in prev_page_link["href"]
)
assert "Previous page" in prev_page_link.text.strip()
assert "page 1" in prev_page_link.text.strip()
def test_doesnt_show_pagination_with_search_term(
client_request,
service_one,
active_user_with_permissions,
mock_get_notifications_with_previous_next,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_get_no_api_keys,
mocker,
):
page = client_request.post(
"main.view_notifications",
service_id=service_one["id"],
message_type="sms",
_data={
"to": "test@example.com",
},
_expected_status=200,
)
assert len(page.select("tbody tr")) == 50
assert not page.find("a", {"rel": "next"})
assert not page.find("a", {"rel": "previous"})
assert normalize_spaces(page.select_one(".table-show-more-link").text) == (
"Only showing the first 50 messages"
)
@pytest.mark.parametrize(
("job_created_at", "expected_message"),
[
("2016-01-10 11:09:00.000000+00:00", "Data available for 7 days"),
("2016-01-04 11:09:00.000000+00:00", "Data available for 1 day"),
("2016-01-03 11:09:00.000000+00:00", "Data available for 12 hours"),
("2016-01-02 23:59:59.000000+00:00", "Data no longer available"),
],
)
@freeze_time("2016-01-10 12:00:00.000000")
def test_time_left(job_created_at, expected_message):
assert get_time_left(job_created_at) == expected_message
STATISTICS = {"sms": {"requested": 6, "failed": 2, "delivered": 1}}
def test_get_status_filters_calculates_stats(client_request):
ret = get_status_filters(Service({"id": "foo"}), "sms", STATISTICS)
assert {label: count for label, _option, _link, count in ret} == {
"total": 6,
"pending": 3,
"failed": 2,
"delivered": 1,
}
def test_get_status_filters_in_right_order(client_request):
ret = get_status_filters(Service({"id": "foo"}), "sms", STATISTICS)
assert [label for label, _option, _link, _count in ret] == [
"total",
"pending",
"delivered",
"failed",
]
def test_get_status_filters_constructs_links(client_request):
ret = get_status_filters(Service({"id": "foo"}), "sms", STATISTICS)
link = ret[0][2]
assert link == "/services/foo/notifications/sms?status={}".format(
"sending,delivered,failed"
)
def test_html_contains_notification_id(
client_request,
service_one,
active_user_with_permissions,
mock_get_notifications,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_get_no_api_keys,
mocker,
):
page = client_request.get(
"main.view_notifications",
service_id=service_one["id"],
message_type="sms",
status="",
)
notifications = page.tbody.find_all("tr")
for tr in notifications:
assert uuid.UUID(tr.attrs["id"])
def test_html_contains_links_for_failed_notifications(
client_request,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_get_no_api_keys,
mocker,
):
notifications = create_notifications(status="technical-failure")
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=notifications,
)
response = client_request.get(
"main.view_notifications",
service_id=SERVICE_ONE_ID,
message_type="sms",
status="sending%2Cdelivered%2Cfailed",
)
notifications = response.tbody.find_all("tr")
for tr in notifications:
link_text = tr.find("div", class_="table-field-status-error").find("a").text
assert normalize_spaces(link_text) == "Technical failure"
@pytest.mark.parametrize(
("notification_type", "expected_row_contents"),
[
("sms", ("2021234567 hello & welcome hidden")),
("email", ("example@gsa.gov hidden, hello & welcome")),
],
)
def test_redacts_templates_that_should_be_redacted(
client_request,
mocker,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_get_no_api_keys,
notification_type,
expected_row_contents,
):
notifications = create_notifications(
status="technical-failure",
content="hello & welcome ((name))",
subject="((name)), hello & welcome",
personalisation={"name": "Jo"},
redact_personalisation=True,
template_type=notification_type,
)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=notifications,
)
page = client_request.get(
"main.view_notifications",
service_id=SERVICE_ONE_ID,
message_type=notification_type,
)
2024-07-23 15:27:03 -04:00
assert normalize_spaces(page.select("tbody tr td")[0].text) == (
expected_row_contents
)
@freeze_time("2017-09-27 12:30:00.000000")
@pytest.mark.parametrize(
("message_type", "status", "expected_hint_status", "single_line"),
[
("email", "created", "Sending since 09-27-2017 at 08:30 AM", True),
("email", "sending", "Sending since 09-27-2017 at 08:30 AM", True),
(
"email",
"temporary-failure",
"Inbox not accepting messages right now 09-27-2017 at 08:30 AM",
False,
),
(
"email",
"permanent-failure",
"Email address does not exist 09-27-2017 at 08:30 AM",
False,
),
("email", "delivered", "Delivered 09-27-2017 at 08:30 AM", True),
("sms", "created", "Sending since 09-27-2017 at 08:30 AM", True),
("sms", "sending", "Sending since 09-27-2017 at 08:30 AM", True),
(
"sms",
"temporary-failure",
"Phone not accepting messages right now 09-27-2017 at 08:30 AM",
2023-11-16 12:24:27 -08:00
False,
),
(
"sms",
"permanent-failure",
"Not delivered 09-27-2017 at 08:30 AM",
False,
),
("sms", "delivered", "Delivered 09-27-2017 at 08:30 AM", True),
],
)
def test_sending_status_hint_displays_correctly_on_notifications_page(
client_request,
service_one,
mock_get_service_statistics,
mock_get_service_data_retention,
mock_get_no_api_keys,
message_type,
status,
expected_hint_status,
single_line,
mocker,
):
notifications = create_notifications(template_type=message_type, status=status)
mocker.patch(
"app.notification_api_client.get_notifications_for_service",
return_value=notifications,
)
page = client_request.get(
"main.view_notifications",
service_id=service_one["id"],
message_type=message_type,
Add flake8 linting to project The GDS Way™[1] recommends using Flake8 to lint Python projects. This commit takes the Flake8 config from Digital Marketplace API[2] and removes the bits we don’t need. It changes the `max_complexity` setting to 14, which is the most complex code we have in this repo currently (we shouldn’t be writing code _more_ complex than what we already have). This commit also fixes the errors found by Flake8, which includes 6(!) tests which were never getting run because they had the same names as existing tests. Here is a full list of the errors that were found and fixed: ``` ./app/__init__.py:2:1: F401 're' imported but unused ./app/__init__.py:4:1: F401 'json' imported but unused ./app/__init__.py:8:1: F401 'dateutil' imported but unused ./app/__init__.py:11:1: F401 'flask.escape' imported but unused ./app/__init__.py:41:1: F401 'app.proxy_fix' imported but unused ./app/__init__.py:129:5: F821 undefined name 'proxy_fix' ./app/__init__.py:221:19: F821 undefined name 'highlight' ./app/__init__.py:221:35: F821 undefined name 'JavascriptLexer' ./app/__init__.py:221:54: F821 undefined name 'HtmlFormatter' ./app/config.py:2:1: F401 'datetime.timedelta' imported but unused ./app/event_handlers.py:2:1: F401 'flask_login.current_user' imported but unused ./app/utils.py:11:1: F401 'dateutil.parser' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.two_factor' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.notifications' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.add_service' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.forgot_password' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.inbound_number' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.styleguide' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.organisations' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.letter_jobs' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.verify' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.conversation' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.api_keys' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.send' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.dashboard' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.jobs' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.manage_users' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.sign_in' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.sign_out' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.code_not_received' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.invites' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.platform_admin' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.providers' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.service_settings' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.index' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.new_password' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.user_profile' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.feedback' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.choose_service' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.templates' imported but unused ./app/main/__init__.py:5:1: F401 'app.main.views.register' imported but unused ./app/main/forms.py:12:1: F401 'wtforms.SelectField' imported but unused ./app/main/views/api_keys.py:37:29: E241 multiple spaces after ':' ./app/main/views/feedback.py:3:1: F401 'flask.flash' imported but unused ./app/main/views/feedback.py:122:17: E123 closing bracket does not match indentation of opening bracket's line ./app/main/views/inbound_number.py:1:1: F401 'flask.url_for' imported but unused ./app/main/views/inbound_number.py:1:1: F401 'flask.session' imported but unused ./app/main/views/inbound_number.py:1:1: F401 'flask.redirect' imported but unused ./app/main/views/inbound_number.py:1:1: F401 'flask.request' imported but unused ./app/main/views/inbound_number.py:13:1: F401 'flask.jsonify' imported but unused ./app/main/views/jobs.py:31:1: F401 'app.utils.get_template' imported but unused ./app/main/views/letter_jobs.py:1:1: F401 'datetime' imported but unused ./app/main/views/letter_jobs.py:6:1: F401 'app.format_datetime_24h' imported but unused ./app/main/views/manage_users.py:111:9: E123 closing bracket does not match indentation of opening bracket's line ./app/main/views/notifications.py:121:5: F841 local variable 'status_args' is assigned to but never used ./app/main/views/organisations.py:1:1: F401 'flask.request' imported but unused ./app/main/views/service_settings.py:77:9: E123 closing bracket does not match indentation of opening bracket's line ./app/main/views/service_settings.py:82:9: E123 closing bracket does not match indentation of opening bracket's line ./app/main/views/service_settings.py:420:13: E123 closing bracket does not match indentation of opening bracket's line ./app/main/views/sign_in.py:12:1: F401 'flask_login.confirm_login' imported but unused ./app/main/views/sign_in.py:17:1: F401 'app.service_api_client' imported but unused ./app/main/views/sign_in.py:62:13: E123 closing bracket does not match indentation of opening bracket's line ./app/main/views/templates.py:4:1: F401 'flask.json' imported but unused ./app/main/views/templates.py:17:1: F401 'notifications_utils.formatters.escape_html' imported but unused ./app/main/views/templates.py:23:1: F401 'app.utils.get_help_argument' imported but unused ./app/main/views/templates.py:64:13: E123 closing bracket does not match indentation of opening bracket's line ./app/notify_client/service_api_client.py:6:1: F401 '.notification_api_client' imported but unused ./app/notify_client/user_api_client.py:1:1: F401 'uuid' imported but unused ./app/notify_client/user_api_client.py:3:1: F401 'flask.session' imported but unused ./tests/__init__.py:1:1: F401 'csv' imported but unused ./tests/app/main/test_asset_fingerprinter.py:2:1: F401 'os' imported but unused ./tests/app/main/test_asset_fingerprinter.py:4:1: F401 'unittest.mock' imported but unused ./tests/app/main/test_asset_fingerprinter.py:98:9: F841 local variable 'string_with_unicode_character' is assigned to but never used ./tests/app/main/test_errorhandlers.py:2:1: F401 'flask.url_for' imported but unused ./tests/app/main/test_permissions.py:26:13: F841 local variable 'response' is assigned to but never used ./tests/app/main/test_placeholder_form.py:3:1: F401 'wtforms.Label' imported but unused ./tests/app/main/test_placeholder_form.py:11:10: F841 local variable 'req' is assigned to but never used ./tests/app/main/test_two_factor_form.py:10:67: F841 local variable 'req' is assigned to but never used ./tests/app/main/test_two_factor_form.py:23:65: F841 local variable 'req' is assigned to but never used ./tests/app/main/test_two_factor_form.py:37:48: F841 local variable 'req' is assigned to but never used ./tests/app/main/test_two_factor_form.py:51:67: F841 local variable 'req' is assigned to but never used ./tests/app/main/test_two_factor_form.py:65:67: F841 local variable 'req' is assigned to but never used ./tests/app/main/views/test_accept_invite.py:356:5: F841 local variable 'element' is assigned to but never used ./tests/app/main/views/test_activity.py:11:1: F811 redefinition of unused 'mock_get_notifications' from line 11 ./tests/app/main/views/test_activity.py:18:1: F401 'datetime.datetime' imported but unused ./tests/app/main/views/test_activity.py:102:5: F841 local variable 'content' is assigned to but never used ./tests/app/main/views/test_activity.py:104:5: F841 local variable 'notification' is assigned to but never used ./tests/app/main/views/test_activity.py:337:5: F841 local variable '_notifications_mock' is assigned to but never used ./tests/app/main/views/test_activity.py:373:13: E126 continuation line over-indented for hanging indent ./tests/app/main/views/test_activity.py:378:9: E121 continuation line under-indented for hanging indent ./tests/app/main/views/test_activity.py:404:13: E126 continuation line over-indented for hanging indent ./tests/app/main/views/test_activity.py:407:9: E121 continuation line under-indented for hanging indent ./tests/app/main/views/test_api_keys.py:354:5: F841 local variable 'response' is assigned to but never used ./tests/app/main/views/test_conversation.py:5:1: F401 'bs4.BeautifulSoup' imported but unused ./tests/app/main/views/test_conversation.py:198:5: F841 local variable 'mock_get_inbound_sms' is assigned to but never used ./tests/app/main/views/test_dashboard.py:53:5: F841 local variable 'mock_template_stats' is assigned to but never used ./tests/app/main/views/test_dashboard.py:72:5: F841 local variable 'mock_template_stats' is assigned to but never used ./tests/app/main/views/test_jobs.py:2:1: F401 'uuid' imported but unused ./tests/app/main/views/test_jobs.py:3:1: F401 'urllib.parse.urlparse' imported but unused ./tests/app/main/views/test_jobs.py:3:1: F401 'urllib.parse.quote' imported but unused ./tests/app/main/views/test_jobs.py:3:1: F401 'urllib.parse.parse_qs' imported but unused ./tests/app/main/views/test_jobs.py:9:1: F401 'app.main.views.jobs.get_status_filters' imported but unused ./tests/app/main/views/test_jobs.py:10:1: F401 'tests.notification_json' imported but unused ./tests/app/main/views/test_letters.py:6:1: F401 'tests.service_json' imported but unused ./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.REQUESTED_STATUSES' imported but unused ./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.DELIVERED_STATUSES' imported but unused ./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.SENDING_STATUSES' imported but unused ./tests/app/main/views/test_notifications.py:5:1: F401 'app.utils.FAILURE_STATUSES' imported but unused ./tests/app/main/views/test_platform_admin.py:242:13: E126 continuation line over-indented for hanging indent ./tests/app/main/views/test_platform_admin.py:247:13: E126 continuation line over-indented for hanging indent ./tests/app/main/views/test_send.py:3:1: F401 'unittest.mock.Mock' imported but unused ./tests/app/main/views/test_send.py:18:1: F811 redefinition of unused 'mock_get_service' from line 18 ./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.multiple_letter_contact_blocks' imported but unused ./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.no_sms_senders' imported but unused ./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.multiple_sms_senders' imported but unused ./tests/app/main/views/test_send.py:18:1: F401 'tests.conftest.no_letter_contact_blocks' imported but unused ./tests/app/main/views/test_send.py:102:5: F841 local variable 'response' is assigned to but never used ./tests/app/main/views/test_send.py:870:5: F841 local variable 'response' is assigned to but never used ./tests/app/main/views/test_send.py:1367:5: F841 local variable 'service_id' is assigned to but never used ./tests/app/main/views/test_send.py:1451:13: E126 continuation line over-indented for hanging indent ./tests/app/main/views/test_send.py:1620:80: E226 missing whitespace around arithmetic operator ./tests/app/main/views/test_send.py:1909:13: E126 continuation line over-indented for hanging indent ./tests/app/main/views/test_send.py:1912:9: E121 continuation line under-indented for hanging indent ./tests/app/main/views/test_service_settings.py:13:1: F811 redefinition of unused 'no_reply_to_email_addresses' from line 13 ./tests/app/main/views/test_service_settings.py:13:1: F401 'tests.conftest.single_reply_to_email_address' imported but unused ./tests/app/main/views/test_service_settings.py:28:5: E123 closing bracket does not match indentation of opening bracket's line ./tests/app/main/views/test_service_settings.py:104:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:166:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:186:5: F841 local variable 'mocked_get_fn' is assigned to but never used ./tests/app/main/views/test_service_settings.py:217:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:237:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:257:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:307:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:340:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:466:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:555:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:615:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:719:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:874:5: F841 local variable 'page' is assigned to but never used ./tests/app/main/views/test_service_settings.py:902:5: F841 local variable 'page' is assigned to but never used ./tests/app/main/views/test_service_settings.py:954:5: F841 local variable 'page' is assigned to but never used ./tests/app/main/views/test_service_settings.py:986:5: F841 local variable 'page' is assigned to but never used ./tests/app/main/views/test_service_settings.py:1101:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1121:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1271:1: F811 redefinition of unused 'test_set_letter_contact_block_saves' from line 1189 ./tests/app/main/views/test_service_settings.py:1433:5: F841 local variable 'page' is assigned to but never used ./tests/app/main/views/test_service_settings.py:1495:5: F841 local variable 'mocked_get_fn' is assigned to but never used ./tests/app/main/views/test_service_settings.py:1540:5: F841 local variable 'mocked_get_fn' is assigned to but never used ./tests/app/main/views/test_service_settings.py:1570:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1589:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1621:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1641:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1658:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1676:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1697:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1759:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_service_settings.py:1775:1: F811 redefinition of unused 'single_reply_to_email_address' from line 13 ./tests/app/main/views/test_templates.py:3:1: F401 'uuid' imported but unused ./tests/app/main/views/test_templates.py:11:1: F401 'tests.conftest.mock_get_user' imported but unused ./tests/app/main/views/test_templates.py:514:1: F811 redefinition of unused 'mock_get_user' from line 11 ./tests/app/main/views/test_templates.py:672:1: F811 redefinition of unused 'mock_get_user' from line 11 ./tests/app/main/views/test_templates.py:795:1: F811 redefinition of unused 'mock_get_user' from line 11 ./tests/app/main/views/test_templates.py:835:1: F811 redefinition of unused 'mock_get_user' from line 11 ./tests/app/main/views/test_two_factor.py:67:13: E126 continuation line over-indented for hanging indent ./tests/app/notify_client/test_notification_client.py:79:5: F841 local variable 'mock_post' is assigned to but never used ``` 1. https://gds-way.cloudapps.digital/manuals/programming-languages/python/linting.html#how-to-use-flake8 2. https://github.com/alphagov/digitalmarketplace-api/blob/d5ab8afef4a0472f9d266d94ab4ffe1333a9aaad/.flake8
2017-10-18 14:51:26 +01:00
)
assert (
normalize_spaces(page.select(".table-field-right-aligned")[0].text)
== expected_hint_status
)
assert bool(page.select(".align-with-message-body")) is single_line