class TestCancelBrief(BaseApplicationTest): url = '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-outcomes/{brief_id}/cancel' def setup_method(self, method): super(TestCancelBrief, self).setup_method(method) self.data_api_client_patch = mock.patch('app.main.views.outcome.data_api_client', autospec=True) self.data_api_client = self.data_api_client_patch.start() self.data_api_client.get_framework.return_value = FrameworkStub( slug='digital-outcomes-and-specialists-4', status='live', lots=[ LotStub(slug='digital-outcomes', allows_brief=True).response(), ] ).single_result_response() self.brief = BriefStub( user_id=123, framework_slug='digital-outcomes-and-specialists-4', lot_slug="digital-outcomes", status='closed' ).response() self.data_api_client.get_brief.return_value = {"briefs": self.brief} self.login_as_buyer() def teardown_method(self, method): self.data_api_client_patch.stop() super(TestCancelBrief, self).teardown_method(method) def test_cancel_brief_form_displays_default_title_correctly_when_accessed_through_cancel_url(self): """ This form has a dynamic title dependent on the url it is accessed through. This test checks for the default "Why do you need to cancel <brief_name>? title when accessed through the '/cancel' url". """ self.login_as_buyer() res = self.client.get(self.url.format(brief_id=1234)) assert res.status_code == 200 document = html.fromstring(res.get_data(as_text=True)) self.assert_breadcrumbs(res, extra_breadcrumbs=[ ( 'I need a thing to do a thing', '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-outcomes/1234' ), ( "Why do you need to cancel?", ) ]) page_title = document.xpath('//h1')[0].text_content() assert "Why do you need to cancel {}?".format(self.brief.get('title')) in page_title submit_button = document.xpath( '//button[normalize-space(string())=$t]', t="Update requirements", ) assert len(submit_button) == 1 expected_previous_page_link_text = 'Previous page' expected_previous_page_link_url = ( '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-outcomes/1234' ) assert ( document.xpath("//a[text()='{}']/@href".format(expected_previous_page_link_text))[0] == expected_previous_page_link_url ) def test_cancel_form_post_action_is_correct_when_accessed_from_cancel_url(self): url = ( '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/' 'digital-outcomes/{brief_id}/cancel' ) self.login_as_buyer() res = self.client.get(url.format(brief_id=1234)) document = html.fromstring(res.get_data(as_text=True)) assert document.xpath('//form[@action="{}"]'.format(url.format(brief_id=1234)))[0] is not None res = self.client.post(url.format(brief_id=1234)) document = html.fromstring(res.get_data(as_text=True)) assert document.xpath('//form[@action="{}"]'.format(url.format(brief_id=1234)))[0] is not None def test_cancel_form_displays_correctly_accessed_from_award_flow_url(self): url = ( '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/' 'digital-outcomes/{brief_id}/cancel-award' ) self.login_as_buyer() res = self.client.get(url.format(brief_id=1234)) assert res.status_code == 200 document = html.fromstring(res.get_data(as_text=True)) page_title = document.xpath('//h1')[0].text_content() assert "Why didn’t you award a contract for {}?".format(self.brief.get('title')) in page_title submit_button = document.xpath( '//button[normalize-space(string())=$t]', t="Update requirements", ) assert len(submit_button) == 1 expected_previous_page_link_text = 'Previous page' expected_previous_page_link_url = ( '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-outcomes/1234/award' ) assert ( document.xpath("//a[text()='{}']/@href".format(expected_previous_page_link_text))[0] == expected_previous_page_link_url ) def test_cancel_form_post_action_is_correct_when_accessed_from_award_flow_url(self): url = ( '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/' 'digital-outcomes/{brief_id}/cancel-award' ) self.login_as_buyer() res = self.client.get(url.format(brief_id=1234)) document = html.fromstring(res.get_data(as_text=True)) assert document.xpath('//form[@action="{}"]'.format(url.format(brief_id=1234)))[0] is not None res = self.client.post(url.format(brief_id=1234)) document = html.fromstring(res.get_data(as_text=True)) assert document.xpath('//form[@action="{}"]'.format(url.format(brief_id=1234)))[0] is not None def test_404_if_user_is_not_brief_owner(self): self.data_api_client.get_brief.return_value['briefs']['users'][0]['id'] = 234 res = self.client.get(self.url.format(brief_id=self.brief["id"])) assert res.status_code == 404 @pytest.mark.parametrize('status', ['withdrawn', 'draft', 'live', 'cancelled', 'unsuccessful', 'awarded']) def test_404_if_brief_not_closed(self, status): self.data_api_client.get_brief.return_value['briefs']['status'] = status res = self.client.get(self.url.format(brief_id=self.brief["id"])) assert res.status_code == 404 @pytest.mark.parametrize('framework_status', ['live', 'expired']) def test_200_for_acceptable_framework_statuses(self, framework_status): self.data_api_client.get_framework.return_value['frameworks']['status'] = framework_status res = self.client.get(self.url.format(brief_id=123)) assert res.status_code == 200 def test_that_no_option_chosen_triggers_error(self): res = self.client.post(self.url.format(brief_id=123)) document = html.fromstring(res.get_data(as_text=True)) error_message = document.xpath('//span[@class="govuk-error-message"]')[0].text_content() assert res.status_code == 400 assert "Select a reason for cancelling the brief." in error_message def test_that_no_option_chosen_does_not_trigger_update(self): res = self.client.post(self.url.format(brief_id=123)) assert res.status_code == 400 self.data_api_client.cancel_brief.assert_not_called() def test_cancel_triggers_cancel_brief(self): res = self.client.post( self.url.format(brief_id=123), data={'cancel_reason': 'cancel'} ) assert res.status_code == 302 self.data_api_client.cancel_brief.assert_called_once_with('123', user='******') def test_unsuccessful_triggers_cancel_brief(self): res = self.client.post( self.url.format(brief_id=123), data={'cancel_reason': 'unsuccessful'} ) assert res.status_code == 302 self.data_api_client.update_brief_as_unsuccessful.assert_called_once_with('123', user='******') @pytest.mark.parametrize('status', ['withdrawn', 'draft', 'live', 'closed', 'awarded']) def test_400_if_incorrect_status_supplied(self, status): res = self.client.post( self.url.format(brief_id=123), data={'cancel_reason': status} ) assert res.status_code == 400 assert "Not a valid choice" in res.get_data(as_text=True) @pytest.mark.parametrize('status', ['withdrawn', 'draft', 'live', 'closed', 'awarded']) def test_update_methods_not_called_if_incorrect_status_supplied(self, status): res = self.client.post( self.url.format(brief_id=123), data={'cancel_reason': status} ) assert res.status_code == 400 self.data_api_client.update_brief_as_unsuccessful.assert_not_called() self.data_api_client.cancel_brief.assert_not_called() @pytest.mark.parametrize('status', ['cancel', 'unsuccessful']) def test_redirect_and_flash_on_successful_status_change(self, status): res = self.client.post( self.url.format(brief_id=123), data={'cancel_reason': status} ) redirect_text = html.fromstring(res.get_data(as_text=True)).text_content().strip() expected_url = '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-outcomes/123' assert res.status_code == 302 assert expected_url in redirect_text expected_message = "You’ve updated ‘I need a thing to do a thing’" expected_category = "success" self.assert_flashes(expected_message, expected_category) self.assert_flashes_with_dm_alert(expected_message, expected_category)
class TestWithdrawBriefSubmission(BaseApplicationTest): def setup_method(self, method): super().setup_method(method) self.data_api_client_patch = mock.patch( "app.main.views.withdraw_brief.data_api_client", autospec=True ) self.data_api_client = self.data_api_client_patch.start() self.data_api_client.get_brief.return_value = BriefStub().single_result_response() self.data_api_client.get_framework.return_value = FrameworkStub( slug='digital-outcomes-and-specialists-4', status='live', lots=[ LotStub(slug='digital-specialists', allows_brief=True).response() ] ).single_result_response() self.brief = BriefStub( user_id=123, framework_slug='digital-outcomes-and-specialists-4', lot_slug="digital-specialists", status='draft' ).response() self.login_as_buyer() def teardown_method(self, method): self.data_api_client_patch.stop() super().teardown_method(method) @pytest.mark.parametrize('framework_status', ['live', 'expired']) def test_withdraw_brief_warning_page_displays_correctly(self, framework_status): self.data_api_client.get_framework.return_value = FrameworkStub( slug='digital-outcomes-and-specialists-4', status=framework_status, lots=[LotStub(slug='digital-specialists', allows_brief=True).response()] ).single_result_response() self.data_api_client.get_brief.return_value = BriefStub( framework_slug='digital-outcomes-and-specialists-4', status='live', ).single_result_response() res = self.client.get( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/withdraw" ) assert res.status_code == 200 document = html.fromstring(res.get_data(as_text=True)) self.assert_breadcrumbs(res, extra_breadcrumbs=[ ( 'I need a thing to do a thing', '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234' ), ( "Are you sure you want to withdraw these requirements?", ) ]) page_title = document.xpath('//h1')[0].text_content() title_caption = document.cssselect('span.govuk-caption-xl')[0].text_content() assert title_caption == self.brief.get('title') assert page_title == "Are you sure you want to withdraw these requirements?" assert document.xpath( '//form[@action="/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/withdraw"]' # noqa )[0] is not None submit_button = document.cssselect('button[name="withdraw_confirmed"]') cancel_link = document.xpath("//a[normalize-space()='Cancel']") assert len(submit_button) == 1 assert len(cancel_link) == 1 assert cancel_link[0].attrib['href'] == "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234" # noqa @pytest.mark.parametrize('framework_status', ['live', 'expired']) def test_withdraw_brief_submission(self, framework_status): self.data_api_client.get_framework.return_value = FrameworkStub( slug='digital-outcomes-and-specialists-4', status=framework_status, lots=[LotStub(slug='digital-specialists', allows_brief=True).response()] ).single_result_response() self.data_api_client.get_brief.return_value = BriefStub( framework_slug='digital-outcomes-and-specialists-4', status='live', ).single_result_response() res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/withdraw", data={"withdraw_confirmed": True} ) assert res.status_code == 302 assert self.data_api_client.delete_brief.call_args_list == [] assert res.location == "http://localhost{}".format(self.briefs_dashboard_url) expected_flash_message = ("You’ve withdrawn your requirements for ‘I need a thing to do a thing’", "success") self.assert_flashes(*expected_flash_message) self.assert_flashes_with_dm_alert(*expected_flash_message) @pytest.mark.parametrize('framework_status', ['coming', 'open', 'pending', 'standstill']) def test_404_if_framework_is_not_live_or_expired(self, framework_status): self.data_api_client.get_framework.return_value = FrameworkStub( slug='digital-outcomes-and-specialists-4', status=framework_status, lots=[LotStub(slug='digital-specialists', allows_brief=True).response()] ).single_result_response() res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/withdraw", data={"withdraw_confirmed": True} ) assert res.status_code == 404 assert not self.data_api_client.delete_brief.called @pytest.mark.parametrize('status', ['draft', 'closed', 'awarded', 'cancelled', 'unsuccessful', 'withdrawn']) def test_cannot_withdraw_non_live_brief(self, status): self.data_api_client.get_brief.return_value = BriefStub(status=status).single_result_response() res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/withdraw", data={"withdraw_confirmed": True} ) assert res.status_code == 404 assert self.data_api_client.delete_brief.call_args_list == [] def test_404_if_brief_does_not_belong_to_user(self): self.data_api_client.get_brief.return_value = BriefStub(user_id=234, status='live').single_result_response() res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/withdraw", data={"withdraw_confirmed": True} ) assert res.status_code == 404 def test_404_if_brief_has_wrong_lot(self): self.data_api_client.get_brief.return_value = BriefStub(status='live').single_result_response() res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-outcomes/1234/withdraw", data={"withdraw_confirmed": True}) assert res.status_code == 404
class TestDeleteBriefSubmission(BaseApplicationTest): def setup_method(self, method): super().setup_method(method) self.data_api_client_patch = mock.patch( "app.main.views.create_a_brief.delete.data_api_client", autospec=True) self.data_api_client = self.data_api_client_patch.start() self.data_api_client.get_brief.return_value = BriefStub( framework_slug="digital-outcomes-and-specialists-4", ).single_result_response() self.data_api_client.get_framework.return_value = FrameworkStub( slug='digital-outcomes-and-specialists-4', status='live', lots=[ LotStub(slug='digital-specialists', allows_brief=True).response() ]).single_result_response() self.brief = BriefStub( user_id=123, framework_slug='digital-outcomes-and-specialists-4', lot_slug="digital-specialists", status='draft').response() self.data_api_client.get_brief.return_value = {"briefs": self.brief} self.login_as_buyer() def teardown_method(self, method): self.data_api_client_patch.stop() super().teardown_method(method) def test_delete_brief_warning_page_displays_correctly(self): res = self.client.get( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/delete" ) assert res.status_code == 200 document = html.fromstring(res.get_data(as_text=True)) self.assert_breadcrumbs( res, extra_breadcrumbs= [('I need a thing to do a thing', '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234' ), ("Are you sure you want to delete these requirements?", )]) page_title = document.xpath('//h1')[0].text_content() title_caption = document.cssselect( 'span.govuk-caption-xl')[0].text_content() assert title_caption == self.brief.get('title') assert page_title == "Are you sure you want to delete these requirements?" url = ( '/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/' 'digital-specialists/1234/delete') assert document.xpath('//form[@action="{}"]'.format( url.format(brief_id=1234)))[0] is not None submit_button = document.cssselect('button[name="delete_confirmed"]') cancel_link = document.xpath("//a[normalize-space()='Cancel']") assert len(submit_button) == 1 assert len(cancel_link) == 1 assert cancel_link[0].attrib[ 'href'] == "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234" # noqa def test_delete_brief_submission(self): for framework_status in ['live', 'expired']: self.data_api_client.get_framework.return_value = FrameworkStub( slug='digital-outcomes-and-specialists-4', status=framework_status, lots=[ LotStub(slug='digital-specialists', allows_brief=True).response() ]).single_result_response() res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/delete", data={"delete_confirmed": "True"}) assert res.status_code == 302 assert self.data_api_client.delete_brief.called assert res.location == "http://localhost{}".format( self.briefs_dashboard_url) expected_message = "Your requirements ‘I need a thing to do a thing’ were deleted" expected_category = "success" self.assert_flashes(expected_message, expected_category) self.assert_flashes_with_dm_alert(expected_message, expected_category) def test_404_if_framework_is_not_live_or_expired(self): for framework_status in ['coming', 'open', 'pending', 'standstill']: self.data_api_client.get_framework.return_value = FrameworkStub( slug='digital-outcomes-and-specialists-4', status=framework_status, lots=[ LotStub(slug='digital-specialists', allows_brief=True).response() ]).single_result_response() res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/delete", ) assert res.status_code == 404 assert not self.data_api_client.delete_brief.called def test_cannot_delete_live_brief(self): self.data_api_client.get_brief.return_value = BriefStub( status='live').single_result_response() res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-specialists/1234/delete", ) assert res.status_code == 404 assert not self.data_api_client.delete_brief.called def test_404_if_brief_does_not_belong_to_user(self): self.data_api_client.get_brief.return_value = BriefStub( user_id=234).single_result_response() res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/" "digital-specialists/1234/delete", data={"delete_confirmed": True}) assert res.status_code == 404 def test_404_if_brief_has_wrong_lot(self): res = self.client.post( "/buyers/frameworks/digital-outcomes-and-specialists-4/requirements/digital-outcomes/1234/delete", data={"delete_confirmed": True}) assert res.status_code == 404