wbcore 1.46.0__py2.py3-none-any.whl → 1.58.2__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (321) hide show
  1. wbcore/cache/decorators.py +5 -3
  2. wbcore/cache/registry.py +14 -7
  3. wbcore/configs/__init__.py +1 -0
  4. wbcore/configs/configs.py +5 -0
  5. wbcore/configs/decorators.py +1 -1
  6. wbcore/configurations/configurations/apps.py +3 -2
  7. wbcore/configurations/configurations/authentication.py +1 -1
  8. wbcore/configurations/configurations/base.py +1 -1
  9. wbcore/configurations/configurations/cache.py +1 -1
  10. wbcore/configurations/configurations/i18nl10n.py +2 -1
  11. wbcore/configurations/configurations/maintenance.py +1 -1
  12. wbcore/configurations/configurations/media.py +1 -1
  13. wbcore/configurations/configurations/middleware.py +1 -1
  14. wbcore/configurations/configurations/rest_framework.py +1 -1
  15. wbcore/configurations/configurations/static.py +3 -3
  16. wbcore/configurations/configurations/wbcore.py +1 -1
  17. wbcore/content_type/serializers.py +13 -5
  18. wbcore/content_type/utils.py +3 -3
  19. wbcore/content_type/viewsets.py +2 -2
  20. wbcore/contrib/agenda/filters/calendar_item.py +5 -4
  21. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po +145 -52
  22. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po.translated +236 -0
  23. wbcore/contrib/agenda/locale/en/LC_MESSAGES/django.po +200 -0
  24. wbcore/contrib/agenda/locale/fr/LC_MESSAGES/django.po +201 -0
  25. wbcore/contrib/agenda/viewsets/calendar_items.py +7 -7
  26. wbcore/contrib/agenda/viewsets/menu/calendar_items.py +0 -6
  27. wbcore/contrib/ai/exceptions.py +5 -5
  28. wbcore/contrib/ai/llm/config.py +76 -27
  29. wbcore/contrib/ai/llm/mixins.py +5 -8
  30. wbcore/contrib/ai/llm/utils.py +50 -26
  31. wbcore/contrib/authentication/admin.py +2 -2
  32. wbcore/contrib/authentication/factories/__init__.py +8 -1
  33. wbcore/contrib/authentication/factories/users.py +19 -0
  34. wbcore/contrib/authentication/filters.py +1 -2
  35. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po +209 -187
  36. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po.translated +634 -0
  37. wbcore/contrib/authentication/locale/en/LC_MESSAGES/django.po +590 -0
  38. wbcore/contrib/authentication/locale/fr/LC_MESSAGES/django.po +592 -0
  39. wbcore/contrib/authentication/models/users.py +3 -3
  40. wbcore/contrib/authentication/models/users_activities.py +1 -1
  41. wbcore/contrib/authentication/serializers/users.py +2 -2
  42. wbcore/contrib/authentication/tests/test_tokens.py +3 -3
  43. wbcore/contrib/authentication/tests/test_users.py +0 -1
  44. wbcore/contrib/authentication/urls.py +0 -4
  45. wbcore/contrib/authentication/viewsets/endpoints/user_activities.py +2 -11
  46. wbcore/contrib/authentication/viewsets/endpoints/users.py +0 -3
  47. wbcore/contrib/authentication/viewsets/user_activities.py +2 -1
  48. wbcore/contrib/authentication/viewsets/users.py +6 -4
  49. wbcore/contrib/color/models.py +2 -1
  50. wbcore/contrib/currency/factories.py +1 -1
  51. wbcore/contrib/currency/import_export/backends/fixerio/currency_fx_rates.py +3 -1
  52. wbcore/contrib/currency/models.py +30 -8
  53. wbcore/contrib/currency/serializers.py +5 -1
  54. wbcore/contrib/currency/tests/test_serializers.py +7 -3
  55. wbcore/contrib/currency/tests/test_viewsets.py +1 -1
  56. wbcore/contrib/currency/viewsets/currency.py +2 -2
  57. wbcore/contrib/currency/viewsets/endpoints/currency_fx_rates.py +0 -9
  58. wbcore/contrib/dataloader/tests/test/dataloaders/protocols.py +1 -2
  59. wbcore/contrib/dataloader/utils.py +2 -2
  60. wbcore/contrib/directory/factories/__init__.py +1 -1
  61. wbcore/contrib/directory/factories/entries.py +2 -1
  62. wbcore/contrib/directory/filters/entries.py +9 -0
  63. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po +728 -714
  64. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po.translated +1779 -0
  65. wbcore/contrib/directory/locale/en/LC_MESSAGES/django.po +1652 -0
  66. wbcore/contrib/directory/locale/fr/LC_MESSAGES/django.po +1654 -0
  67. wbcore/contrib/directory/migrations/0011_person_description_person_i18n.py +24 -0
  68. wbcore/contrib/directory/migrations/0012_alter_person_managers.py +20 -0
  69. wbcore/contrib/directory/migrations/0013_alter_clientmanagerrelationship_options.py +17 -0
  70. wbcore/contrib/directory/models/contacts.py +2 -2
  71. wbcore/contrib/directory/models/entries.py +31 -5
  72. wbcore/contrib/directory/models/relationships.py +31 -35
  73. wbcore/contrib/directory/permissions.py +6 -0
  74. wbcore/contrib/directory/serializers/companies.py +16 -8
  75. wbcore/contrib/directory/serializers/contacts.py +8 -8
  76. wbcore/contrib/directory/serializers/entries.py +26 -15
  77. wbcore/contrib/directory/serializers/entry_representations.py +4 -2
  78. wbcore/contrib/directory/serializers/persons.py +12 -10
  79. wbcore/contrib/directory/serializers/relationships.py +2 -2
  80. wbcore/contrib/directory/tests/conftest.py +2 -0
  81. wbcore/contrib/directory/tests/disable_signals.py +11 -1
  82. wbcore/contrib/directory/tests/signals.py +2 -2
  83. wbcore/contrib/directory/tests/test_models.py +88 -66
  84. wbcore/contrib/directory/tests/test_serializers.py +1 -1
  85. wbcore/contrib/directory/tests/test_viewsets.py +8 -8
  86. wbcore/contrib/directory/viewsets/buttons/__init__.py +1 -1
  87. wbcore/contrib/directory/viewsets/buttons/relationships.py +32 -0
  88. wbcore/contrib/directory/viewsets/contacts.py +6 -6
  89. wbcore/contrib/directory/viewsets/display/__init__.py +1 -1
  90. wbcore/contrib/directory/viewsets/display/contacts.py +1 -14
  91. wbcore/contrib/directory/viewsets/display/entries.py +68 -38
  92. wbcore/contrib/directory/viewsets/display/relationships.py +26 -50
  93. wbcore/contrib/directory/viewsets/endpoints/relationships.py +1 -26
  94. wbcore/contrib/directory/viewsets/entries.py +8 -6
  95. wbcore/contrib/directory/viewsets/previews/entries.py +3 -3
  96. wbcore/contrib/directory/viewsets/relationships.py +16 -2
  97. wbcore/contrib/directory/viewsets/titles/relationships.py +2 -3
  98. wbcore/contrib/documents/filters.py +0 -2
  99. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po +103 -94
  100. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po.translated +285 -0
  101. wbcore/contrib/documents/locale/en/LC_MESSAGES/django.po +271 -0
  102. wbcore/contrib/documents/locale/fr/LC_MESSAGES/django.po +270 -0
  103. wbcore/contrib/documents/tests/test_models.py +32 -28
  104. wbcore/contrib/documents/viewsets/endpoints/shareable_links.py +2 -21
  105. wbcore/contrib/dynamic_preferences/types.py +108 -0
  106. wbcore/contrib/dynamic_preferences/viewsets.py +27 -0
  107. wbcore/contrib/example_app/filters/event.py +3 -1
  108. wbcore/contrib/example_app/filters/match.py +1 -1
  109. wbcore/contrib/example_app/models.py +91 -22
  110. wbcore/contrib/example_app/serializers/person_team.py +4 -4
  111. wbcore/contrib/example_app/templates/example_app/embedded_view.html +19 -0
  112. wbcore/contrib/example_app/tests/e2e/test_teams.py +1 -1
  113. wbcore/contrib/example_app/tests/test_models/test_match.py +17 -7
  114. wbcore/contrib/example_app/urls.py +2 -0
  115. wbcore/contrib/example_app/views.py +7 -0
  116. wbcore/contrib/example_app/viewsets/displays/team.py +23 -4
  117. wbcore/contrib/example_app/viewsets/menu/menus.py +1 -1
  118. wbcore/contrib/example_app/viewsets/menus.py +1 -1
  119. wbcore/contrib/geography/tests/conftest.py +14 -0
  120. wbcore/contrib/geography/tests/test_models.py +23 -8
  121. wbcore/contrib/geography/tests/test_viewsets.py +96 -2
  122. wbcore/contrib/guardian/tests/test_model_mixins.py +3 -4
  123. wbcore/contrib/guardian/tests/test_tasks.py +9 -9
  124. wbcore/contrib/guardian/tests/test_viewsets.py +2 -2
  125. wbcore/contrib/guardian/viewsets/configs/__init__.py +1 -1
  126. wbcore/contrib/guardian/viewsets/configs/buttons.py +9 -0
  127. wbcore/contrib/guardian/viewsets/configs/endpoints.py +7 -0
  128. wbcore/contrib/guardian/viewsets/viewsets.py +2 -0
  129. wbcore/contrib/i18n/__init__.py +2 -0
  130. wbcore/contrib/i18n/buttons.py +33 -0
  131. wbcore/contrib/i18n/serializers/__init__.py +0 -0
  132. wbcore/contrib/i18n/serializers/fields.py +20 -0
  133. wbcore/contrib/i18n/serializers/mixins.py +13 -0
  134. wbcore/contrib/i18n/tests/conftest.py +11 -0
  135. wbcore/contrib/i18n/tests/test_viewsets.py +67 -0
  136. wbcore/contrib/i18n/translation.py +140 -0
  137. wbcore/contrib/i18n/viewsets.py +36 -0
  138. wbcore/contrib/icons/backends/default.py +1 -0
  139. wbcore/contrib/icons/backends/material.py +1 -0
  140. wbcore/contrib/icons/icons.py +5 -8
  141. wbcore/contrib/io/admin.py +1 -0
  142. wbcore/contrib/io/backends/mail.py +3 -2
  143. wbcore/contrib/io/backends/utils.py +14 -17
  144. wbcore/contrib/io/exceptions.py +8 -0
  145. wbcore/contrib/io/factories.py +1 -1
  146. wbcore/contrib/io/import_export/backends/mail.py +1 -0
  147. wbcore/contrib/io/import_export/backends/sftp.py +29 -20
  148. wbcore/contrib/io/import_export/backends/stream.py +2 -2
  149. wbcore/contrib/io/import_export/parsers/__init__.py +0 -0
  150. wbcore/contrib/io/import_export/parsers/base_csv.py +36 -0
  151. wbcore/contrib/io/import_export/parsers/resources.py +50 -0
  152. wbcore/contrib/io/imports.py +33 -25
  153. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po +114 -22
  154. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po.translated +103 -0
  155. wbcore/contrib/io/locale/en/LC_MESSAGES/django.po +138 -0
  156. wbcore/contrib/io/locale/fr/LC_MESSAGES/django.po +138 -0
  157. wbcore/contrib/io/migrations/0008_importsource_resource_kwargs.py +18 -0
  158. wbcore/contrib/io/models.py +65 -45
  159. wbcore/contrib/io/resources.py +0 -6
  160. wbcore/contrib/io/serializers.py +2 -2
  161. wbcore/contrib/io/signals.py +4 -0
  162. wbcore/contrib/io/tests/test_backends.py +19 -13
  163. wbcore/contrib/io/tests/test_exports.py +1 -1
  164. wbcore/contrib/io/tests/test_imports.py +1 -1
  165. wbcore/contrib/io/tests/test_models.py +47 -14
  166. wbcore/contrib/io/tests/test_viewsets.py +271 -0
  167. wbcore/contrib/io/viewset_mixins.py +41 -54
  168. wbcore/contrib/notifications/admin.py +1 -0
  169. wbcore/contrib/notifications/apps.py +2 -1
  170. wbcore/contrib/notifications/backends/abstract_backend.py +2 -4
  171. wbcore/contrib/notifications/backends/firebase/backends.py +5 -2
  172. wbcore/contrib/notifications/dispatch.py +18 -7
  173. wbcore/contrib/notifications/factories/notification_types.py +1 -0
  174. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po +25 -19
  175. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po.translated +63 -0
  176. wbcore/contrib/notifications/locale/en/LC_MESSAGES/django.po +61 -0
  177. wbcore/contrib/notifications/locale/fr/LC_MESSAGES/django.po +62 -0
  178. wbcore/contrib/notifications/migrations/0008_notificationtype_is_lock.py +18 -0
  179. wbcore/contrib/notifications/migrations/0009_alter_notificationtypesetting_options_and_more.py +32 -0
  180. wbcore/contrib/notifications/models/notification_types.py +67 -24
  181. wbcore/contrib/notifications/serializers/notification_types.py +16 -1
  182. wbcore/contrib/notifications/tests/test_models/test_tokens.py +8 -0
  183. wbcore/contrib/notifications/tests/test_serializers/test_notification_types.py +5 -0
  184. wbcore/contrib/notifications/tests/test_viewsets/test_notification_types.py +3 -5
  185. wbcore/contrib/notifications/utils.py +3 -2
  186. wbcore/contrib/notifications/viewsets/configs/notification_types.py +28 -6
  187. wbcore/contrib/notifications/viewsets/menus.py +1 -1
  188. wbcore/contrib/notifications/viewsets/notification_types.py +12 -2
  189. wbcore/contrib/pandas/fields.py +38 -10
  190. wbcore/contrib/pandas/filters.py +4 -1
  191. wbcore/contrib/pandas/filterset.py +8 -7
  192. wbcore/contrib/pandas/tests/test_fields/test_number_fields.py +2 -7
  193. wbcore/contrib/pandas/utils.py +1 -1
  194. wbcore/contrib/pandas/views.py +14 -13
  195. wbcore/contrib/tags/models/tags.py +4 -1
  196. wbcore/contrib/workflow/factories/display.py +2 -2
  197. wbcore/contrib/workflow/factories/transition.py +16 -15
  198. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po +457 -566
  199. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po.translated +1326 -0
  200. wbcore/contrib/workflow/locale/en/LC_MESSAGES/django.po +1102 -0
  201. wbcore/contrib/workflow/locale/fr/LC_MESSAGES/django.po +1114 -0
  202. wbcore/contrib/workflow/models/data.py +7 -4
  203. wbcore/contrib/workflow/models/process.py +2 -2
  204. wbcore/contrib/workflow/models/step.py +57 -15
  205. wbcore/contrib/workflow/serializers/data.py +8 -8
  206. wbcore/contrib/workflow/serializers/process.py +3 -2
  207. wbcore/contrib/workflow/tests/conftest.py +224 -0
  208. wbcore/contrib/workflow/tests/test_dispatch.py +82 -77
  209. wbcore/contrib/workflow/tests/test_displays.py +10 -88
  210. wbcore/contrib/workflow/tests/test_filters.py +57 -40
  211. wbcore/contrib/workflow/tests/test_models/step/test_decision_step.py +71 -68
  212. wbcore/contrib/workflow/tests/test_models/step/test_email_step.py +78 -38
  213. wbcore/contrib/workflow/tests/test_models/step/test_finish_step.py +152 -90
  214. wbcore/contrib/workflow/tests/test_models/step/test_join_step.py +100 -110
  215. wbcore/contrib/workflow/tests/test_models/step/test_step.py +168 -33
  216. wbcore/contrib/workflow/tests/test_models/test_condition.py +1 -1
  217. wbcore/contrib/workflow/tests/test_models/test_workflow.py +3 -3
  218. wbcore/contrib/workflow/tests/test_serializers.py +172 -150
  219. wbcore/contrib/workflow/tests/test_viewsets.py +264 -323
  220. wbcore/contrib/workflow/tests/test_workflow_assignees.py +215 -205
  221. wbcore/contrib/workflow/viewsets/process.py +4 -1
  222. wbcore/contrib/workflow/workflows/assignees.py +12 -7
  223. wbcore/dynamic_preferences_registry.py +102 -0
  224. wbcore/enums.py +2 -51
  225. wbcore/filters/fields/choices.py +4 -6
  226. wbcore/filters/fields/content_type.py +15 -4
  227. wbcore/filters/fields/datetime.py +50 -25
  228. wbcore/filters/fields/models.py +18 -9
  229. wbcore/filters/fields/numbers.py +9 -8
  230. wbcore/filters/filterset.py +27 -6
  231. wbcore/filters/mixins.py +41 -42
  232. wbcore/forms.py +6 -6
  233. wbcore/fsm/markdown_extensions.py +1 -1
  234. wbcore/fsm/mixins.py +20 -6
  235. wbcore/locale/de/LC_MESSAGES/django.po +982 -397
  236. wbcore/locale/de/LC_MESSAGES/django.po.translated +1580 -0
  237. wbcore/locale/en/LC_MESSAGES/django.po +1234 -0
  238. wbcore/locale/fr/LC_MESSAGES/django.po +1235 -0
  239. wbcore/markdown/models.py +8 -5
  240. wbcore/markdown/views.py +1 -1
  241. wbcore/menus/menus.py +2 -2
  242. wbcore/metadata/configs/buttons/bases.py +10 -7
  243. wbcore/metadata/configs/buttons/buttons.py +2 -1
  244. wbcore/metadata/configs/buttons/enums.py +50 -0
  245. wbcore/metadata/configs/buttons/view_config.py +13 -46
  246. wbcore/metadata/configs/display/display.py +2 -2
  247. wbcore/metadata/configs/display/formatting.py +6 -9
  248. wbcore/metadata/configs/display/instance_display/display.py +5 -2
  249. wbcore/metadata/configs/display/instance_display/pages.py +1 -1
  250. wbcore/metadata/configs/display/instance_display/shortcuts.py +1 -1
  251. wbcore/metadata/configs/display/list_display.py +54 -40
  252. wbcore/metadata/configs/display/models.py +6 -0
  253. wbcore/metadata/configs/display/view_config.py +11 -9
  254. wbcore/metadata/configs/endpoints.py +11 -4
  255. wbcore/metadata/configs/fields.py +6 -1
  256. wbcore/metadata/configs/filter_fields.py +12 -13
  257. wbcore/metadata/configs/identifiers.py +3 -1
  258. wbcore/metadata/tests/test_buttons.py +13 -16
  259. wbcore/models/fields.py +2 -2
  260. wbcore/pagination.py +1 -2
  261. wbcore/permissions/permissions.py +2 -2
  262. wbcore/permissions/utils.py +2 -2
  263. wbcore/release_notes/display.py +2 -8
  264. wbcore/release_notes/serializers.py +2 -9
  265. wbcore/release_notes/viewsets.py +8 -2
  266. wbcore/reversion/viewsets/titles.py +4 -3
  267. wbcore/serializers/__init__.py +2 -0
  268. wbcore/serializers/fields/__init__.py +2 -1
  269. wbcore/serializers/fields/boolean.py +1 -1
  270. wbcore/serializers/fields/choice.py +28 -4
  271. wbcore/serializers/fields/datetime.py +45 -36
  272. wbcore/serializers/fields/fields.py +1 -1
  273. wbcore/serializers/fields/fsm.py +1 -1
  274. wbcore/serializers/fields/list.py +2 -5
  275. wbcore/serializers/fields/mixins.py +24 -11
  276. wbcore/serializers/fields/number.py +6 -23
  277. wbcore/serializers/fields/other.py +2 -10
  278. wbcore/serializers/fields/related.py +4 -6
  279. wbcore/serializers/fields/text.py +1 -1
  280. wbcore/serializers/fields/types.py +2 -0
  281. wbcore/serializers/serializers.py +12 -3
  282. wbcore/signals/__init__.py +1 -0
  283. wbcore/signals/clone.py +4 -0
  284. wbcore/signals/models.py +2 -6
  285. wbcore/tasks.py +2 -2
  286. wbcore/templates/wbcore/email_base_template.html +3 -3
  287. wbcore/test/e2e_helpers_methods/e2e_checks.py +10 -4
  288. wbcore/test/e2e_helpers_methods/e2e_helper_methods.py +4 -2
  289. wbcore/test/mixins.py +52 -102
  290. wbcore/test/tests.py +6 -9
  291. wbcore/test/utils.py +3 -4
  292. wbcore/tests/e2e/test_e2e.py +2 -2
  293. wbcore/tests/test_cache/test_decorators.py +4 -7
  294. wbcore/tests/test_configs.py +2 -5
  295. wbcore/tests/test_enums.py +2 -1
  296. wbcore/tests/test_fields/test_choice_fields.py +9 -1
  297. wbcore/tests/test_fields/test_number_fields.py +7 -15
  298. wbcore/tests/test_fields/test_other_fields.py +1 -2
  299. wbcore/tests/test_filters/test_mixins.py +35 -35
  300. wbcore/tests/test_list_display.py +0 -2
  301. wbcore/tests/test_models/test_mixins.py +1 -1
  302. wbcore/tests/test_utils/test_date.py +1 -1
  303. wbcore/tests/test_utils/test_date_builder.py +25 -1
  304. wbcore/tests/test_utils/test_primary.py +1 -1
  305. wbcore/urls.py +4 -0
  306. wbcore/utils/date.py +18 -2
  307. wbcore/utils/figures.py +2 -2
  308. wbcore/utils/models.py +21 -4
  309. wbcore/utils/reportlab.py +7 -0
  310. wbcore/utils/rrules.py +3 -1
  311. wbcore/utils/string_loader.py +1 -1
  312. wbcore/utils/strings.py +3 -3
  313. wbcore/utils/views.py +8 -3
  314. wbcore/viewsets/mixins.py +9 -4
  315. {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/METADATA +9 -5
  316. {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/RECORD +317 -271
  317. wbcore/contrib/geography/tests/test_serializers.py +0 -7
  318. wbcore/contrib/geography/tests/tests.py +0 -13
  319. wbcore/contrib/io/tests/tests.py +0 -19
  320. wbcore/contrib/workflow/tests/tests.py +0 -25
  321. {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/WHEEL +0 -0
@@ -1,89 +1,94 @@
1
- from unittest.mock import patch
2
-
3
1
  import pytest
2
+ from pytest_mock import MockerFixture
4
3
 
5
- from wbcore.contrib.directory.factories import PersonFactory
6
4
  from wbcore.contrib.workflow.dispatch import check_workflow_for_instance
7
- from wbcore.contrib.workflow.factories import UserStepFactory
8
- from wbcore.contrib.workflow.models import Process, ProcessStep
5
+ from wbcore.contrib.workflow.models import Process, ProcessStep, Step, Workflow
9
6
 
10
7
 
11
- @pytest.mark.django_db
12
8
  class TestDispatch:
13
- @patch("wbcore.contrib.workflow.models.step.Step.set_failed")
9
+ @pytest.fixture
10
+ def mocked_instance(self, mocker: MockerFixture):
11
+ return mocker.MagicMock()
12
+
13
+ # Fixture that automatically patches ContentType lookup in every test.
14
+ @pytest.fixture(autouse=True)
15
+ def patch_content_type(self, mocker: MockerFixture):
16
+ return mocker.patch(
17
+ "wbcore.contrib.workflow.dispatch.ContentType.objects.get_for_model",
18
+ return_value="dummy_content_type",
19
+ )
20
+
21
+ # Fixture for creating a fake process step with a mismatching status.
22
+ @pytest.fixture
23
+ def mocked_process_step(self, mocker: MockerFixture):
24
+ # Create the fake casted step.
25
+ mocked_casted_step = mocker.MagicMock(spec=Step)
26
+
27
+ # Create a fake workflow with a status field.
28
+ mocked_workflow = mocker.MagicMock(spec=Workflow)
29
+ mocked_workflow.status_field = "status_a"
30
+
31
+ # Create a fake process that uses the workflow.
32
+ mocked_process = mocker.MagicMock(spec=Process)
33
+ mocked_process.workflow = mocked_workflow
34
+
35
+ # Create a fake process step with a mismatching status.
36
+ mocked_process_step = mocker.MagicMock(spec=ProcessStep)
37
+ mocked_process_step.process = mocked_process
38
+ mocked_process_step.status = "status_b"
39
+ mocked_process_step.step.get_casted_step.return_value = mocked_casted_step
40
+
41
+ return mocked_process_step, mocked_casted_step
42
+
14
43
  def test_check_workflow_for_instance_fail_process_steps(
15
- self, mock_failed, process_step_factory, random_child_step_factory
44
+ self, mocked_instance, mocked_process_step, mocker: MockerFixture
16
45
  ):
17
- instance = PersonFactory()
18
- step = random_child_step_factory(exclude_factories=[UserStepFactory])
19
- process_step1 = process_step_factory(
20
- step=step,
21
- state=ProcessStep.StepState.WAITING,
22
- process__state=Process.ProcessState.ACTIVE,
23
- process__instance=instance,
24
- )
25
- process_step2 = process_step_factory(
26
- step=step,
27
- state=ProcessStep.StepState.ACTIVE,
28
- process__state=Process.ProcessState.ACTIVE,
29
- process__instance=instance,
30
- )
31
- process_step_factory(
32
- step=step,
33
- state=ProcessStep.StepState.ACTIVE,
34
- process__state=Process.ProcessState.ACTIVE,
35
- process__instance=instance,
36
- status=instance.first_name,
37
- )
38
- process_step_factory(
39
- step=step,
40
- state=ProcessStep.StepState.CANCELED,
41
- process__state=Process.ProcessState.ACTIVE,
42
- process__instance=instance,
43
- )
44
- process_step_factory(
45
- step=step,
46
- state=ProcessStep.StepState.FAILED,
47
- process__state=Process.ProcessState.ACTIVE,
48
- process__instance=instance,
49
- )
50
- process_step_factory(
51
- step=step,
52
- state=ProcessStep.StepState.FINISHED,
53
- process__state=Process.ProcessState.ACTIVE,
54
- process__instance=instance,
46
+ # Arrange
47
+ mocked_process_step, mocked_casted_step = mocked_process_step
48
+
49
+ # Patch ProcessStep.objects.filter to return a fake process step.
50
+ mocker.patch(
51
+ "wbcore.contrib.workflow.models.ProcessStep.objects.filter",
52
+ return_value=[mocked_process_step],
55
53
  )
56
- process_step_factory(
57
- step=step,
58
- state=ProcessStep.StepState.ACTIVE,
59
- process__state=Process.ProcessState.FAILED,
60
- process__instance=instance,
54
+ # Patch get_start_steps_for_instance to return an empty list.
55
+ mocker.patch(
56
+ "wbcore.contrib.workflow.models.Workflow.get_start_steps_for_instance",
57
+ return_value=[],
61
58
  )
62
- process_step_factory(
63
- step=step,
64
- state=ProcessStep.StepState.ACTIVE,
65
- process__state=Process.ProcessState.FINISHED,
66
- process__instance=instance,
59
+
60
+ # Act
61
+ check_workflow_for_instance(sender=None, instance=mocked_instance, created=True)
62
+
63
+ # Assert: Ensure set_failed was called with the correct arguments.
64
+ mocked_casted_step.set_failed.assert_called_once_with(mocked_process_step, "Invalid status detected!")
65
+
66
+ def test_check_workflow_for_instance_start_workflow(self, mocked_instance, mocker: MockerFixture):
67
+ # Arrange: Create two fake start steps, each with its own workflow.
68
+ fake_start_step1 = mocker.MagicMock()
69
+ fake_workflow1 = mocker.MagicMock(spec=Workflow)
70
+ fake_start_step1.workflow = fake_workflow1
71
+
72
+ fake_start_step2 = mocker.MagicMock()
73
+ fake_workflow2 = mocker.MagicMock(spec=Workflow)
74
+ fake_start_step2.workflow = fake_workflow2
75
+
76
+ # Patch get_start_steps_for_instance to return our fake start steps.
77
+ get_start_steps_patch = mocker.patch(
78
+ "wbcore.contrib.workflow.models.Workflow.get_start_steps_for_instance",
79
+ return_value=[fake_start_step1, fake_start_step2],
67
80
  )
68
- process_step_factory(
69
- step=step,
70
- state=ProcessStep.StepState.ACTIVE,
71
- process__state=Process.ProcessState.ACTIVE,
72
- process__instance=PersonFactory(),
81
+ # Patch ProcessStep.objects.filter to return an empty list.
82
+ mocker.patch(
83
+ "wbcore.contrib.workflow.models.ProcessStep.objects.filter",
84
+ return_value=[],
73
85
  )
74
- check_workflow_for_instance(instance.__class__, instance, False)
75
- assert len(mock_failed.call_args_list) == 2
76
- assert str(mock_failed.call_args_list[0][0][0].pk) == process_step1.pk
77
- assert str(mock_failed.call_args_list[1][0][0].pk) == process_step2.pk
78
-
79
- @patch("wbcore.contrib.workflow.models.workflow.Workflow.start_workflow")
80
- @patch("wbcore.contrib.workflow.models.workflow.Workflow.get_start_steps_for_instance")
81
- def test_check_workflow_for_instance_start_workflow(self, mock_start_steps, mock_start, start_step_factory):
82
- instance = PersonFactory()
83
- start_step1 = start_step_factory()
84
- start_step2 = start_step_factory()
85
- start_step_factory()
86
- mock_start_steps.return_value = [start_step1, start_step2]
87
- check_workflow_for_instance(instance.__class__, instance, False)
88
- assert mock_start_steps.call_args.args == (instance,)
89
- assert mock_start.call_args_list == [((start_step1, instance),), ((start_step2, instance),)]
86
+
87
+ # Act
88
+ check_workflow_for_instance(sender=None, instance=mocked_instance, created=True)
89
+
90
+ # Assert: Verify that get_start_steps_for_instance was called with our instance.
91
+ get_start_steps_patch.assert_called_once_with(mocked_instance)
92
+ # Verify that each fake workflow's start_workflow was called with its corresponding start step and the instance.
93
+ fake_workflow1.start_workflow.assert_called_once_with(fake_start_step1, mocked_instance)
94
+ fake_workflow2.start_workflow.assert_called_once_with(fake_start_step2, mocked_instance)
@@ -1,4 +1,3 @@
1
- import pytest
2
1
  from rest_framework.test import APIRequestFactory
3
2
 
4
3
  from wbcore.contrib.color.enums import WBColor
@@ -9,7 +8,6 @@ from wbcore.contrib.workflow.viewsets.display.process import (
9
8
  )
10
9
 
11
10
 
12
- @pytest.mark.django_db
13
11
  class TestProcessStep:
14
12
  api_factory = APIRequestFactory()
15
13
 
@@ -19,8 +17,16 @@ class TestProcessStep:
19
17
  (ProcessStep.StepState.CANCELED, WBColor.BLUE_LIGHT.value),
20
18
  ]
21
19
  assert set((y.icon, y.label, y.value) for y in get_state_legend(color_map)[0].items) == {
22
- (WBColor.GREEN_LIGHT.value, ProcessStep.StepState.FAILED.label, ProcessStep.StepState.FAILED.value),
23
- (WBColor.BLUE_LIGHT.value, ProcessStep.StepState.CANCELED.label, ProcessStep.StepState.CANCELED.value),
20
+ (
21
+ WBColor.GREEN_LIGHT.value,
22
+ ProcessStep.StepState.FAILED.label,
23
+ ProcessStep.StepState.FAILED.value,
24
+ ),
25
+ (
26
+ WBColor.BLUE_LIGHT.value,
27
+ ProcessStep.StepState.CANCELED.label,
28
+ ProcessStep.StepState.CANCELED.value,
29
+ ),
24
30
  }
25
31
 
26
32
  def test_get_state_formatting(self):
@@ -34,87 +40,3 @@ class TestProcessStep:
34
40
  (WBColor.GREY.value, ProcessStep.StepState.WAITING.value),
35
41
  (WBColor.YELLOW_DARK.value, ProcessStep.StepState.ACTIVE.value),
36
42
  }
37
-
38
- # @patch("wbcore.contrib.workflow.viewsets.display.process.split_list_into_grid_template_area_sublists")
39
- # def test_process_step_display_instance_injection(
40
- # self, mock_split, data_factory, user_step_factory, process_step_factory
41
- # ):
42
- # request = self.api_factory.get("")
43
- # request.user = get_or_create_superuser()
44
- # request.query_params = {}
45
- # step = user_step_factory()
46
- # process_step = process_step_factory(step=step)
47
- # data_factory(workflow=process_step.step.workflow)
48
- # mvs = ProcessStepModelViewSet(request=request, kwargs={"pk": process_step.pk})
49
- # display = mvs.display_config_class(mvs, request).get_instance_display()
50
- # assert display.pages[0].layouts["default"].grid_template_areas == step.display.grid_template_areas
51
- # assert not mock_split.called
52
-
53
- # @patch("wbcore.contrib.workflow.viewsets.display.process.split_list_into_grid_template_area_sublists")
54
- # def test_process_step_display_no_userstep(self, mock_split, random_child_step_factory, process_step_factory):
55
- # request = self.api_factory.get("")
56
- # request.user = get_or_create_superuser()
57
- # request.query_params = {}
58
- # step = random_child_step_factory(exclude_factories=[UserStepFactory])
59
- # process_step = process_step_factory(step=step)
60
- # mvs = ProcessStepModelViewSet(request=request, kwargs={"pk": process_step.pk})
61
- # display = mvs.display_config_class(mvs, request).get_instance_display()
62
- # display_fields = set(itertools.chain.from_iterable(display.pages[0].layouts["default"].grid_template_areas))
63
- # person_fields = set(PersonModelSerializer.Meta.fields)
64
- # assert not mock_split.called
65
- # assert display_fields.intersection(person_fields) == {"id"}
66
-
67
- # @patch("wbcore.contrib.workflow.viewsets.display.process.split_list_into_grid_template_area_sublists")
68
- # def test_process_step_display_no_display(self, mock_split, user_step_factory, process_step_factory):
69
- # request = self.api_factory.get("")
70
- # request.user = get_or_create_superuser()
71
- # request.query_params = {}
72
- # step = user_step_factory(display=None)
73
- # process_step = process_step_factory(step=step)
74
- # mvs = ProcessStepModelViewSet(request=request, kwargs={"pk": process_step.pk})
75
- # display = mvs.display_config_class(mvs, request).get_instance_display()
76
- # display_fields = set(itertools.chain.from_iterable(display.pages[0].layouts["default"].grid_template_areas))
77
- # person_fields = set(PersonModelSerializer.Meta.fields)
78
- # assert not mock_split.called
79
- # assert display_fields.intersection(person_fields) == {"id"}
80
-
81
- # @patch("wbcore.contrib.workflow.viewsets.display.process.split_list_into_grid_template_area_sublists")
82
- # def test_process_step_display_data_injection(
83
- # self, mock_split, data_factory, user_step_factory, process_step_factory
84
- # ):
85
- # request = self.api_factory.get("")
86
- # request.user = get_or_create_superuser()
87
- # request.query_params = {}
88
- # step = user_step_factory(display=None)
89
- # process_step = process_step_factory(step=step)
90
- # data1 = data_factory(workflow=process_step.process.workflow)
91
- # data2 = data_factory(workflow=process_step.process.workflow)
92
- # data_factory()
93
- # data_sublist = ["a", "b", "c"]
94
- # mock_split.return_value = data_sublist
95
- # mvs = ProcessStepModelViewSet(request=request, kwargs={"pk": process_step.pk})
96
- # display = mvs.display_config_class(mvs, request).get_instance_display()
97
- # display_fields = set(itertools.chain.from_iterable(display.pages[0].layouts["default"].grid_template_areas))
98
- # person_fields = set(PersonModelSerializer.Meta.fields)
99
- # assert display_fields.intersection(person_fields) == {"id"}
100
- # assert mock_split.call_args.args[0] == [f"data__{str(data1.pk)}", f"data__{str(data2.pk)}"]
101
- # for key in data_sublist:
102
- # assert key in display_fields
103
-
104
- # @patch("wbcore.contrib.workflow.viewsets.display.process.split_list_into_grid_template_area_sublists")
105
- # def test_process_step_display_no_display_no_data(
106
- # self, mock_split, data_factory, user_step_factory, process_step_factory
107
- # ):
108
- # request = self.api_factory.get("")
109
- # request.user = get_or_create_superuser()
110
- # request.query_params = {}
111
- # step = user_step_factory(display=None)
112
- # process_step = process_step_factory(step=step)
113
- # data_factory()
114
- # data_factory()
115
- # mvs = ProcessStepModelViewSet(request=request, kwargs={"pk": process_step.pk})
116
- # display = mvs.display_config_class(mvs, request).get_instance_display()
117
- # display_fields = set(itertools.chain.from_iterable(display.pages[0].layouts["default"].grid_template_areas))
118
- # person_fields = set(PersonModelSerializer.Meta.fields)
119
- # assert display_fields.intersection(person_fields) == {"id"}
120
- # assert not mock_split.called
@@ -12,76 +12,93 @@ from wbcore.contrib.workflow.viewsets import (
12
12
  from wbcore.test.utils import get_or_create_superuser
13
13
 
14
14
 
15
+ @pytest.fixture()
16
+ def super_user_get_request():
17
+ request = APIRequestFactory().get("")
18
+ request.user = get_or_create_superuser()
19
+
20
+
15
21
  @pytest.mark.django_db
16
22
  class TestWorkflow:
17
- api_factory = APIRequestFactory()
23
+ @pytest.fixture()
24
+ def workflow_viewset(self):
25
+ return WorkflowModelViewSet()
18
26
 
19
- def test_filter_attached_model(self, workflow_factory):
27
+ def test_filter_attached_model(self, super_user_get_request, workflow_viewset, workflow_factory):
20
28
  workflow_factory()
21
29
  workflow_factory(model=ContentType.objects.first())
22
- mvs = WorkflowModelViewSet()
23
- request = self.api_factory.get("")
24
- request.user = get_or_create_superuser()
25
- qs = mvs.get_queryset()
26
- assert mvs.filterset_class(request=request).filter_attached_model(qs, "", None) == qs
27
- assert mvs.filterset_class(request=request).filter_attached_model(qs, "", "person").count() == 1
28
- assert not mvs.filterset_class(request=request).filter_attached_model(qs, "", "company").exists()
30
+ qs = workflow_viewset.get_queryset()
31
+ assert (
32
+ workflow_viewset.filterset_class(request=super_user_get_request).filter_attached_model(qs, "", None) == qs
33
+ )
34
+ assert (
35
+ workflow_viewset.filterset_class(request=super_user_get_request)
36
+ .filter_attached_model(qs, "", "person")
37
+ .count()
38
+ == 1
39
+ )
40
+ assert (
41
+ not workflow_viewset.filterset_class(request=super_user_get_request)
42
+ .filter_attached_model(qs, "", "company")
43
+ .exists()
44
+ )
29
45
 
30
- def test_filter_by_data(self, workflow_factory, data_factory):
46
+ def test_filter_by_data(self, super_user_get_request, workflow_viewset, workflow_factory, data_factory):
31
47
  workflow_factory()
32
48
  data = data_factory()
33
- mvs = WorkflowModelViewSet()
34
- request = self.api_factory.get("")
35
- request.user = get_or_create_superuser()
36
- qs = mvs.get_queryset()
37
- assert mvs.filterset_class(request=request).filter_by_data(qs, "", None) == qs
38
- assert mvs.filterset_class(request=request).filter_by_data(qs, "", data).count() == 1
39
- assert mvs.filterset_class(request=request).filter_by_data(qs, "", data).first() == data.workflow
49
+ qs = workflow_viewset.get_queryset()
50
+ assert workflow_viewset.filterset_class(request=super_user_get_request).filter_by_data(qs, "", None) == qs
51
+ assert (
52
+ workflow_viewset.filterset_class(request=super_user_get_request).filter_by_data(qs, "", data).count() == 1
53
+ )
54
+ assert (
55
+ workflow_viewset.filterset_class(request=super_user_get_request).filter_by_data(qs, "", data).first()
56
+ == data.workflow
57
+ )
40
58
 
41
59
 
42
60
  @pytest.mark.django_db
43
61
  class TestStep:
44
- api_factory = APIRequestFactory()
45
-
46
- def test_filter_by_transition(self, transition_factory, random_child_step_factory):
62
+ def test_filter_by_transition(self, super_user_get_request, transition_factory, random_child_step_factory):
47
63
  transition = transition_factory()
48
64
  random_child_step_factory()
49
65
  mvs = StepModelViewSet(kwargs={})
50
- request = self.api_factory.get("")
51
- request.user = get_or_create_superuser()
52
66
  qs = mvs.get_queryset()
53
- assert mvs.get_filterset_class(request=request)().filter_by_transition(qs, "", None) == qs
54
- assert set(mvs.get_filterset_class(request=request)().filter_by_transition(qs, "", transition)) == set(
55
- Step.objects.filter(id__in=[transition.from_step.pk, transition.to_step.pk])
56
- )
67
+ assert mvs.get_filterset_class(request=super_user_get_request)().filter_by_transition(qs, "", None) == qs
68
+ assert set(
69
+ mvs.get_filterset_class(request=super_user_get_request)().filter_by_transition(qs, "", transition)
70
+ ) == set(Step.objects.filter(id__in=[transition.from_step.pk, transition.to_step.pk]))
57
71
 
58
- def test_email_filter_template_name(self, email_step_factory):
72
+ def test_email_filter_template_name(self, super_user_get_request, email_step_factory):
59
73
  step = email_step_factory()
60
74
  email_step_factory()
61
75
  mvs = EmailStepModelViewSet(kwargs={})
62
- request = self.api_factory.get("")
63
- request.user = get_or_create_superuser()
64
76
  qs = mvs.get_queryset()
65
- assert mvs.get_filterset_class(request=request)().filter_template_name(qs, "", None) == qs
66
- assert mvs.get_filterset_class(request=request)().filter_template_name(qs, "", step.template.name).count() == 1
77
+ assert mvs.get_filterset_class(request=super_user_get_request)().filter_template_name(qs, "", None) == qs
78
+ assert (
79
+ mvs.get_filterset_class(request=super_user_get_request)()
80
+ .filter_template_name(qs, "", step.template.name)
81
+ .count()
82
+ == 1
83
+ )
67
84
  assert (
68
- mvs.get_filterset_class(request=request)().filter_template_name(qs, "", step.template.name).first() == step
85
+ mvs.get_filterset_class(request=super_user_get_request)()
86
+ .filter_template_name(qs, "", step.template.name)
87
+ .first()
88
+ == step
69
89
  )
70
90
 
71
91
 
72
92
  @pytest.mark.django_db
73
93
  class TestTransition:
74
- api_factory = APIRequestFactory()
75
-
76
- def test_filter_by_condition(self, condition_factory, transition_factory):
94
+ def test_filter_by_condition(self, super_user_get_request, condition_factory, transition_factory):
77
95
  transition_factory()
78
96
  condition = condition_factory()
79
97
  mvs = TransitionModelViewSet(kwargs={})
80
- request = self.api_factory.get("")
81
- request.user = get_or_create_superuser()
82
98
  qs = mvs.get_queryset()
83
- assert mvs.filterset_class(request=request).filter_by_condition(qs, "", None) == qs
84
- assert mvs.filterset_class(request=request).filter_by_condition(qs, "", condition).count() == 1
99
+ assert mvs.filterset_class(request=super_user_get_request).filter_by_condition(qs, "", None) == qs
100
+ assert mvs.filterset_class(request=super_user_get_request).filter_by_condition(qs, "", condition).count() == 1
85
101
  assert (
86
- mvs.filterset_class(request=request).filter_by_condition(qs, "", condition).first() == condition.transition
102
+ mvs.filterset_class(request=super_user_get_request).filter_by_condition(qs, "", condition).first()
103
+ == condition.transition
87
104
  )
@@ -1,79 +1,82 @@
1
- from unittest.mock import patch
2
-
3
1
  import pytest
4
- from wbcore.contrib.directory.factories import PersonFactory
5
- from wbcore.contrib.workflow.models import Condition
2
+ from pytest_mock import MockerFixture
3
+ from wbcore.contrib.workflow.models import DecisionStep, Transition
6
4
 
7
5
 
8
- @pytest.mark.django_db
9
6
  class TestDecisionStep:
7
+ @pytest.fixture
8
+ def mocked_instances(self, mocker: MockerFixture):
9
+ return mocker.MagicMock(first_name="John")
10
+
11
+ @pytest.fixture
12
+ def mocked_decision_step(self, mocker: MockerFixture):
13
+ return mocker.MagicMock(spec=DecisionStep)
14
+
10
15
  def test_get_first_valid_transition(
11
- self, process_step_factory, decision_step_factory, transition_factory, condition_factory
16
+ self,
17
+ mocker: MockerFixture,
18
+ mocked_process_step,
19
+ mocked_instances,
20
+ mocked_decision_step,
12
21
  ):
13
- attached_instance = PersonFactory()
14
- step = decision_step_factory()
15
- process_step = process_step_factory(process__instance=attached_instance, step=step)
16
- valid_transition1 = transition_factory(from_step=step)
17
- valid_transition2 = transition_factory(from_step=step)
18
- invalid_transition = transition_factory(from_step=step)
19
- transition_factory()
20
- condition_factory(
21
- transition=invalid_transition,
22
- attribute_name="first_name",
23
- expected_value=attached_instance.first_name,
24
- operator=Condition.Operator.EQ,
25
- negate_operator=True,
26
- )
27
- assert step.get_first_valid_transition(process_step) in [valid_transition1, valid_transition2]
22
+ # Arrange
23
+ mocked_process_step.get_instance.return_value = mocked_instances
24
+ mocked_process_step.step = mocked_decision_step
25
+ valid_transition1 = mocker.MagicMock(spec=Transition)
26
+ valid_transition2 = mocker.MagicMock(spec=Transition)
27
+ invalid_transition = mocker.MagicMock(spec=Transition)
28
+ mocked_decision_step.get_outgoing_transitions.return_value = [
29
+ invalid_transition,
30
+ valid_transition1,
31
+ valid_transition2,
32
+ ]
33
+ invalid_transition.all_conditions_satisfied.return_value = False
34
+ valid_transition1.all_conditions_satisfied.return_value = True
35
+ valid_transition2.all_conditions_satisfied.return_value = True
36
+ # Act
37
+ result = DecisionStep.get_first_valid_transition(mocked_decision_step, mocked_process_step)
38
+ # Assert
39
+ assert result in [valid_transition1, valid_transition2]
40
+ invalid_transition.all_conditions_satisfied.assert_called_once_with(mocked_process_step)
41
+ valid_transition1.all_conditions_satisfied.assert_called_once_with(mocked_process_step)
42
+ valid_transition2.all_conditions_satisfied.assert_not_called()
28
43
 
29
44
  def test_get_first_valid_transition_no_transitions(
30
- self, process_step_factory, decision_step_factory, transition_factory, condition_factory
45
+ self, mocker, mocked_process_step, mocked_instances, mocked_decision_step
31
46
  ):
32
- attached_instance = PersonFactory()
33
- step = decision_step_factory()
34
- process_step = process_step_factory(process__instance=attached_instance, step=step)
35
- invalid_transition = transition_factory(from_step=step)
36
- transition_factory()
37
- condition_factory(
38
- transition=invalid_transition,
39
- attribute_name="first_name",
40
- expected_value=attached_instance.first_name,
41
- operator=Condition.Operator.EQ,
42
- negate_operator=True,
43
- )
44
- assert step.get_first_valid_transition(process_step) is None
47
+ # Arrange
48
+ mocked_process_step.get_instance.return_value = mocked_instances
49
+ mocked_process_step.step = mocked_decision_step
50
+ invalid_transition = mocker.MagicMock(spec=Transition)
51
+ mocked_decision_step.get_outgoing_transitions.return_value = [invalid_transition]
52
+ invalid_transition.all_conditions_satisfied.return_value = False
53
+ # Act
54
+ result = DecisionStep.get_first_valid_transition(mocked_decision_step, mocked_process_step)
55
+ # Assert
56
+ assert result is None
57
+ invalid_transition.all_conditions_satisfied.assert_called_once_with(mocked_process_step)
45
58
 
46
- @patch("wbcore.contrib.workflow.models.step.DecisionStep.get_first_valid_transition")
47
- @patch("wbcore.contrib.workflow.models.step.Step.start_next_step")
48
- def test_run(
49
- self,
50
- mock_next,
51
- mock_transition,
52
- process_step_factory,
53
- transition_factory,
54
- decision_step_factory,
55
- ):
56
- transition = transition_factory()
57
- mock_transition.return_value = transition
58
- step = decision_step_factory()
59
- process_step = process_step_factory(step=step)
60
- step.run(process_step)
61
- assert mock_next.call_args.args == (process_step, transition)
59
+ def test_run(self, mocker: MockerFixture, mocked_process_step, mocked_decision_step):
60
+ # Arrange
61
+ mocked_start_next_step = mocker.patch("wbcore.contrib.workflow.models.step.Step.start_next_step")
62
+ mocked_transition = mocker.MagicMock(spec=Transition)
63
+ mocked_decision_step.get_first_valid_transition.return_value = mocked_transition
64
+ # Act
65
+ DecisionStep.run(mocked_decision_step, mocked_process_step)
66
+ # Assert
67
+ mocked_decision_step.get_first_valid_transition.assert_called_once_with(mocked_process_step)
68
+ mocked_start_next_step.assert_called_once_with(mocked_process_step, mocked_transition)
62
69
 
63
- @patch("wbcore.contrib.workflow.models.step.Step.set_failed")
64
- @patch("wbcore.contrib.workflow.models.step.activate_step.delay")
65
- @patch("wbcore.contrib.workflow.models.step.DecisionStep.get_first_valid_transition")
66
- def test_run_failed(
67
- self,
68
- mock_transition,
69
- mock_activate,
70
- mock_failed,
71
- process_step_factory,
72
- decision_step_factory,
73
- ):
74
- mock_transition.return_value = None
75
- step = decision_step_factory()
76
- process_step = process_step_factory(step=step)
77
- step.run(process_step)
78
- assert mock_failed.call_args.args[0] == process_step
79
- assert not mock_activate.called
70
+ def test_run_failed(self, mocker: MockerFixture, mocked_process_step, mocked_decision_step):
71
+ # Arrange
72
+ mocked_activate_step = mocker.patch("wbcore.contrib.workflow.models.step.activate_step.delay")
73
+ mocked_decision_step.get_first_valid_transition.return_value = None
74
+ mocked_set_failed = mocker.patch.object(mocked_decision_step, "set_failed")
75
+ # Act
76
+ DecisionStep.run(mocked_decision_step, mocked_process_step)
77
+ # Assert
78
+ mocked_decision_step.get_first_valid_transition.assert_called_once_with(mocked_process_step)
79
+ mocked_set_failed.assert_called_once_with(
80
+ mocked_process_step, "No valid outgoing transition found for this step!"
81
+ )
82
+ mocked_activate_step.assert_not_called()