From 5b99dc02f6e4fdd9c79f5ce9d405f46d72bc1b5b Mon Sep 17 00:00:00 2001 From: Steven Bal Date: Mon, 13 Jan 2025 13:58:03 +0100 Subject: [PATCH] :white_check_mark: [#4993] Tests for fetching options from Referentielijsten --- ...stenOptionsTests.test_items_not_found.yaml | 44 +++ ...entielijstenOptionsTests.test_success.yaml | 46 +++ ...stenOptionsTests.test_items_not_found.yaml | 44 +++ ...entielijstenOptionsTests.test_success.yaml | 46 +++ .../tests/test_referentielijsten_config.py | 365 ++++++++++++++++++ 5 files changed, 545 insertions(+) create mode 100644 src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectReferentielijstenOptionsTests/SelectReferentielijstenOptionsTests.test_items_not_found.yaml create mode 100644 src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectReferentielijstenOptionsTests/SelectReferentielijstenOptionsTests.test_success.yaml create mode 100644 src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectboxesReferentielijstenOptionsTests/SelectboxesReferentielijstenOptionsTests.test_items_not_found.yaml create mode 100644 src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectboxesReferentielijstenOptionsTests/SelectboxesReferentielijstenOptionsTests.test_success.yaml create mode 100644 src/openforms/formio/dynamic_config/tests/test_referentielijsten_config.py diff --git a/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectReferentielijstenOptionsTests/SelectReferentielijstenOptionsTests.test_items_not_found.yaml b/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectReferentielijstenOptionsTests/SelectReferentielijstenOptionsTests.test_items_not_found.yaml new file mode 100644 index 0000000000..31bfbe10cd --- /dev/null +++ b/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectReferentielijstenOptionsTests/SelectReferentielijstenOptionsTests.test_items_not_found.yaml @@ -0,0 +1,44 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.2 + method: GET + uri: http://localhost:8004/api/v1/items?tabel__code=non-existent + response: + body: + string: '{"count":0,"next":null,"previous":null,"results":[]}' + headers: + Allow: + - GET, HEAD, OPTIONS + Content-Length: + - '52' + Content-Security-Policy: + - 'frame-src ''self''; form-action ''self''; object-src ''none''; style-src + ''self'' ''unsafe-inline'' fonts.googleapis.com; script-src ''self'' ''unsafe-inline''; + font-src ''self'' fonts.gstatic.com; worker-src ''self'' blob:; frame-ancestors + ''none''; img-src ''self'' data: cdn.redoc.ly; default-src ''self''; base-uri + ''self''' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectReferentielijstenOptionsTests/SelectReferentielijstenOptionsTests.test_success.yaml b/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectReferentielijstenOptionsTests/SelectReferentielijstenOptionsTests.test_success.yaml new file mode 100644 index 0000000000..252e5f80b2 --- /dev/null +++ b/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectReferentielijstenOptionsTests/SelectReferentielijstenOptionsTests.test_success.yaml @@ -0,0 +1,46 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.2 + method: GET + uri: http://localhost:8004/api/v1/items?tabel__code=tabel1 + response: + body: + string: '{"count":2,"next":null,"previous":null,"results":[{"code":"option1","naam":"Option + 1","begindatumGeldigheid":"2025-01-07T14:17:53Z","einddatumGeldigheid":null,"aanvullendeGegevens":null},{"code":"option2","naam":"Option + 2","begindatumGeldigheid":"2025-01-07T14:17:59Z","einddatumGeldigheid":null,"aanvullendeGegevens":null}]}' + headers: + Allow: + - GET, HEAD, OPTIONS + Content-Length: + - '325' + Content-Security-Policy: + - 'frame-src ''self''; form-action ''self''; object-src ''none''; style-src + ''self'' ''unsafe-inline'' fonts.googleapis.com; script-src ''self'' ''unsafe-inline''; + font-src ''self'' fonts.gstatic.com; worker-src ''self'' blob:; frame-ancestors + ''none''; img-src ''self'' data: cdn.redoc.ly; default-src ''self''; base-uri + ''self''' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectboxesReferentielijstenOptionsTests/SelectboxesReferentielijstenOptionsTests.test_items_not_found.yaml b/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectboxesReferentielijstenOptionsTests/SelectboxesReferentielijstenOptionsTests.test_items_not_found.yaml new file mode 100644 index 0000000000..31bfbe10cd --- /dev/null +++ b/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectboxesReferentielijstenOptionsTests/SelectboxesReferentielijstenOptionsTests.test_items_not_found.yaml @@ -0,0 +1,44 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.2 + method: GET + uri: http://localhost:8004/api/v1/items?tabel__code=non-existent + response: + body: + string: '{"count":0,"next":null,"previous":null,"results":[]}' + headers: + Allow: + - GET, HEAD, OPTIONS + Content-Length: + - '52' + Content-Security-Policy: + - 'frame-src ''self''; form-action ''self''; object-src ''none''; style-src + ''self'' ''unsafe-inline'' fonts.googleapis.com; script-src ''self'' ''unsafe-inline''; + font-src ''self'' fonts.gstatic.com; worker-src ''self'' blob:; frame-ancestors + ''none''; img-src ''self'' data: cdn.redoc.ly; default-src ''self''; base-uri + ''self''' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectboxesReferentielijstenOptionsTests/SelectboxesReferentielijstenOptionsTests.test_success.yaml b/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectboxesReferentielijstenOptionsTests/SelectboxesReferentielijstenOptionsTests.test_success.yaml new file mode 100644 index 0000000000..252e5f80b2 --- /dev/null +++ b/src/openforms/formio/dynamic_config/tests/files/vcr_cassettes/SelectboxesReferentielijstenOptionsTests/SelectboxesReferentielijstenOptionsTests.test_success.yaml @@ -0,0 +1,46 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate, br + Connection: + - keep-alive + User-Agent: + - python-requests/2.32.2 + method: GET + uri: http://localhost:8004/api/v1/items?tabel__code=tabel1 + response: + body: + string: '{"count":2,"next":null,"previous":null,"results":[{"code":"option1","naam":"Option + 1","begindatumGeldigheid":"2025-01-07T14:17:53Z","einddatumGeldigheid":null,"aanvullendeGegevens":null},{"code":"option2","naam":"Option + 2","begindatumGeldigheid":"2025-01-07T14:17:59Z","einddatumGeldigheid":null,"aanvullendeGegevens":null}]}' + headers: + Allow: + - GET, HEAD, OPTIONS + Content-Length: + - '325' + Content-Security-Policy: + - 'frame-src ''self''; form-action ''self''; object-src ''none''; style-src + ''self'' ''unsafe-inline'' fonts.googleapis.com; script-src ''self'' ''unsafe-inline''; + font-src ''self'' fonts.gstatic.com; worker-src ''self'' blob:; frame-ancestors + ''none''; img-src ''self'' data: cdn.redoc.ly; default-src ''self''; base-uri + ''self''' + Content-Type: + - application/json + Cross-Origin-Opener-Policy: + - same-origin + Referrer-Policy: + - same-origin + Vary: + - origin + X-Content-Type-Options: + - nosniff + X-Frame-Options: + - DENY + status: + code: 200 + message: OK +version: 1 diff --git a/src/openforms/formio/dynamic_config/tests/test_referentielijsten_config.py b/src/openforms/formio/dynamic_config/tests/test_referentielijsten_config.py new file mode 100644 index 0000000000..bca4d9069c --- /dev/null +++ b/src/openforms/formio/dynamic_config/tests/test_referentielijsten_config.py @@ -0,0 +1,365 @@ +from pathlib import Path + +from django.test import TestCase, tag +from django.utils.translation import gettext as _ + +import requests_mock +from requests import RequestException +from rest_framework import status +from rest_framework.reverse import reverse +from rest_framework.test import APITestCase +from zgw_consumers.constants import AuthTypes +from zgw_consumers.test.factories import ServiceFactory + +from openforms.formio.components.vanilla import Select, SelectBoxes +from openforms.forms.tests.factories import FormFactory +from openforms.logging.models import TimelineLogProxy +from openforms.submissions.tests.factories import SubmissionFactory +from openforms.submissions.tests.mixins import SubmissionsMixin +from openforms.utils.tests.cache import clear_caches +from openforms.utils.tests.vcr import OFVCRMixin + +from ...dynamic_config.dynamic_options import DynamicOptionException + +TESTS_DIR = Path(__file__).parent.resolve() +TEST_FILES = TESTS_DIR / "files" + + +@tag("gh-4993") +class SelectReferentielijstenOptionsTests(OFVCRMixin, TestCase): + VCR_TEST_FILES = TEST_FILES + + def setUp(self): + super().setUp() + + self.service = ServiceFactory.create( + api_root="http://localhost:8004/api/v1/", + slug="referentielijsten", + auth_type=AuthTypes.no_auth, + ) + self.component = { + "key": "select", + "type": "select", + "label": "Select", + "values": [{"label": "", "value": ""}], + "dataType": "string", + "openForms": { + "code": "tabel1", + "dataSrc": "referentielijsten", + "service": self.service.slug, + "translations": {}, + }, + "id": "ew0bwv7", + } + self.submission = SubmissionFactory.create() + + # The requests to Referentielijsten are cached, we need to make sure + # that the cache is reset between tests to correctly test different scenarios + self.addCleanup(clear_caches) + + def test_success(self): + Select("select").mutate_config_dynamically(self.component, self.submission, {}) + + self.assertEqual( + self.component["data"]["values"], + [ + {"label": "Option 1", "value": "option1"}, + {"label": "Option 2", "value": "option2"}, + ], + ) + + def test_no_service_configured(self): + self.component["openForms"]["service"] = "" + + with self.assertRaises(DynamicOptionException): + Select("select").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual(log.template, "logging/events/form_configuration_error.txt") + self.assertEqual( + log.extra_data["error"], + _( + "Cannot fetch from Referentielijsten API, because no `service` is configured." + ), + ) + + def test_no_code_configured(self): + self.component["openForms"]["code"] = "" + + with self.assertRaises(DynamicOptionException): + Select("select").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual(log.template, "logging/events/form_configuration_error.txt") + self.assertEqual( + log.extra_data["error"], + _( + "Cannot fetch from Referentielijsten API, because no `code` is configured." + ), + ) + + def test_service_does_not_exist(self): + self.service.delete() + + with self.assertRaises(DynamicOptionException): + Select("select").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual(log.template, "logging/events/form_configuration_error.txt") + self.assertEqual( + log.extra_data["error"], + _( + "Cannot fetch from Referentielijsten API, service with {service_slug} does not exist." + ).format(service_slug=self.service.slug), + ) + + def test_items_not_found(self): + self.component["openForms"]["code"] = "non-existent" + + with self.assertRaises(DynamicOptionException): + Select("select").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual( + log.template, "logging/events/referentielijsten_failure_response.txt" + ) + self.assertEqual( + log.extra_data["error"], + _("No results found from Referentielijsten API."), + ) + + @requests_mock.Mocker() + def test_request_exception(self, m): + m.get( + f"{self.service.api_root}items?tabel__code=tabel1", + exc=RequestException("something went wrong"), + ) + + with self.assertRaises(DynamicOptionException): + Select("select").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual( + log.template, "logging/events/referentielijsten_failure_response.txt" + ) + self.assertEqual( + log.extra_data["error"], + _( + "Exception occurred while fetching from Referentielijsten API: something went wrong." + ), + ) + + +@tag("gh-4993") +class SelectboxesReferentielijstenOptionsTests(OFVCRMixin, TestCase): + VCR_TEST_FILES = TEST_FILES + + def setUp(self): + super().setUp() + + self.service = ServiceFactory.create( + api_root="http://localhost:8004/api/v1/", + slug="referentielijsten", + auth_type=AuthTypes.no_auth, + ) + self.component = { + "key": "selectboxes", + "type": "selectboxes", + "label": "Selectboxes", + "values": [{"label": "", "value": ""}], + "dataType": "string", + "openForms": { + "code": "tabel1", + "dataSrc": "referentielijsten", + "service": self.service.slug, + "translations": {}, + }, + "id": "ew0bwv7", + } + self.submission = SubmissionFactory.create() + + # The requests to Referentielijsten are cached, we need to make sure + # that the cache is reset between tests to correctly test different scenarios + self.addCleanup(clear_caches) + + def test_success(self): + Select("selectboxes").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertEqual( + self.component["data"]["values"], + [ + {"label": "Option 1", "value": "option1"}, + {"label": "Option 2", "value": "option2"}, + ], + ) + + def test_no_service_configured(self): + self.component["openForms"]["service"] = "" + + with self.assertRaises(DynamicOptionException): + SelectBoxes("selectboxes").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual(log.template, "logging/events/form_configuration_error.txt") + self.assertEqual( + log.extra_data["error"], + _( + "Cannot fetch from Referentielijsten API, because no `service` is configured." + ), + ) + + def test_no_code_configured(self): + self.component["openForms"]["code"] = "" + + with self.assertRaises(DynamicOptionException): + SelectBoxes("selectboxes").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual(log.template, "logging/events/form_configuration_error.txt") + self.assertEqual( + log.extra_data["error"], + _( + "Cannot fetch from Referentielijsten API, because no `code` is configured." + ), + ) + + def test_service_does_not_exist(self): + self.service.delete() + + with self.assertRaises(DynamicOptionException): + SelectBoxes("selectboxes").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual(log.template, "logging/events/form_configuration_error.txt") + self.assertEqual( + log.extra_data["error"], + _( + "Cannot fetch from Referentielijsten API, service with {service_slug} does not exist." + ).format(service_slug=self.service.slug), + ) + + def test_items_not_found(self): + self.component["openForms"]["code"] = "non-existent" + + with self.assertRaises(DynamicOptionException): + SelectBoxes("selectboxes").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual( + log.template, "logging/events/referentielijsten_failure_response.txt" + ) + self.assertEqual( + log.extra_data["error"], + _("No results found from Referentielijsten API."), + ) + + @requests_mock.Mocker() + def test_request_exception(self, m): + m.get( + f"{self.service.api_root}items?tabel__code=tabel1", + exc=RequestException("something went wrong"), + ) + + with self.assertRaises(DynamicOptionException): + SelectBoxes("selectboxes").mutate_config_dynamically( + self.component, self.submission, {} + ) + + self.assertNotIn("data", self.component) + log = TimelineLogProxy.objects.get(object_id=self.submission.form.id) + assert log.extra_data + self.assertEqual( + log.template, "logging/events/referentielijsten_failure_response.txt" + ) + self.assertEqual( + log.extra_data["error"], + _( + "Exception occurred while fetching from Referentielijsten API: something went wrong." + ), + ) + + +@tag("gh-4993") +class SubmissionStepDetailTest(SubmissionsMixin, APITestCase): + def test_get_submissionstep_detail_raises_error_for_referentielijsten_if_service_is_incorrect( + self, + ): + form = FormFactory.create( + generate_minimal_setup=True, + formstep__form_definition__configuration={ + "components": [ + { + "key": "selectboxes", + "type": "selectboxes", + "label": "Selectboxes", + "values": [{"label": "", "value": ""}], + "dataType": "string", + "openForms": { + "code": "tabel1", + "dataSrc": "referentielijsten", + "service": "non-existent", + "translations": {}, + }, + "id": "ew0bwv7", + } + ] + }, + ) + submission = SubmissionFactory.create(form=form) + endpoint = reverse( + "api:submission-steps-detail", + kwargs={ + "submission_uuid": submission.uuid, + "step_uuid": form.formstep_set.get().uuid, + }, + ) + self._add_submission_to_session(submission) + + response = self.client.get(endpoint) + + self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR) + # the detail message should be passed for errors that occur when fetching referentielijsten + self.assertEqual( + response.json()["detail"], + _( + "Loading the form failed due to problems with an external system, please try again later" + ), + )