From c5f92eabfb62b04cd2029b307dee9458b3fe8077 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Mon, 12 Jun 2017 17:21:25 +0100 Subject: [PATCH 1/5] add add one-off notification status completely mimicks the job status page, and as such, all the code and templates have been taken from the job page. This page performs exactly the same as the job page for now * total, sending, delivered, failed blue boxes (though they'll just read 0/1 for now. * download report button (same as with job download, except without job or row number in file) * removed references to scheduled * kept references to help (aka tour/tutorial) as that'll eventually change over from a job to a one-off too --- app/main/__init__.py | 1 + app/main/views/jobs.py | 19 +-- app/main/views/notifications.py | 137 ++++++++++++++++++ app/notify_client/notification_api_client.py | 6 +- app/templates/partials/{jobs => }/count.html | 0 .../partials/notifications/notifications.html | 39 +++++ .../partials/notifications/status.html | 6 + .../views/notifications/notification.html | 27 ++++ app/utils.py | 50 +++++-- 9 files changed, 255 insertions(+), 30 deletions(-) create mode 100644 app/main/views/notifications.py rename app/templates/partials/{jobs => }/count.html (100%) create mode 100644 app/templates/partials/notifications/notifications.html create mode 100644 app/templates/partials/notifications/status.html create mode 100644 app/templates/views/notifications/notification.html diff --git a/app/main/__init__.py b/app/main/__init__.py index c6b2161a9..506d07858 100644 --- a/app/main/__init__.py +++ b/app/main/__init__.py @@ -29,4 +29,5 @@ from app.main.views import ( platform_admin, letter_jobs, conversation, + notifications ) diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index d10028b35..266811651 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -1,8 +1,5 @@ # -*- coding: utf-8 -*- -import ago -import dateutil from orderedset import OrderedSet -from datetime import datetime, timedelta, timezone from itertools import chain from flask import ( @@ -35,6 +32,7 @@ from app.utils import ( generate_notifications_csv, get_help_argument, get_template, + get_time_left, REQUESTED_STATUSES, FAILURE_STATUSES, SENDING_STATUSES, @@ -364,7 +362,7 @@ def get_job_partials(job): ) return { 'counts': render_template( - 'partials/jobs/count.html', + 'partials/count.html', counts=_get_job_counts(job, request.args.get('help', 0)), status=filter_args['status'] ), @@ -388,16 +386,3 @@ def get_job_partials(job): job=job ), } - - -def get_time_left(job_created_at): - return ago.human( - ( - datetime.now(timezone.utc).replace(hour=23, minute=59, second=59) - ) - ( - dateutil.parser.parse(job_created_at) + timedelta(days=8) - ), - future_tense='Data available for {}', - past_tense='Data no longer available', # No-one should ever see this - precision=1 - ) diff --git a/app/main/views/notifications.py b/app/main/views/notifications.py new file mode 100644 index 000000000..ec51789bd --- /dev/null +++ b/app/main/views/notifications.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +from flask import ( + render_template, + jsonify, + request, + url_for, + current_app +) +from flask_login import login_required + +from app import ( + notification_api_client, + current_service +) +from app.main import main +from app.utils import ( + user_has_permissions, + get_help_argument, + get_template, + get_time_left, + REQUESTED_STATUSES, + FAILURE_STATUSES, + SENDING_STATUSES, + DELIVERED_STATUSES, +) + + +def get_status_arg(filter_args): + if 'status' not in filter_args or not filter_args['status']: + return REQUESTED_STATUSES + elif filter_args['status'] == 'sending': + return SENDING_STATUSES + elif filter_args['status'] == 'delivered': + return DELIVERED_STATUSES + elif filter_args['status'] == 'failed': + return FAILURE_STATUSES + else: + current_app.logger.info('Unrecognised status filter: {}'.format(filter_args['status'])) + return REQUESTED_STATUSES + + +@main.route("/services//one-off-notification/") +@login_required +@user_has_permissions('view_activity', admin_override=True) +def view_notification(service_id, notification_id): + notification = notification_api_client.get_notification(service_id, notification_id) + return render_template( + 'views/notifications/notification.html', + finished=(notification['status'] in (DELIVERED_STATUSES + FAILURE_STATUSES)), + uploaded_file_name='Report', + template=get_template( + notification['template'], + current_service, + letter_preview_url=url_for( + '.view_template_version_preview', + service_id=service_id, + template_id=notification['template']['id'], + version=notification['template_version'], + filetype='png', + ), + ), + status=request.args.get('status'), + updates_url=url_for( + ".view_notification_updates", + service_id=service_id, + notification_id=notification['id'], + status=request.args.get('status'), + help=get_help_argument() + ), + partials=get_single_notification_partials(notification), + help=get_help_argument() + ) + + +@main.route("/services//one-off-notification/.json") +@user_has_permissions('view_activity', admin_override=True) +def view_notification_updates(service_id, notification_id): + return jsonify(**get_single_notification_partials( + notification_api_client.get_notification(service_id, notification_id) + )) + + +def _get_single_notification_counts(notification, help_argument): + return [ + ( + label, + query_param, + url_for( + ".view_notification", + service_id=notification['service'], + notification_id=notification['id'], + status=query_param, + help=help_argument + ), + count + ) for label, query_param, count in [ + [ + 'total', '', + 1 + ], + [ + 'sending', 'sending', + int(notification['status'] in SENDING_STATUSES) + ], + [ + 'delivered', 'delivered', + int(notification['status'] in DELIVERED_STATUSES) + ], + [ + 'failed', 'failed', + int(notification['status'] in FAILURE_STATUSES) + ] + ] + ] + + +def get_single_notification_partials(notification): + status_args = get_status_arg(request.args) + + return { + 'counts': render_template( + 'partials/count.html', + counts=_get_single_notification_counts(notification, request.args.get('help', 0)), + status=status_args + ), + 'notifications': render_template( + 'partials/notifications/notifications.html', + notification=notification, + more_than_one_page=False, + percentage_complete=100, + time_left=get_time_left(notification['created_at']), + ), + 'status': render_template( + 'partials/notifications/status.html', + notification=notification + ), + } diff --git a/app/notify_client/notification_api_client.py b/app/notify_client/notification_api_client.py index 88ee80e21..bea8506d9 100644 --- a/app/notify_client/notification_api_client.py +++ b/app/notify_client/notification_api_client.py @@ -55,7 +55,5 @@ class NotificationApiClient(NotifyAdminAPIClient): params=params ) - def get_notification(self, service_id, notification_id): - return self.get( - url='/service/{}/notifications/{}'.format(service_id, notification_id) - ) + def get_notification(self, service_id, notification_id):m + return self.get(url='/service/{}/notifications/{}'.format(service_id, notification_id)) diff --git a/app/templates/partials/jobs/count.html b/app/templates/partials/count.html similarity index 100% rename from app/templates/partials/jobs/count.html rename to app/templates/partials/count.html diff --git a/app/templates/partials/notifications/notifications.html b/app/templates/partials/notifications/notifications.html new file mode 100644 index 000000000..6e2be2049 --- /dev/null +++ b/app/templates/partials/notifications/notifications.html @@ -0,0 +1,39 @@ +{% from "components/table.html" import list_table, field, right_aligned_field_heading, row_heading, notification_status_field %} +{% from "components/page-footer.html" import page_footer %} + +
+
+ + {% if not help %} +

+ Download this report +   + {{ time_left }} +

+ {% endif %} + + {% call(item, row_number) list_table( + [notification], + caption=None, + caption_visible=False, + empty_message=None, + field_headings=[ + 'Recipient', + 'Status' + ], + field_headings_visible=False + ) %} + {% call row_heading() %} +

{{ item.to }}

+ {% endcall %} + {{ notification_status_field(item) }} + {% endcall %} + + {% if more_than_one_page %} + + {% endif %} + +
+
diff --git a/app/templates/partials/notifications/status.html b/app/templates/partials/notifications/status.html new file mode 100644 index 000000000..481b32446 --- /dev/null +++ b/app/templates/partials/notifications/status.html @@ -0,0 +1,6 @@ +
+

+ Sent {% if notification.created_by %}by {{ notification.created_by.name }} {% endif %} + on {{ notification.created_at|format_datetime_short }} +

+
diff --git a/app/templates/views/notifications/notification.html b/app/templates/views/notifications/notification.html new file mode 100644 index 000000000..f4936fb53 --- /dev/null +++ b/app/templates/views/notifications/notification.html @@ -0,0 +1,27 @@ +{% extends "withnav_template.html" %} +{% from "components/banner.html" import banner %} +{% from "components/ajax-block.html" import ajax_block %} +{% from "components/page-footer.html" import page_footer %} + +{% block service_page_title %} + Report +{% endblock %} + +{% block maincolumn_content %} + +

+ Report +

+ + {{ template|string }} + + {{ ajax_block(partials, updates_url, 'status', finished=finished) }} + {{ ajax_block(partials, updates_url, 'counts', finished=finished) }} + {{ ajax_block(partials, updates_url, 'notifications', finished=finished) }} + + {{ page_footer( + secondary_link=url_for('.view_template', service_id=current_service.id, template_id=template.id), + secondary_link_text='Back to {}'.format(template.name) + ) }} + +{% endblock %} diff --git a/app/utils.py b/app/utils.py index 5cec5e67c..309427e72 100644 --- a/app/utils.py +++ b/app/utils.py @@ -1,11 +1,13 @@ import re import csv -from io import StringIO, BytesIO +from io import StringIO from os import path from functools import wraps import unicodedata -from datetime import datetime +from datetime import datetime, timedelta, timezone +import dateutil +import ago from flask import ( abort, current_app, @@ -15,6 +17,11 @@ from flask import ( url_for ) from flask_login import current_user +import pyexcel +import pyexcel.ext.io +import pyexcel.ext.xls +import pyexcel.ext.xlsx +import pyexcel.ext.ods3 from notifications_utils.template import ( SMSPreviewTemplate, @@ -23,12 +30,6 @@ from notifications_utils.template import ( LetterPreviewTemplate, ) -import pyexcel -import pyexcel.ext.io -import pyexcel.ext.xls -import pyexcel.ext.xlsx -import pyexcel.ext.ods3 - SENDING_STATUSES = ['created', 'pending', 'sending'] DELIVERED_STATUSES = ['delivered', 'sent'] @@ -144,13 +145,31 @@ def generate_notifications_csv(**kwargs): notification['status'], notification['created_at'] ] - line = ','.join([str(i) for i in values]) + '\n' + line = ','.join(str(i) for i in values) + '\n' yield line if notifications_resp['links'].get('next'): kwargs['page'] += 1 else: return + raise Exception("Should never reach here") + + +def generate_single_notification_csv(notification): + fieldnames = ['Recipient', 'Template', 'Type', 'Status', 'Time'] + yield ','.join(fieldnames) + '\n' + + values = [ + notification['to'], + notification['template']['name'], + notification['template']['template_type'], + notification['status'], + notification['created_at'] + ] + line = ','.join(str(i) for i in values) + '\n' + yield line + + return def get_page_from_request(): @@ -301,3 +320,16 @@ def get_current_financial_year(): current_month = int(now.strftime('%-m')) current_year = int(now.strftime('%Y')) return current_year if current_month > 3 else current_year - 1 + + +def get_time_left(created_at): + return ago.human( + ( + datetime.now(timezone.utc).replace(hour=23, minute=59, second=59) + ) - ( + dateutil.parser.parse(created_at) + timedelta(days=8) + ), + future_tense='Data available for {}', + past_tense='Data no longer available', # No-one should ever see this + precision=1 + ) From 09dc85e5bc2d6e8d2333107a9bf1dffcf758dffb Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Fri, 16 Jun 2017 12:13:21 +0100 Subject: [PATCH 2/5] Clean up code to remove unnecessary paths. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Status code was overcomplex, given how we control the inputs. Now, it expects a single value, rather than a comma separated list, and if you give something it doesn't expect it just returns all. Note, it won't select the correct box - but if you've been manually editing the URL that's your own problem ¯\_(ツ)_/¯ Also, as this page will only ever be shown from the tour (tutorial), it doesn't need some non-help things - such as the download csv button and associated endpoint. --- .../partials/notifications/notifications.html | 8 ------ app/utils.py | 17 ----------- tests/app/main/views/test_notifications.py | 28 +++++++++++++++++++ 3 files changed, 28 insertions(+), 25 deletions(-) create mode 100644 tests/app/main/views/test_notifications.py diff --git a/app/templates/partials/notifications/notifications.html b/app/templates/partials/notifications/notifications.html index 6e2be2049..d982e2a97 100644 --- a/app/templates/partials/notifications/notifications.html +++ b/app/templates/partials/notifications/notifications.html @@ -4,14 +4,6 @@
- {% if not help %} -

- Download this report -   - {{ time_left }} -

- {% endif %} - {% call(item, row_number) list_table( [notification], caption=None, diff --git a/app/utils.py b/app/utils.py index 309427e72..5f6afc925 100644 --- a/app/utils.py +++ b/app/utils.py @@ -155,23 +155,6 @@ def generate_notifications_csv(**kwargs): raise Exception("Should never reach here") -def generate_single_notification_csv(notification): - fieldnames = ['Recipient', 'Template', 'Type', 'Status', 'Time'] - yield ','.join(fieldnames) + '\n' - - values = [ - notification['to'], - notification['template']['name'], - notification['template']['template_type'], - notification['status'], - notification['created_at'] - ] - line = ','.join(str(i) for i in values) + '\n' - yield line - - return - - def get_page_from_request(): if 'page' in request.args: try: diff --git a/tests/app/main/views/test_notifications.py b/tests/app/main/views/test_notifications.py new file mode 100644 index 000000000..b4b70b776 --- /dev/null +++ b/tests/app/main/views/test_notifications.py @@ -0,0 +1,28 @@ +from freezegun import freeze_time +import pytest +from werkzeug.datastructures import MultiDict + +from app.main.views.notifications import get_status_arg +from app.utils import ( + REQUESTED_STATUSES, + FAILURE_STATUSES, + SENDING_STATUSES, + DELIVERED_STATUSES, +) + + +@pytest.mark.parametrize('multidict_args, expected_statuses', [ + ([], REQUESTED_STATUSES), + ([('status', '')], REQUESTED_STATUSES), + ([('status', 'garbage')], REQUESTED_STATUSES), + ([('status', 'sending')], SENDING_STATUSES), + ([('status', 'delivered')], DELIVERED_STATUSES), + ([('status', 'failed')], FAILURE_STATUSES), +]) +def test_status_filters(mocker, multidict_args, expected_statuses): + mocker.patch('app.main.views.notifications.current_app') + + args = MultiDict(multidict_args) + args['status'] = get_status_arg(args) + + assert sorted(args['status']) == sorted(expected_statuses) From 20bb34849d8599c0d8eb95f1b9b006909d007d3c Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Fri, 16 Jun 2017 14:57:48 +0100 Subject: [PATCH 3/5] add tests for notification status page --- tests/__init__.py | 8 ++- tests/app/main/views/test_notifications.py | 54 +++++++++++++++++++ .../notify_client/test_notification_client.py | 8 +++ tests/conftest.py | 54 +++++++++++++++++++ 4 files changed, 119 insertions(+), 5 deletions(-) diff --git a/tests/__init__.py b/tests/__init__.py index 8560ead2d..70fbaf095 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -245,18 +245,16 @@ def notification_json( 'notifications': [{ 'id': uuid.uuid4(), 'to': to, - 'template': { - 'id': template['id'], - 'name': template['name'], - 'template_type': template['template_type'], - }, 'body': template['content'], + 'template': template, 'job': job_payload, 'sent_at': sent_at, 'status': status, 'created_at': created_at, + 'created_by': None, 'updated_at': updated_at, 'job_row_number': job_row_number, + 'service': service_id, 'template_version': template['version'] } for i in range(rows)], 'total': rows, diff --git a/tests/app/main/views/test_notifications.py b/tests/app/main/views/test_notifications.py index b4b70b776..07a2d867c 100644 --- a/tests/app/main/views/test_notifications.py +++ b/tests/app/main/views/test_notifications.py @@ -10,6 +10,8 @@ from app.utils import ( DELIVERED_STATUSES, ) +from tests.conftest import mock_get_notification + @pytest.mark.parametrize('multidict_args, expected_statuses', [ ([], REQUESTED_STATUSES), @@ -26,3 +28,55 @@ def test_status_filters(mocker, multidict_args, expected_statuses): args['status'] = get_status_arg(args) assert sorted(args['status']) == sorted(expected_statuses) + + +@freeze_time("2016-01-01 11:09:00.061258") +def test_notification_status_page_shows_details( + client_request, + mock_get_notification, + service_one, + fake_uuid, +): + page = client_request.get( + 'main.view_notification', + endpoint_kwargs={ + 'service_id': service_one['id'], + 'notification_id': fake_uuid + } + ) + + assert page.find('div', {'class': 'sms-message-wrapper'}).text.strip() == 'service one: template content' + assert ' '.join(page.find('tbody').find('tr').text.split()) == '07123456789 Delivered 1 January at 11:10am' + + mock_get_notification.assert_called_with( + service_one['id'], + fake_uuid + ) + + +@pytest.mark.parametrize('notification_status, expected_big_number_vals', [ + ('created', [1, 1, 0, 0]), + ('sending', [1, 1, 0, 0]), + ('delivered', [1, 0, 1, 0]), + ('temporary-failure', [1, 0, 0, 1]), +]) +def test_notification_status_page_shows_correct_numbers( + client_request, + mocker, + service_one, + fake_uuid, + notification_status, + expected_big_number_vals +): + mock_get_notification(mocker, fake_uuid, notification_status=notification_status) + + page = client_request.get( + 'main.view_notification', + endpoint_kwargs={ + 'service_id': service_one['id'], + 'notification_id': fake_uuid + } + ) + + big_numbers = page.find_all('div', {'class': 'big-number-number'}) + assert expected_big_number_vals == [int(num.text.strip()) for num in big_numbers] diff --git a/tests/app/notify_client/test_notification_client.py b/tests/app/notify_client/test_notification_client.py index d0e2168dc..a794c4241 100644 --- a/tests/app/notify_client/test_notification_client.py +++ b/tests/app/notify_client/test_notification_client.py @@ -33,3 +33,11 @@ def test_client_gets_notifications_for_service_and_job_by_page(mocker, arguments mock_get = mocker.patch('app.notify_client.notification_api_client.NotificationApiClient.get') NotificationApiClient().get_notifications_for_service('abcd1234', **arguments) mock_get.assert_called_once_with(**expected_call) + + +def test_get_notification(mocker): + mock_get = mocker.patch('app.notify_client.notification_api_client.NotificationApiClient.get') + NotificationApiClient().get_notification('foo', 'bar') + mock_get.assert_called_once_with( + url='/service/foo/notifications/bar' + ) diff --git a/tests/conftest.py b/tests/conftest.py index c763008e5..2b90a9e6e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -4,6 +4,8 @@ from unittest.mock import Mock import pytest from notifications_python_client.errors import HTTPError +from flask import url_for +from bs4 import BeautifulSoup from app import create_app from app.notify_client.models import ( @@ -1630,6 +1632,33 @@ def mock_reset_failed_login_count(mocker): return mocker.patch('app.user_api_client.reset_failed_login_count') +@pytest.fixture +def mock_get_notification(mocker, fake_uuid, notification_status='delivered'): + def _get_notification( + service_id, + notification_id, + ): + noti = notification_json( + service_id, + rows=1, + status=notification_status + )['notifications'][0] + + noti['id'] = notification_id + noti['created_by'] = { + 'id': fake_uuid, + 'name': 'Test User', + 'email_address': 'test@user.gov.uk' + } + noti['template'] = template_json(service_id, str(generate_uuid())) + return noti + + return mocker.patch( + 'app.notification_api_client.get_notification', + side_effect=_get_notification + ) + + @pytest.fixture(scope='function') def client(app_): with app_.test_request_context(), app_.test_client() as client: @@ -1671,3 +1700,28 @@ def os_environ(): os.environ = {} yield os.environ = old_env + + +@pytest.fixture +@pytest.fixture +def client_request(logged_in_client): + class ClientRequest: + + @staticmethod + def get(endpoint, endpoint_kwargs=None, expected_status=200, follow_redirects=False): + resp = logged_in_client.get( + url_for(endpoint, **(endpoint_kwargs or {})) + ) + assert resp.status_code == expected_status + return BeautifulSoup(resp.data.decode('utf-8'), 'html.parser') + + @staticmethod + def post(endpoint, endpoint_kwargs=None, data=None, expected_status=302, follow_redirects=False): + resp = logged_in_client.post( + url_for(endpoint, **(endpoint_kwargs or {})), + data + ) + assert resp.status_code == expected_status + return BeautifulSoup(resp.data.decode('utf-8'), 'html.parser') + + return ClientRequest From 580c225ca2eec794549f2aae8c25e22773e57bb8 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Mon, 19 Jun 2017 12:31:14 +0100 Subject: [PATCH 4/5] Change client_request so its kwargs look more like url_for --- app/config.py | 1 + app/notify_client/notification_api_client.py | 2 +- tests/app/main/views/test_notifications.py | 12 ++++-------- tests/conftest.py | 16 +++++++++------- 4 files changed, 15 insertions(+), 16 deletions(-) diff --git a/app/config.py b/app/config.py index c19849a7e..201517a09 100644 --- a/app/config.py +++ b/app/config.py @@ -96,6 +96,7 @@ class Development(Config): class Test(Development): DEBUG = True + TESTING = True STATSD_ENABLED = True WTF_CSRF_ENABLED = False CSV_UPLOAD_BUCKET_NAME = 'test-notifications-csv-upload' diff --git a/app/notify_client/notification_api_client.py b/app/notify_client/notification_api_client.py index bea8506d9..1f026eb9d 100644 --- a/app/notify_client/notification_api_client.py +++ b/app/notify_client/notification_api_client.py @@ -55,5 +55,5 @@ class NotificationApiClient(NotifyAdminAPIClient): params=params ) - def get_notification(self, service_id, notification_id):m + def get_notification(self, service_id, notification_id): return self.get(url='/service/{}/notifications/{}'.format(service_id, notification_id)) diff --git a/tests/app/main/views/test_notifications.py b/tests/app/main/views/test_notifications.py index 07a2d867c..c03b4969a 100644 --- a/tests/app/main/views/test_notifications.py +++ b/tests/app/main/views/test_notifications.py @@ -39,10 +39,8 @@ def test_notification_status_page_shows_details( ): page = client_request.get( 'main.view_notification', - endpoint_kwargs={ - 'service_id': service_one['id'], - 'notification_id': fake_uuid - } + service_id=service_one['id'], + notification_id=fake_uuid ) assert page.find('div', {'class': 'sms-message-wrapper'}).text.strip() == 'service one: template content' @@ -72,10 +70,8 @@ def test_notification_status_page_shows_correct_numbers( page = client_request.get( 'main.view_notification', - endpoint_kwargs={ - 'service_id': service_one['id'], - 'notification_id': fake_uuid - } + service_id=service_one['id'], + notification_id=fake_uuid ) big_numbers = page.find_all('div', {'class': 'big-number-number'}) diff --git a/tests/conftest.py b/tests/conftest.py index 2b90a9e6e..fed2c3c1f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,4 @@ + import os from datetime import date, datetime, timedelta from unittest.mock import Mock @@ -1702,26 +1703,27 @@ def os_environ(): os.environ = old_env -@pytest.fixture @pytest.fixture def client_request(logged_in_client): class ClientRequest: @staticmethod - def get(endpoint, endpoint_kwargs=None, expected_status=200, follow_redirects=False): + def get(endpoint, _expected_status=200, _follow_redirects=False, **endpoint_kwargs): resp = logged_in_client.get( - url_for(endpoint, **(endpoint_kwargs or {})) + url_for(endpoint, **(endpoint_kwargs or {})), + follow_redirects=_follow_redirects, ) - assert resp.status_code == expected_status + assert resp.status_code == _expected_status return BeautifulSoup(resp.data.decode('utf-8'), 'html.parser') @staticmethod - def post(endpoint, endpoint_kwargs=None, data=None, expected_status=302, follow_redirects=False): + def post(endpoint, _data=None, _expected_status=302, _follow_redirects=False, **endpoint_kwargs): resp = logged_in_client.post( url_for(endpoint, **(endpoint_kwargs or {})), - data + data=_data, + follow_redirects=_follow_redirects, ) - assert resp.status_code == expected_status + assert resp.status_code == _expected_status return BeautifulSoup(resp.data.decode('utf-8'), 'html.parser') return ClientRequest From d47c2cdf9ff49738d48d6e3e108e00b6388eba10 Mon Sep 17 00:00:00 2001 From: Leo Hemsted Date: Tue, 20 Jun 2017 10:51:25 +0100 Subject: [PATCH 5/5] remove dupe fixture --- tests/conftest.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index fed2c3c1f..7f556c22d 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1099,22 +1099,6 @@ def mock_get_notifications(mocker, api_user_active): ) -@pytest.fixture(scope='function') -def mock_get_notification(mocker, api_user_active): - def _get_notification( - service_id, - notification_id, - ): - return single_notification_json( - service_id, - ) - - return mocker.patch( - 'app.notification_api_client.get_notification', - side_effect=_get_notification - ) - - @pytest.fixture(scope='function') def mock_get_notifications_with_previous_next(mocker): def _get_notifications(service_id,