mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-06 19:38:24 -04:00
We used to give users the right version of the agreement by guessing their organisation from their email address. Now we do it by looking at the organisation of the service they’re looking at. In other words, users should only be downloading the agreement as part of the go live journey, not outside it. This is because we think that users will get confused if they download the agreement and: - find there’s nowhere to physically sign it - think that accepting the agreement is all they need to do to go live Maintaining two paths to download the agreement also makes the code more complicated, and makes it harder to update the content on these pages.
486 lines
14 KiB
Python
486 lines
14 KiB
Python
from functools import partial
|
||
from io import BytesIO
|
||
from unittest.mock import call
|
||
|
||
import pytest
|
||
from flask import url_for
|
||
from freezegun import freeze_time
|
||
|
||
from tests import organisation_json
|
||
from tests.conftest import (
|
||
SERVICE_ONE_ID,
|
||
mock_get_service_organisation,
|
||
normalize_spaces,
|
||
)
|
||
|
||
|
||
class _MockS3Object():
|
||
|
||
def __init__(self, data=None):
|
||
self.data = data or b''
|
||
|
||
def get(self):
|
||
return {'Body': BytesIO(self.data)}
|
||
|
||
|
||
@pytest.mark.parametrize('agreement_signed, crown, expected_links', [
|
||
(
|
||
True, True,
|
||
[
|
||
(
|
||
['govuk-back-link'],
|
||
partial(url_for, 'main.request_to_go_live', service_id=SERVICE_ONE_ID),
|
||
),
|
||
(
|
||
[],
|
||
partial(url_for, 'main.service_download_agreement', service_id=SERVICE_ONE_ID),
|
||
),
|
||
]
|
||
),
|
||
(
|
||
False, False,
|
||
[
|
||
(
|
||
['govuk-back-link'],
|
||
partial(url_for, 'main.request_to_go_live', service_id=SERVICE_ONE_ID),
|
||
),
|
||
(
|
||
[],
|
||
partial(url_for, 'main.service_download_agreement', service_id=SERVICE_ONE_ID),
|
||
),
|
||
(
|
||
['button'],
|
||
partial(url_for, 'main.service_accept_agreement', service_id=SERVICE_ONE_ID),
|
||
),
|
||
]
|
||
),
|
||
(
|
||
False, True,
|
||
[
|
||
(
|
||
['govuk-back-link'],
|
||
partial(url_for, 'main.request_to_go_live', service_id=SERVICE_ONE_ID),
|
||
),
|
||
(
|
||
[],
|
||
partial(url_for, 'main.service_download_agreement', service_id=SERVICE_ONE_ID),
|
||
),
|
||
(
|
||
['button'],
|
||
partial(url_for, 'main.service_accept_agreement', service_id=SERVICE_ONE_ID),
|
||
),
|
||
]
|
||
),
|
||
(
|
||
None, None,
|
||
[
|
||
(
|
||
['govuk-back-link'],
|
||
partial(url_for, 'main.request_to_go_live', service_id=SERVICE_ONE_ID),
|
||
),
|
||
(
|
||
[],
|
||
partial(url_for, 'main.support'),
|
||
),
|
||
]
|
||
),
|
||
])
|
||
def test_show_agreement_page(
|
||
client_request,
|
||
mocker,
|
||
fake_uuid,
|
||
mock_has_jobs,
|
||
agreement_signed,
|
||
crown,
|
||
expected_links,
|
||
):
|
||
mock_get_service_organisation(
|
||
mocker,
|
||
crown=crown,
|
||
agreement_signed=agreement_signed,
|
||
)
|
||
page = client_request.get('main.service_agreement', service_id=SERVICE_ONE_ID)
|
||
links = page.select('main .column-five-sixths a')
|
||
assert len(links) == len(expected_links)
|
||
for index, link in enumerate(links):
|
||
classes, url = expected_links[index]
|
||
assert link.get('class', []) == classes
|
||
assert link['href'] == url()
|
||
|
||
|
||
@pytest.mark.parametrize('crown, expected_status, expected_file_fetched, expected_file_served', (
|
||
(
|
||
True, 200, 'crown.pdf',
|
||
'GOV.UK Notify data sharing and financial agreement.pdf',
|
||
),
|
||
(
|
||
False, 200, 'non-crown.pdf',
|
||
'GOV.UK Notify data sharing and financial agreement (non-crown).pdf',
|
||
),
|
||
(
|
||
None, 404, None,
|
||
None,
|
||
),
|
||
))
|
||
def test_download_service_agreement(
|
||
logged_in_client,
|
||
mocker,
|
||
crown,
|
||
expected_status,
|
||
expected_file_fetched,
|
||
expected_file_served,
|
||
):
|
||
mocker.patch(
|
||
'app.models.organisation.organisations_client.get_service_organisation',
|
||
return_value=organisation_json(
|
||
crown=crown
|
||
)
|
||
)
|
||
mock_get_s3_object = mocker.patch(
|
||
'app.s3_client.s3_mou_client.get_s3_object',
|
||
return_value=_MockS3Object(b'foo')
|
||
)
|
||
|
||
response = logged_in_client.get(url_for(
|
||
'main.service_download_agreement',
|
||
service_id=SERVICE_ONE_ID,
|
||
))
|
||
assert response.status_code == expected_status
|
||
|
||
if expected_file_served:
|
||
assert response.get_data() == b'foo'
|
||
assert response.headers['Content-Type'] == 'application/pdf'
|
||
assert response.headers['Content-Disposition'] == (
|
||
'attachment; filename="{}"'.format(expected_file_served)
|
||
)
|
||
mock_get_s3_object.assert_called_once_with('test-mou', expected_file_fetched)
|
||
else:
|
||
assert not expected_file_fetched
|
||
assert mock_get_s3_object.called is False
|
||
|
||
|
||
def test_show_accept_agreement_page(
|
||
client_request,
|
||
mocker,
|
||
mock_get_service_organisation,
|
||
):
|
||
page = client_request.get('main.service_accept_agreement', service_id=SERVICE_ONE_ID)
|
||
|
||
assert [
|
||
(input['type'], input['name'], input.get('id')) for input in page.select('input')
|
||
] == [
|
||
('text', 'version', 'version'),
|
||
('radio', 'who', 'who-0'),
|
||
('radio', 'who', 'who-1'),
|
||
('text', 'on_behalf_of_name', 'on_behalf_of_name'),
|
||
('email', 'on_behalf_of_email', 'on_behalf_of_email'),
|
||
('hidden', 'csrf_token', None),
|
||
]
|
||
|
||
assert normalize_spaces(page.select_one('label[for=version]').text) == (
|
||
'Which version of the agreement are you accepting? '
|
||
'The version number is on the front page, for example ‘3.6’'
|
||
)
|
||
assert page.select_one('input[name=version]')['value'] == ''
|
||
|
||
assert normalize_spaces(page.select_one('#who legend').text) == (
|
||
'Who is accepting the agreement?'
|
||
)
|
||
assert normalize_spaces(page.select_one('label[for=who-0]').text) == (
|
||
'I’m accepting the agreement'
|
||
)
|
||
assert page.select('input[name=who]')[0]['value'] == 'me'
|
||
assert 'checked' not in page.select('input[name=who]')[0]
|
||
assert 'data-target' not in page.select('.multiple-choice')[0]
|
||
assert normalize_spaces(page.select_one('label[for=who-1]').text) == (
|
||
'I’m accepting the agreement on behalf of someone else'
|
||
)
|
||
assert page.select('input[name=who]')[1]['value'] == 'someone-else'
|
||
assert 'checked' not in page.select('input[name=who]')[1]
|
||
assert page.select('.multiple-choice')[1]['data-target'] == 'on-behalf-of'
|
||
assert [
|
||
field['name']
|
||
for field in page.select('#on-behalf-of.conditional-radio-panel input')
|
||
] == [
|
||
'on_behalf_of_name', 'on_behalf_of_email'
|
||
]
|
||
|
||
assert normalize_spaces(page.select_one('label[for=on_behalf_of_name]').text) == (
|
||
'Who are you accepting the agreement on behalf of?'
|
||
)
|
||
assert page.select_one('input[name=on_behalf_of_name]')['value'] == ''
|
||
|
||
assert normalize_spaces(page.select_one('label[for=on_behalf_of_email]').text) == (
|
||
'What’s their email address?'
|
||
)
|
||
assert page.select_one('input[name=on_behalf_of_email]')['value'] == ''
|
||
|
||
|
||
def test_accept_agreement_page_populates(
|
||
client_request,
|
||
mocker,
|
||
mock_get_service_organisation,
|
||
):
|
||
mocker.patch(
|
||
'app.models.organisation.organisations_client.get_service_organisation',
|
||
return_value=organisation_json(
|
||
agreement_signed_version='1.2',
|
||
agreement_signed_on_behalf_of_name='Firstname Lastname',
|
||
agreement_signed_on_behalf_of_email_address='test@example.com',
|
||
)
|
||
)
|
||
|
||
page = client_request.get('main.service_accept_agreement', service_id=SERVICE_ONE_ID)
|
||
|
||
assert [
|
||
(field['name'], field['value']) for field in page.select('input[type=text], input[type=email]')
|
||
] == [
|
||
('version', '1.2'),
|
||
('on_behalf_of_name', 'Firstname Lastname'),
|
||
('on_behalf_of_email', 'test@example.com'),
|
||
]
|
||
assert 'checked' not in page.select('input[name=who]')[0]
|
||
assert page.select('input[name=who]')[1]['checked'] == ''
|
||
|
||
|
||
@pytest.mark.parametrize('data, expected_errors', (
|
||
(
|
||
{
|
||
'version': '',
|
||
'who': '',
|
||
'on_behalf_of_name': '',
|
||
'on_behalf_of_email': '',
|
||
},
|
||
[
|
||
'Must be a number',
|
||
'This field is required.',
|
||
],
|
||
),
|
||
(
|
||
{
|
||
'version': 'one point two',
|
||
'who': 'me',
|
||
'on_behalf_of_name': '',
|
||
'on_behalf_of_email': '',
|
||
},
|
||
[
|
||
'Must be a number',
|
||
],
|
||
),
|
||
(
|
||
{
|
||
'version': '1.2',
|
||
'who': 'someone-else',
|
||
'on_behalf_of_name': '',
|
||
'on_behalf_of_email': '',
|
||
},
|
||
[
|
||
'Can’t be empty',
|
||
'Can’t be empty',
|
||
],
|
||
),
|
||
(
|
||
{
|
||
'version': '1.2',
|
||
'who': 'someone-else',
|
||
'on_behalf_of_name': 'Firstname Lastname',
|
||
'on_behalf_of_email': '',
|
||
},
|
||
[
|
||
'Can’t be empty',
|
||
],
|
||
),
|
||
(
|
||
{
|
||
'version': '1.2',
|
||
'who': 'someone-else',
|
||
'on_behalf_of_name': '',
|
||
'on_behalf_of_email': 'test@example.com',
|
||
},
|
||
[
|
||
'Can’t be empty',
|
||
],
|
||
),
|
||
|
||
))
|
||
def test_accept_agreement_page_validates(
|
||
client_request,
|
||
mock_get_service_organisation,
|
||
data,
|
||
expected_errors,
|
||
):
|
||
page = client_request.post(
|
||
'main.service_accept_agreement',
|
||
service_id=SERVICE_ONE_ID,
|
||
_data=data,
|
||
_expected_status=200,
|
||
)
|
||
assert [
|
||
error.text.strip() for error in page.select('.error-message')
|
||
] == expected_errors
|
||
|
||
|
||
@pytest.mark.parametrize('data, expected_persisted', (
|
||
(
|
||
{
|
||
'version': '1.2',
|
||
'who': 'someone-else',
|
||
'on_behalf_of_name': 'Firstname Lastname',
|
||
'on_behalf_of_email': 'test@example.com',
|
||
},
|
||
call(
|
||
'7aa5d4e9-4385-4488-a489-07812ba13383',
|
||
agreement_signed_version=1.2,
|
||
agreement_signed_on_behalf_of_name='Firstname Lastname',
|
||
agreement_signed_on_behalf_of_email_address='test@example.com',
|
||
)
|
||
),
|
||
(
|
||
{
|
||
'version': '1.2',
|
||
'who': 'me',
|
||
'on_behalf_of_name': 'Firstname Lastname',
|
||
'on_behalf_of_email': 'test@example.com',
|
||
},
|
||
call(
|
||
'7aa5d4e9-4385-4488-a489-07812ba13383',
|
||
agreement_signed_version=1.2,
|
||
agreement_signed_on_behalf_of_name='',
|
||
agreement_signed_on_behalf_of_email_address='',
|
||
)
|
||
),
|
||
(
|
||
{
|
||
'version': '1.2',
|
||
'who': 'me',
|
||
'on_behalf_of_name': '',
|
||
'on_behalf_of_email': '',
|
||
},
|
||
call(
|
||
'7aa5d4e9-4385-4488-a489-07812ba13383',
|
||
agreement_signed_version=1.2,
|
||
agreement_signed_on_behalf_of_name='',
|
||
agreement_signed_on_behalf_of_email_address='',
|
||
)
|
||
),
|
||
))
|
||
def test_accept_agreement_page_persists(
|
||
client_request,
|
||
mock_get_service_organisation,
|
||
mock_update_organisation,
|
||
data,
|
||
expected_persisted,
|
||
):
|
||
client_request.post(
|
||
'main.service_accept_agreement',
|
||
service_id=SERVICE_ONE_ID,
|
||
_data=data,
|
||
_expected_status=302,
|
||
_expected_redirect=url_for(
|
||
'main.service_confirm_agreement',
|
||
service_id=SERVICE_ONE_ID,
|
||
_external=True,
|
||
),
|
||
)
|
||
assert mock_update_organisation.call_args_list == [expected_persisted]
|
||
|
||
|
||
@pytest.mark.parametrize('name, email, expected_paragraph', (
|
||
(None, None, (
|
||
'I confirm that I have the legal authority to accept the '
|
||
'GOV.UK Notify data sharing and financial agreement (version '
|
||
'1.2) and that Test Organisation will be bound by it.'
|
||
)),
|
||
('Firstname Lastname', 'test@example.com', (
|
||
'I confirm that I have the legal authority to accept the '
|
||
'GOV.UK Notify data sharing and financial agreement (version '
|
||
'1.2) on behalf of Firstname Lastname (test@example.com) and '
|
||
'that Test Organisation will be bound by it.'
|
||
)),
|
||
))
|
||
def test_show_confirm_agreement_page(
|
||
client_request,
|
||
mocker,
|
||
name,
|
||
email,
|
||
expected_paragraph,
|
||
):
|
||
mocker.patch(
|
||
'app.models.organisation.organisations_client.get_service_organisation',
|
||
return_value=organisation_json(
|
||
agreement_signed_version='1.2',
|
||
agreement_signed_on_behalf_of_name=name,
|
||
agreement_signed_on_behalf_of_email_address=email,
|
||
)
|
||
)
|
||
page = client_request.get('main.service_confirm_agreement', service_id=SERVICE_ONE_ID)
|
||
assert normalize_spaces(page.select_one('main p').text) == expected_paragraph
|
||
|
||
|
||
@pytest.mark.parametrize('http_method', ('get', 'post'))
|
||
def test_confirm_agreement_page_403s_if_previous_step_not_taken(
|
||
client_request,
|
||
mock_get_service_organisation,
|
||
http_method,
|
||
):
|
||
getattr(client_request, http_method)(
|
||
'main.service_confirm_agreement',
|
||
service_id=SERVICE_ONE_ID,
|
||
_expected_status=403,
|
||
)
|
||
|
||
|
||
@freeze_time("2012-01-01 01:01")
|
||
def test_confirm_agreement_page_persists(
|
||
client_request,
|
||
mocker,
|
||
mock_update_organisation,
|
||
fake_uuid,
|
||
):
|
||
mocker.patch(
|
||
'app.models.organisation.organisations_client.get_service_organisation',
|
||
return_value=organisation_json(agreement_signed_version='1.2')
|
||
)
|
||
client_request.post(
|
||
'main.service_confirm_agreement',
|
||
service_id=SERVICE_ONE_ID,
|
||
_expected_redirect=url_for(
|
||
'main.request_to_go_live',
|
||
service_id=SERVICE_ONE_ID,
|
||
_external=True,
|
||
),
|
||
)
|
||
mock_update_organisation.assert_called_once_with(
|
||
'1234',
|
||
agreement_signed=True,
|
||
agreement_signed_at='2012-01-01 01:01:00',
|
||
agreement_signed_by_id=fake_uuid,
|
||
)
|
||
|
||
|
||
@pytest.mark.parametrize('endpoint', (
|
||
'main.public_agreement',
|
||
'main.public_download_agreement',
|
||
))
|
||
@pytest.mark.parametrize('variant, expected_status', (
|
||
('crown', 200),
|
||
('non-crown', 200),
|
||
('foo', 404),
|
||
))
|
||
def test_show_public_agreement_page(
|
||
client,
|
||
mocker,
|
||
endpoint,
|
||
variant,
|
||
expected_status,
|
||
):
|
||
mocker.patch(
|
||
'app.s3_client.s3_mou_client.get_s3_object',
|
||
return_value=_MockS3Object()
|
||
)
|
||
response = client.get(url_for(
|
||
endpoint,
|
||
variant=variant,
|
||
))
|
||
assert response.status_code == expected_status
|