diff --git a/src/openforms/forms/tests/test_api_formsteps.py b/src/openforms/forms/tests/test_api_formsteps.py index c67a08bbc6..b175a33857 100644 --- a/src/openforms/forms/tests/test_api_formsteps.py +++ b/src/openforms/forms/tests/test_api_formsteps.py @@ -15,6 +15,7 @@ TokenFactory, UserFactory, ) +from openforms.forms.tasks import create_form_variables_for_components from openforms.submissions.tests.factories import SubmissionFactory from ..models import FormStep @@ -856,6 +857,99 @@ def test_with_non_unique_fd_slugs(self): slugs = {form_step.slug for form_step in form_steps} self.assertEqual(len(slugs), 2) # we expect two unique slugs + @tag("gh-4824") + def test_create_form_step_schedules_recouple_task(self): + """ + Regression test for https://github.com/open-formulieren/open-forms/issues/4824 + """ + assign_change_form_permissions(self.user) + form = FormFactory.create() + url = reverse("api:form-steps-list", kwargs={"form_uuid_or_slug": form.uuid}) + form_definition = FormDefinitionFactory.create( + configuration={ + "display": "form", + "components": [ + { + "key": "lastName", + "type": "textfield", + "label": "Last Name", + }, + ], + } + ) + formdefinition_detail_url = reverse( + "api:formdefinition-detail", + kwargs={"uuid": form_definition.uuid}, + ) + data = { + "formDefinition": f"http://testserver{formdefinition_detail_url}", + "index": 0, + } + self.client.force_login(user=self.user) + + with patch.object( + create_form_variables_for_components, "apply_async" + ) as mock_apply_async: + with self.captureOnCommitCallbacks(execute=True): + response = self.client.post(url, data=data) + + self.assertEqual(response.status_code, status.HTTP_201_CREATED) + self.assertEqual( + FormStep.objects.filter(form_definition=form_definition).count(), + 1, + ) + + mock_apply_async.assert_called_once_with(args=(form.id,), countdown=60) + + @tag("gh-4824") + def test_update_form_step_schedules_recouple_task(self): + """ + Regression test for https://github.com/open-formulieren/open-forms/issues/4824 + """ + assign_change_form_permissions(self.user) + form_step = FormStepFactory.create() + form_definition = FormDefinitionFactory.create( + configuration={ + "display": "form", + "components": [ + { + "key": "lastName", + "type": "textfield", + "label": "Last Name", + }, + ], + } + ) + url = reverse( + "api:form-steps-detail", + kwargs={"form_uuid_or_slug": form_step.form.uuid, "uuid": form_step.uuid}, + ) + formdefinition_detail_url = reverse( + "api:formdefinition-detail", + kwargs={"uuid": form_definition.uuid}, + ) + data = { + "formDefinition": f"http://testserver{formdefinition_detail_url}", + "index": 0, + } + self.client.force_login(user=self.user) + + with patch.object( + create_form_variables_for_components, "apply_async" + ) as mock_apply_async: + with self.captureOnCommitCallbacks(execute=True): + response = self.client.put(url, data=data) + + self.assertEqual(response.status_code, status.HTTP_200_OK) + self.assertEqual( + FormStep.objects.filter(form_definition=form_definition).count(), + 1, + ) + + mock_apply_async.assert_called_once_with( + args=(form_step.form.id,), countdown=60 + ) + class FormStepsAPITranslationTests(APITestCase): maxDiff = None diff --git a/src/openforms/forms/tests/test_tasks.py b/src/openforms/forms/tests/test_tasks.py index 761e18c179..129180e45d 100644 --- a/src/openforms/forms/tests/test_tasks.py +++ b/src/openforms/forms/tests/test_tasks.py @@ -2,14 +2,19 @@ from unittest.mock import patch from django.db import DatabaseError -from django.test import TestCase, override_settings +from django.test import TestCase, override_settings, tag from freezegun import freeze_time +from openforms.forms.models import FormVariable from openforms.logging.models import TimelineLogProxy -from ..tasks import activate_forms, deactivate_forms -from .factories import FormFactory +from ..tasks import ( + activate_forms, + create_form_variables_for_components, + deactivate_forms, +) +from .factories import FormDefinitionFactory, FormFactory, FormStepFactory logger = logging.getLogger(__name__) @@ -216,3 +221,45 @@ def test_database_error(self, mocked_deactivation): mocked_deactivation.assert_called() self.assertEqual(message, f"Form deactivation of form {form.admin_name} failed") + + +@tag("gh-4824") +class CreateFormVariablesForComponentsTests(TestCase): + def test_create_form_variables_for_components(self): + form = FormFactory.create() + form_definition = FormDefinitionFactory.create( + configuration={ + "display": "form", + "components": [ + { + "key": "lastName", + "type": "textfield", + "label": "Last Name", + }, + ], + } + ) + FormStepFactory.create(form=form, form_definition=form_definition) + + # Form is in a broken state, because no FormVariable exists for `lastName` + FormVariable.objects.filter(form=form).delete() + + with self.subTest("create variables for components"): + create_form_variables_for_components(form.id) + + variables = FormVariable.objects.filter(form=form) + + self.assertEqual(variables.count(), 1) + + [variable] = variables + + self.assertEqual(variable.form_definition, form_definition) + self.assertEqual(variable.source, "component") + self.assertEqual(variable.key, "lastName") + + with self.subTest("task is idempotent"): + create_form_variables_for_components(form.id) + + variables = FormVariable.objects.filter(form=form) + + self.assertEqual(variables.count(), 1)